phone_console.c 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151
  1. /*
  2. * (C) Copyright 2004 Intracom S.A.
  3. * Pantelis Antoniou <panto@intracom.gr>
  4. *
  5. * See file CREDITS for list of people who contributed to this
  6. * project.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License as
  10. * published by the Free Software Foundation; either version 2 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  21. * MA 02111-1307 USA
  22. */
  23. /*
  24. * phone_console.c
  25. *
  26. * A phone based console
  27. *
  28. * Virtual display of 80x24 characters.
  29. * The actual display is much smaller and panned to show the virtual one.
  30. * Input is made by a numeric keypad utilizing the input method of
  31. * mobile phones. Sorry no T9 lexicons...
  32. *
  33. */
  34. #include <common.h>
  35. #include <version.h>
  36. #include <linux/types.h>
  37. #include <devices.h>
  38. #include <sed156x.h>
  39. /*************************************************************************************************/
  40. #define ROWS 24
  41. #define COLS 80
  42. #define REFRESH_HZ (CFG_HZ/50) /* refresh every 20ms */
  43. #define BLINK_HZ (CFG_HZ/2) /* cursor blink every 500ms */
  44. /*************************************************************************************************/
  45. #define DISPLAY_BACKLIT_PORT ((volatile immap_t *)CFG_IMMR)->im_ioport.iop_pcdat
  46. #define DISPLAY_BACKLIT_MASK 0x0010
  47. /*************************************************************************************************/
  48. #define KP_STABLE_HZ (CFG_HZ/100) /* stable for 10ms */
  49. #define KP_REPEAT_DELAY_HZ (CFG_HZ/4) /* delay before repeat 250ms */
  50. #define KP_REPEAT_HZ (CFG_HZ/20) /* repeat every 50ms */
  51. #define KP_FORCE_DELAY_HZ (CFG_HZ/2) /* key was force pressed */
  52. #define KP_IDLE_DELAY_HZ (CFG_HZ/2) /* key was released and idle */
  53. #if CONFIG_NETPHONE_VERSION == 1
  54. #define KP_SPI_RXD_PORT (((volatile immap_t *)CFG_IMMR)->im_ioport.iop_pcdat)
  55. #define KP_SPI_RXD_MASK 0x0008
  56. #define KP_SPI_TXD_PORT (((volatile immap_t *)CFG_IMMR)->im_ioport.iop_pcdat)
  57. #define KP_SPI_TXD_MASK 0x0004
  58. #define KP_SPI_CLK_PORT (((volatile immap_t *)CFG_IMMR)->im_ioport.iop_pcdat)
  59. #define KP_SPI_CLK_MASK 0x0001
  60. #elif CONFIG_NETPHONE_VERSION == 2
  61. #define KP_SPI_RXD_PORT (((volatile immap_t *)CFG_IMMR)->im_cpm.cp_pbdat)
  62. #define KP_SPI_RXD_MASK 0x00000008
  63. #define KP_SPI_TXD_PORT (((volatile immap_t *)CFG_IMMR)->im_cpm.cp_pbdat)
  64. #define KP_SPI_TXD_MASK 0x00000004
  65. #define KP_SPI_CLK_PORT (((volatile immap_t *)CFG_IMMR)->im_cpm.cp_pbdat)
  66. #define KP_SPI_CLK_MASK 0x00000002
  67. #endif
  68. #define KP_CS_PORT (((volatile immap_t *)CFG_IMMR)->im_cpm.cp_pedat)
  69. #define KP_CS_MASK 0x00000010
  70. #define KP_SPI_RXD() (KP_SPI_RXD_PORT & KP_SPI_RXD_MASK)
  71. #define KP_SPI_TXD(x) \
  72. do { \
  73. if (x) \
  74. KP_SPI_TXD_PORT |= KP_SPI_TXD_MASK; \
  75. else \
  76. KP_SPI_TXD_PORT &= ~KP_SPI_TXD_MASK; \
  77. } while(0)
  78. #define KP_SPI_CLK(x) \
  79. do { \
  80. if (x) \
  81. KP_SPI_CLK_PORT |= KP_SPI_CLK_MASK; \
  82. else \
  83. KP_SPI_CLK_PORT &= ~KP_SPI_CLK_MASK; \
  84. } while(0)
  85. #define KP_SPI_CLK_TOGGLE() (KP_SPI_CLK_PORT ^= KP_SPI_CLK_MASK)
  86. #define KP_SPI_BIT_DELAY() /* no delay */
  87. #define KP_CS(x) \
  88. do { \
  89. if (x) \
  90. KP_CS_PORT |= KP_CS_MASK; \
  91. else \
  92. KP_CS_PORT &= ~KP_CS_MASK; \
  93. } while(0)
  94. #define KP_ROWS 7
  95. #define KP_COLS 4
  96. #define KP_ROWS_MASK ((1 << KP_ROWS) - 1)
  97. #define KP_COLS_MASK ((1 << KP_COLS) - 1)
  98. #define SCAN 0
  99. #define SCAN_FILTER 1
  100. #define SCAN_COL 2
  101. #define SCAN_COL_FILTER 3
  102. #define PRESSED 4
  103. #define KP_F1 0 /* leftmost dot (tab) */
  104. #define KP_F2 1 /* middle left dot */
  105. #define KP_F3 2 /* up */
  106. #define KP_F4 3 /* middle right dot */
  107. #define KP_F5 4 /* rightmost dot */
  108. #define KP_F6 5 /* C */
  109. #define KP_F7 6 /* left */
  110. #define KP_F8 7 /* down */
  111. #define KP_F9 8 /* right */
  112. #define KP_F10 9 /* enter */
  113. #define KP_F11 10 /* R */
  114. #define KP_F12 11 /* save */
  115. #define KP_F13 12 /* redial */
  116. #define KP_F14 13 /* speaker */
  117. #define KP_F15 14 /* unused */
  118. #define KP_F16 15 /* unused */
  119. #define KP_RELEASE -1 /* key depressed */
  120. #define KP_FORCE -2 /* key was pressed for more than force hz */
  121. #define KP_IDLE -3 /* key was released and idle */
  122. #define KP_1 '1'
  123. #define KP_2 '2'
  124. #define KP_3 '3'
  125. #define KP_4 '4'
  126. #define KP_5 '5'
  127. #define KP_6 '6'
  128. #define KP_7 '7'
  129. #define KP_8 '8'
  130. #define KP_9 '9'
  131. #define KP_0 '0'
  132. #define KP_STAR '*'
  133. #define KP_HASH '#'
  134. /*************************************************************************************************/
  135. static int curs_disabled;
  136. static int curs_col, curs_row;
  137. static int disp_col, disp_row;
  138. static int width, height;
  139. /* the simulated vty buffer */
  140. static char vty_buf[ROWS * COLS];
  141. static char last_visible_buf[ROWS * COLS]; /* worst case */
  142. static char *last_visible_curs_ptr;
  143. static int last_visible_curs_rev;
  144. static int blinked_state;
  145. static int last_input_mode;
  146. static int refresh_time;
  147. static int blink_time;
  148. static char last_fast_punct;
  149. /*************************************************************************************************/
  150. #define IM_SMALL 0
  151. #define IM_CAPITAL 1
  152. #define IM_NUMBER 2
  153. static int input_mode;
  154. static char fast_punct;
  155. static int tab_indicator;
  156. static const char *fast_punct_list = ",.:;*";
  157. static const char *input_mode_txt[] = { "abc", "ABC", "123" };
  158. static const char *punct = ".,!;?'\"-()@/:_+&%*=<>$[]{}\\~^#|";
  159. static const char *whspace = " 0\n";
  160. /* per mode character select (for 2-9) */
  161. static const char *digits_sel[2][8] = {
  162. { /* small */
  163. "abc2", /* 2 */
  164. "def3", /* 3 */
  165. "ghi4", /* 4 */
  166. "jkl5", /* 5 */
  167. "mno6", /* 6 */
  168. "pqrs7", /* 7 */
  169. "tuv8", /* 8 */
  170. "wxyz9", /* 9 */
  171. }, { /* capital */
  172. "ABC2", /* 2 */
  173. "DEF3", /* 3 */
  174. "GHI4", /* 4 */
  175. "JKL5", /* 5 */
  176. "MNO6", /* 6 */
  177. "PQRS7", /* 7 */
  178. "TUV8", /* 8 */
  179. "WXYZ9", /* 9 */
  180. }
  181. };
  182. /*****************************************************************************/
  183. static void update(void);
  184. static void ensure_visible(int col, int row, int dx, int dy);
  185. static void console_init(void)
  186. {
  187. curs_disabled = 0;
  188. curs_col = 0;
  189. curs_row = 0;
  190. disp_col = 0;
  191. disp_row = 0;
  192. input_mode = IM_SMALL;
  193. fast_punct = ',';
  194. last_fast_punct = '\0';
  195. refresh_time = REFRESH_HZ;
  196. blink_time = BLINK_HZ;
  197. memset(vty_buf, ' ', sizeof(vty_buf));
  198. memset(last_visible_buf, ' ', sizeof(last_visible_buf));
  199. last_visible_curs_ptr = NULL;
  200. last_input_mode = -1;
  201. last_visible_curs_rev = 0;
  202. blinked_state = 0;
  203. sed156x_init();
  204. width = sed156x_text_width;
  205. height = sed156x_text_height - 1;
  206. tab_indicator = 0;
  207. }
  208. /*****************************************************************************/
  209. void phone_putc(const char c);
  210. /*****************************************************************************/
  211. static int queued_char = -1;
  212. static int enabled = 0;
  213. /*****************************************************************************/
  214. /* flush buffers */
  215. int phone_start(void)
  216. {
  217. console_init();
  218. update();
  219. sed156x_sync();
  220. enabled = 1;
  221. queued_char = 'U' - '@';
  222. /* backlit on */
  223. DISPLAY_BACKLIT_PORT &= ~DISPLAY_BACKLIT_MASK;
  224. return 0;
  225. }
  226. int phone_stop(void)
  227. {
  228. enabled = 0;
  229. sed156x_clear();
  230. sed156x_sync();
  231. /* backlit off */
  232. DISPLAY_BACKLIT_PORT |= DISPLAY_BACKLIT_MASK;
  233. return 0;
  234. }
  235. void phone_puts(const char *s)
  236. {
  237. int count = strlen(s);
  238. while (count--)
  239. phone_putc(*s++);
  240. }
  241. int phone_tstc(void)
  242. {
  243. return queued_char >= 0 ? 1 : 0;
  244. }
  245. int phone_getc(void)
  246. {
  247. int r;
  248. if (queued_char < 0)
  249. return -1;
  250. r = queued_char;
  251. queued_char = -1;
  252. return r;
  253. }
  254. /*****************************************************************************/
  255. int drv_phone_init(void)
  256. {
  257. device_t console_dev;
  258. char *penv;
  259. /*
  260. * Force console i/o to serial ?
  261. */
  262. if ((penv = getenv("console")) != NULL && strcmp(penv, "serial") == 0)
  263. return 0;
  264. console_init();
  265. memset(&console_dev, 0, sizeof(console_dev));
  266. strcpy(console_dev.name, "phone");
  267. console_dev.ext = DEV_EXT_VIDEO; /* Video extensions */
  268. console_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
  269. console_dev.start = phone_start;
  270. console_dev.stop = phone_stop;
  271. console_dev.putc = phone_putc; /* 'putc' function */
  272. console_dev.puts = phone_puts; /* 'puts' function */
  273. console_dev.tstc = phone_tstc; /* 'tstc' function */
  274. console_dev.getc = phone_getc; /* 'getc' function */
  275. if (device_register(&console_dev) == 0)
  276. return 1;
  277. return 0;
  278. }
  279. static int use_me;
  280. int drv_phone_use_me(void)
  281. {
  282. return use_me;
  283. }
  284. static void kp_do_poll(void);
  285. void phone_console_do_poll(void)
  286. {
  287. int i, x, y;
  288. kp_do_poll();
  289. if (enabled) {
  290. /* do the blink */
  291. blink_time -= PHONE_CONSOLE_POLL_HZ;
  292. if (blink_time <= 0) {
  293. blink_time += BLINK_HZ;
  294. if (last_visible_curs_ptr) {
  295. i = last_visible_curs_ptr - last_visible_buf;
  296. x = i % width; y = i / width;
  297. sed156x_reverse_at(x, y, 1);
  298. last_visible_curs_rev ^= 1;
  299. }
  300. }
  301. /* do the refresh */
  302. refresh_time -= PHONE_CONSOLE_POLL_HZ;
  303. if (refresh_time <= 0) {
  304. refresh_time += REFRESH_HZ;
  305. sed156x_sync();
  306. }
  307. }
  308. }
  309. static int last_scancode = -1;
  310. static int forced_scancode = 0;
  311. static int input_state = -1;
  312. static int input_scancode = -1;
  313. static int input_selected_char = -1;
  314. static char input_covered_char;
  315. static void putchar_at_cursor(char c)
  316. {
  317. vty_buf[curs_row * COLS + curs_col] = c;
  318. ensure_visible(curs_col, curs_row, 1, 1);
  319. }
  320. static char getchar_at_cursor(void)
  321. {
  322. return vty_buf[curs_row * COLS + curs_col];
  323. }
  324. static void queue_input_char(char c)
  325. {
  326. if (c <= 0)
  327. return;
  328. queued_char = c;
  329. }
  330. static void terminate_input(void)
  331. {
  332. if (input_state < 0)
  333. return;
  334. if (input_selected_char >= 0)
  335. queue_input_char(input_selected_char);
  336. input_state = -1;
  337. input_selected_char = -1;
  338. putchar_at_cursor(input_covered_char);
  339. curs_disabled = 0;
  340. blink_time = BLINK_HZ;
  341. update();
  342. }
  343. static void handle_enabled_scancode(int scancode)
  344. {
  345. char c;
  346. int new_disp_col, new_disp_row;
  347. const char *sel;
  348. switch (scancode) {
  349. /* key was released */
  350. case KP_RELEASE:
  351. forced_scancode = 0;
  352. break;
  353. /* key was forced */
  354. case KP_FORCE:
  355. switch (last_scancode) {
  356. case '#':
  357. if (input_mode == IM_NUMBER) {
  358. input_mode = IM_CAPITAL;
  359. /* queue backspace to erase # */
  360. queue_input_char('\b');
  361. } else {
  362. input_mode = IM_NUMBER;
  363. fast_punct = '*';
  364. }
  365. update();
  366. break;
  367. case '0': case '1':
  368. case '2': case '3': case '4': case '5':
  369. case '6': case '7': case '8': case '9':
  370. if (input_state < 0)
  371. break;
  372. input_selected_char = last_scancode;
  373. putchar_at_cursor((char)input_selected_char);
  374. terminate_input();
  375. break;
  376. default:
  377. break;
  378. }
  379. break;
  380. /* release and idle */
  381. case KP_IDLE:
  382. input_scancode = -1;
  383. if (input_state < 0)
  384. break;
  385. terminate_input();
  386. break;
  387. /* change input mode */
  388. case '#':
  389. if (last_scancode == '#') /* no repeat */
  390. break;
  391. if (input_mode == IM_NUMBER) {
  392. input_scancode = scancode;
  393. input_state = 0;
  394. input_selected_char = scancode;
  395. input_covered_char = getchar_at_cursor();
  396. putchar_at_cursor((char)input_selected_char);
  397. terminate_input();
  398. break;
  399. }
  400. if (input_mode == IM_SMALL)
  401. input_mode = IM_CAPITAL;
  402. else
  403. input_mode = IM_SMALL;
  404. update();
  405. break;
  406. case '*':
  407. /* no repeat */
  408. if (last_scancode == scancode)
  409. break;
  410. if (input_state >= 0)
  411. terminate_input();
  412. input_scancode = fast_punct;
  413. input_state = 0;
  414. input_selected_char = input_scancode;
  415. input_covered_char = getchar_at_cursor();
  416. putchar_at_cursor((char)input_selected_char);
  417. terminate_input();
  418. break;
  419. case '0': case '1':
  420. case '2': case '3': case '4': case '5':
  421. case '6': case '7': case '8': case '9':
  422. /* no repeat */
  423. if (last_scancode == scancode)
  424. break;
  425. if (input_mode == IM_NUMBER) {
  426. input_scancode = scancode;
  427. input_state = 0;
  428. input_selected_char = scancode;
  429. input_covered_char = getchar_at_cursor();
  430. putchar_at_cursor((char)input_selected_char);
  431. terminate_input();
  432. break;
  433. }
  434. if (input_state >= 0 && input_scancode != scancode)
  435. terminate_input();
  436. if (input_state < 0) {
  437. curs_disabled = 1;
  438. input_scancode = scancode;
  439. input_state = 0;
  440. input_covered_char = getchar_at_cursor();
  441. } else
  442. input_state++;
  443. if (scancode == '0')
  444. sel = whspace;
  445. else if (scancode == '1')
  446. sel = punct;
  447. else
  448. sel = digits_sel[input_mode][scancode - '2'];
  449. c = *(sel + input_state);
  450. if (c == '\0') {
  451. input_state = 0;
  452. c = *sel;
  453. }
  454. input_selected_char = (int)c;
  455. putchar_at_cursor((char)input_selected_char);
  456. update();
  457. break;
  458. /* move visible display */
  459. case KP_F3: case KP_F8: case KP_F7: case KP_F9:
  460. new_disp_col = disp_col;
  461. new_disp_row = disp_row;
  462. switch (scancode) {
  463. /* up */
  464. case KP_F3:
  465. if (new_disp_row <= 0)
  466. break;
  467. new_disp_row--;
  468. break;
  469. /* down */
  470. case KP_F8:
  471. if (new_disp_row >= ROWS - height)
  472. break;
  473. new_disp_row++;
  474. break;
  475. /* left */
  476. case KP_F7:
  477. if (new_disp_col <= 0)
  478. break;
  479. new_disp_col--;
  480. break;
  481. /* right */
  482. case KP_F9:
  483. if (new_disp_col >= COLS - width)
  484. break;
  485. new_disp_col++;
  486. break;
  487. }
  488. /* no change? */
  489. if (disp_col == new_disp_col && disp_row == new_disp_row)
  490. break;
  491. disp_col = new_disp_col;
  492. disp_row = new_disp_row;
  493. update();
  494. break;
  495. case KP_F6: /* backspace */
  496. /* inputing something; no backspace sent, just cancel input */
  497. if (input_state >= 0) {
  498. input_selected_char = -1; /* cancel */
  499. terminate_input();
  500. break;
  501. }
  502. queue_input_char('\b');
  503. break;
  504. case KP_F10: /* enter */
  505. /* inputing something; first cancel input */
  506. if (input_state >= 0)
  507. terminate_input();
  508. queue_input_char('\r');
  509. break;
  510. case KP_F11: /* R -> Ctrl-C (abort) */
  511. if (input_state >= 0)
  512. terminate_input();
  513. queue_input_char('C' - 'Q'); /* ctrl-c */
  514. break;
  515. case KP_F5: /* F% -> Ctrl-U (clear line) */
  516. if (input_state >= 0)
  517. terminate_input();
  518. queue_input_char('U' - 'Q'); /* ctrl-c */
  519. break;
  520. case KP_F1: /* tab */
  521. /* inputing something; first cancel input */
  522. if (input_state >= 0)
  523. terminate_input();
  524. queue_input_char('\t');
  525. break;
  526. case KP_F2: /* change fast punct */
  527. sel = strchr(fast_punct_list, fast_punct);
  528. if (sel == NULL)
  529. sel = &fast_punct_list[0];
  530. sel++;
  531. if (*sel == '\0')
  532. sel = &fast_punct_list[0];
  533. fast_punct = *sel;
  534. update();
  535. break;
  536. }
  537. if (scancode != KP_FORCE && scancode != KP_IDLE) /* don't record forced or idle scancode */
  538. last_scancode = scancode;
  539. }
  540. static void scancode_action(int scancode)
  541. {
  542. #if 0
  543. if (scancode == KP_RELEASE)
  544. printf(" RELEASE\n");
  545. else if (scancode == KP_FORCE)
  546. printf(" FORCE\n");
  547. else if (scancode == KP_IDLE)
  548. printf(" IDLE\n");
  549. else if (scancode < 32)
  550. printf(" F%d", scancode + 1);
  551. else
  552. printf(" %c", (char)scancode);
  553. printf("\n");
  554. #endif
  555. if (enabled) {
  556. handle_enabled_scancode(scancode);
  557. return;
  558. }
  559. if (scancode == KP_FORCE && last_scancode == '*')
  560. use_me = 1;
  561. last_scancode = scancode;
  562. }
  563. /**************************************************************************************/
  564. /* update the display; make sure to update only the differences */
  565. static void update(void)
  566. {
  567. int i;
  568. char *s, *e, *t, *r, *b, *cp;
  569. if (input_mode != last_input_mode)
  570. sed156x_output_at(sed156x_text_width - 3, sed156x_text_height - 1, input_mode_txt[input_mode], 3);
  571. if (tab_indicator == 0) {
  572. sed156x_output_at(0, sed156x_text_height - 1, "\\t", 2);
  573. tab_indicator = 1;
  574. }
  575. if (fast_punct != last_fast_punct)
  576. sed156x_output_at(4, sed156x_text_height - 1, &fast_punct, 1);
  577. if (curs_disabled ||
  578. curs_col < disp_col || curs_col >= (disp_col + width) ||
  579. curs_row < disp_row || curs_row >= (disp_row + height)) {
  580. cp = NULL;
  581. } else
  582. cp = last_visible_buf + (curs_row - disp_row) * width + (curs_col - disp_col);
  583. /* printf("(%d,%d) (%d,%d) %s\n", curs_col, curs_row, disp_col, disp_row, cp ? "YES" : "no"); */
  584. /* clear previous cursor */
  585. if (last_visible_curs_ptr && last_visible_curs_rev == 0) {
  586. i = last_visible_curs_ptr - last_visible_buf;
  587. sed156x_reverse_at(i % width, i / width, 1);
  588. }
  589. b = vty_buf + disp_row * COLS + disp_col;
  590. t = last_visible_buf;
  591. for (i = 0; i < height; i++) {
  592. s = b;
  593. e = b + width;
  594. /* update only the differences */
  595. do {
  596. while (s < e && *s == *t) {
  597. s++;
  598. t++;
  599. }
  600. if (s == e) /* no more */
  601. break;
  602. /* find run */
  603. r = s;
  604. while (s < e && *s != *t)
  605. *t++ = *s++;
  606. /* and update */
  607. sed156x_output_at(r - b, i, r, s - r);
  608. } while (s < e);
  609. b += COLS;
  610. }
  611. /* set cursor */
  612. if (cp) {
  613. last_visible_curs_ptr = cp;
  614. i = last_visible_curs_ptr - last_visible_buf;
  615. sed156x_reverse_at(i % width, i / width, 1);
  616. last_visible_curs_rev = 0;
  617. } else {
  618. last_visible_curs_ptr = NULL;
  619. }
  620. last_input_mode = input_mode;
  621. last_fast_punct = fast_punct;
  622. }
  623. /* ensure visibility; the trick is to minimize the screen movement */
  624. static void ensure_visible(int col, int row, int dx, int dy)
  625. {
  626. int x1, y1, x2, y2, a1, b1, a2, b2;
  627. /* clamp visible region */
  628. if (col < 0) {
  629. dx -= col;
  630. col = 0;
  631. if (dx <= 0)
  632. dx = 1;
  633. }
  634. if (row < 0) {
  635. dy -= row;
  636. row = 0;
  637. if (dy <= 0)
  638. dy = 1;
  639. }
  640. if (col + dx > COLS)
  641. dx = COLS - col;
  642. if (row + dy > ROWS)
  643. dy = ROWS - row;
  644. /* move to easier to use vars */
  645. x1 = disp_col; y1 = disp_row;
  646. x2 = x1 + width; y2 = y1 + height;
  647. a1 = col; b1 = row;
  648. a2 = a1 + dx; b2 = b1 + dy;
  649. /* printf("(%d,%d) - (%d,%d) : (%d, %d) - (%d, %d)\n", x1, y1, x2, y2, a1, b1, a2, b2); */
  650. if (a2 > x2) {
  651. /* move to the right */
  652. x2 = a2;
  653. x1 = x2 - width;
  654. if (x1 < 0) {
  655. x1 = 0;
  656. x2 = width;
  657. }
  658. } else if (a1 < x1) {
  659. /* move to the left */
  660. x1 = a1;
  661. x2 = x1 + width;
  662. if (x2 > COLS) {
  663. x2 = COLS;
  664. x1 = x2 - width;
  665. }
  666. }
  667. if (b2 > y2) {
  668. /* move down */
  669. y2 = b2;
  670. y1 = y2 - height;
  671. if (y1 < 0) {
  672. y1 = 0;
  673. y2 = height;
  674. }
  675. } else if (b1 < y1) {
  676. /* move up */
  677. y1 = b1;
  678. y2 = y1 + width;
  679. if (y2 > ROWS) {
  680. y2 = ROWS;
  681. y1 = y2 - height;
  682. }
  683. }
  684. /* printf("(%d,%d) - (%d,%d) : (%d, %d) - (%d, %d)\n", x1, y1, x2, y2, a1, b1, a2, b2); */
  685. /* no movement? */
  686. if (disp_col == x1 && disp_row == y1)
  687. return;
  688. disp_col = x1;
  689. disp_row = y1;
  690. }
  691. /**************************************************************************************/
  692. static void newline(void)
  693. {
  694. curs_col = 0;
  695. if (curs_row + 1 < ROWS)
  696. curs_row++;
  697. else {
  698. memmove(vty_buf, vty_buf + COLS, COLS * (ROWS - 1));
  699. memset(vty_buf + (ROWS - 1) * COLS, ' ', COLS);
  700. }
  701. }
  702. void phone_putc(const char c)
  703. {
  704. int i;
  705. if (input_mode != -1) {
  706. input_selected_char = -1;
  707. terminate_input();
  708. }
  709. curs_disabled = 1;
  710. update();
  711. blink_time = BLINK_HZ;
  712. switch (c) {
  713. case '\a': /* ignore bell */
  714. case '\r': /* ignore carriage return */
  715. break;
  716. case '\n': /* next line */
  717. newline();
  718. ensure_visible(curs_col, curs_row, 1, 1);
  719. break;
  720. case 9: /* tab 8 */
  721. /* move to tab */
  722. i = curs_col;
  723. i |= 0x0008;
  724. i &= ~0x0007;
  725. if (i < COLS)
  726. curs_col = i;
  727. else
  728. newline();
  729. ensure_visible(curs_col, curs_row, 1, 1);
  730. break;
  731. case 8: /* backspace */
  732. if (curs_col <= 0)
  733. break;
  734. curs_col--;
  735. /* make sure that we see a couple of characters before */
  736. if (curs_col > 4)
  737. ensure_visible(curs_col - 4, curs_row, 4, 1);
  738. else
  739. ensure_visible(curs_col, curs_row, 1, 1);
  740. break;
  741. default: /* draw the char */
  742. putchar_at_cursor(c);
  743. /*
  744. * check for newline
  745. */
  746. if (curs_col + 1 < COLS)
  747. curs_col++;
  748. else
  749. newline();
  750. ensure_visible(curs_col, curs_row, 1, 1);
  751. break;
  752. }
  753. curs_disabled = 0;
  754. blink_time = BLINK_HZ;
  755. update();
  756. }
  757. /**************************************************************************************/
  758. static inline unsigned int kp_transfer(unsigned int val)
  759. {
  760. unsigned int rx;
  761. int b;
  762. rx = 0; b = 8;
  763. while (--b >= 0) {
  764. KP_SPI_TXD(val & 0x80);
  765. val <<= 1;
  766. KP_SPI_CLK_TOGGLE();
  767. KP_SPI_BIT_DELAY();
  768. rx <<= 1;
  769. if (KP_SPI_RXD())
  770. rx |= 1;
  771. KP_SPI_CLK_TOGGLE();
  772. KP_SPI_BIT_DELAY();
  773. }
  774. return rx;
  775. }
  776. unsigned int kp_data_transfer(unsigned int val)
  777. {
  778. KP_SPI_CLK(1);
  779. KP_CS(0);
  780. val = kp_transfer(val);
  781. KP_CS(1);
  782. return val;
  783. }
  784. unsigned int kp_get_col_mask(unsigned int row_mask)
  785. {
  786. unsigned int val, col_mask;
  787. val = 0x80 | (row_mask & 0x7F);
  788. (void)kp_data_transfer(val);
  789. #if CONFIG_NETPHONE_VERSION == 1
  790. col_mask = kp_data_transfer(val) & 0x0F;
  791. #elif CONFIG_NETPHONE_VERSION == 2
  792. col_mask = ((volatile immap_t *)CFG_IMMR)->im_cpm.cp_pedat & 0x0f;
  793. /* XXX FUCK FUCK FUCK FUCK FUCK!!!! */
  794. col_mask = ((col_mask & 0x08) >> 3) | /* BKBR1 */
  795. ((col_mask & 0x04) << 1) | /* BKBR2 */
  796. (col_mask & 0x02) | /* BKBR3 */
  797. ((col_mask & 0x01) << 2); /* BKBR4 */
  798. #endif
  799. /* printf("col_mask(row_mask = 0x%x) -> col_mask = 0x%x\n", row_mask, col_mask); */
  800. return col_mask;
  801. }
  802. /**************************************************************************************/
  803. static const int kp_scancodes[KP_ROWS * KP_COLS] = {
  804. KP_F1, KP_F3, KP_F4, KP_F2,
  805. KP_F6, KP_F8, KP_F9, KP_F7,
  806. KP_1, KP_3, KP_F11, KP_2,
  807. KP_4, KP_6, KP_F12, KP_5,
  808. KP_7, KP_9, KP_F13, KP_8,
  809. KP_STAR, KP_HASH, KP_F14, KP_0,
  810. KP_F5, KP_F15, KP_F16, KP_F10,
  811. };
  812. static const int kp_repeats[KP_ROWS * KP_COLS] = {
  813. 0, 1, 0, 0,
  814. 0, 1, 1, 1,
  815. 1, 1, 0, 1,
  816. 1, 1, 0, 1,
  817. 1, 1, 0, 1,
  818. 1, 1, 0, 1,
  819. 0, 0, 0, 1,
  820. };
  821. static int kp_state = SCAN;
  822. static int kp_last_col_mask;
  823. static int kp_cur_row, kp_cur_col;
  824. static int kp_scancode;
  825. static int kp_stable;
  826. static int kp_repeat;
  827. static int kp_repeat_time;
  828. static int kp_force_time;
  829. static int kp_idle_time;
  830. static void kp_do_poll(void)
  831. {
  832. unsigned int col_mask;
  833. int col;
  834. switch (kp_state) {
  835. case SCAN:
  836. if (kp_idle_time > 0) {
  837. kp_idle_time -= PHONE_CONSOLE_POLL_HZ;
  838. if (kp_idle_time <= 0)
  839. scancode_action(KP_IDLE);
  840. }
  841. col_mask = kp_get_col_mask(KP_ROWS_MASK);
  842. if (col_mask == KP_COLS_MASK)
  843. break; /* nothing */
  844. kp_last_col_mask = col_mask;
  845. kp_stable = 0;
  846. kp_state = SCAN_FILTER;
  847. break;
  848. case SCAN_FILTER:
  849. col_mask = kp_get_col_mask(KP_ROWS_MASK);
  850. if (col_mask != kp_last_col_mask) {
  851. kp_state = SCAN;
  852. break;
  853. }
  854. kp_stable += PHONE_CONSOLE_POLL_HZ;
  855. if (kp_stable < KP_STABLE_HZ)
  856. break;
  857. kp_cur_row = 0;
  858. kp_stable = 0;
  859. kp_state = SCAN_COL;
  860. (void)kp_get_col_mask(1 << kp_cur_row);
  861. break;
  862. case SCAN_COL:
  863. col_mask = kp_get_col_mask(1 << kp_cur_row);
  864. if (col_mask == KP_COLS_MASK) {
  865. if (++kp_cur_row >= KP_ROWS) {
  866. kp_state = SCAN;
  867. break;
  868. }
  869. kp_get_col_mask(1 << kp_cur_row);
  870. break;
  871. }
  872. kp_last_col_mask = col_mask;
  873. kp_stable = 0;
  874. kp_state = SCAN_COL_FILTER;
  875. break;
  876. case SCAN_COL_FILTER:
  877. col_mask = kp_get_col_mask(1 << kp_cur_row);
  878. if (col_mask != kp_last_col_mask || col_mask == KP_COLS_MASK) {
  879. kp_state = SCAN;
  880. break;
  881. }
  882. kp_stable += PHONE_CONSOLE_POLL_HZ;
  883. if (kp_stable < KP_STABLE_HZ)
  884. break;
  885. for (col = 0; col < KP_COLS; col++)
  886. if ((col_mask & (1 << col)) == 0)
  887. break;
  888. kp_cur_col = col;
  889. kp_state = PRESSED;
  890. kp_scancode = kp_scancodes[kp_cur_row * KP_COLS + kp_cur_col];
  891. kp_repeat = kp_repeats[kp_cur_row * KP_COLS + kp_cur_col];
  892. if (kp_repeat)
  893. kp_repeat_time = KP_REPEAT_DELAY_HZ;
  894. kp_force_time = KP_FORCE_DELAY_HZ;
  895. scancode_action(kp_scancode);
  896. break;
  897. case PRESSED:
  898. col_mask = kp_get_col_mask(1 << kp_cur_row);
  899. if (col_mask != kp_last_col_mask) {
  900. kp_state = SCAN;
  901. scancode_action(KP_RELEASE);
  902. kp_idle_time = KP_IDLE_DELAY_HZ;
  903. break;
  904. }
  905. if (kp_repeat) {
  906. kp_repeat_time -= PHONE_CONSOLE_POLL_HZ;
  907. if (kp_repeat_time <= 0) {
  908. kp_repeat_time += KP_REPEAT_HZ;
  909. scancode_action(kp_scancode);
  910. }
  911. }
  912. if (kp_force_time > 0) {
  913. kp_force_time -= PHONE_CONSOLE_POLL_HZ;
  914. if (kp_force_time <= 0)
  915. scancode_action(KP_FORCE);
  916. }
  917. break;
  918. }
  919. }
  920. /**************************************************************************************/
  921. int drv_phone_is_idle(void)
  922. {
  923. return kp_state == SCAN;
  924. }