phone_console.c 23 KB

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