charlcd.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Character LCD driver for Linux
  4. *
  5. * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu>
  6. * Copyright (C) 2016-2017 Glider bvba
  7. */
  8. #include <linux/atomic.h>
  9. #include <linux/ctype.h>
  10. #include <linux/delay.h>
  11. #include <linux/fs.h>
  12. #include <linux/miscdevice.h>
  13. #include <linux/module.h>
  14. #include <linux/notifier.h>
  15. #include <linux/reboot.h>
  16. #include <linux/slab.h>
  17. #include <linux/uaccess.h>
  18. #include <linux/workqueue.h>
  19. #include <generated/utsrelease.h>
  20. #include <misc/charlcd.h>
  21. #define LCD_MINOR 156
  22. #define DEFAULT_LCD_BWIDTH 40
  23. #define DEFAULT_LCD_HWIDTH 64
  24. /* Keep the backlight on this many seconds for each flash */
  25. #define LCD_BL_TEMPO_PERIOD 4
  26. #define LCD_FLAG_B 0x0004 /* Blink on */
  27. #define LCD_FLAG_C 0x0008 /* Cursor on */
  28. #define LCD_FLAG_D 0x0010 /* Display on */
  29. #define LCD_FLAG_F 0x0020 /* Large font mode */
  30. #define LCD_FLAG_N 0x0040 /* 2-rows mode */
  31. #define LCD_FLAG_L 0x0080 /* Backlight enabled */
  32. /* LCD commands */
  33. #define LCD_CMD_DISPLAY_CLEAR 0x01 /* Clear entire display */
  34. #define LCD_CMD_ENTRY_MODE 0x04 /* Set entry mode */
  35. #define LCD_CMD_CURSOR_INC 0x02 /* Increment cursor */
  36. #define LCD_CMD_DISPLAY_CTRL 0x08 /* Display control */
  37. #define LCD_CMD_DISPLAY_ON 0x04 /* Set display on */
  38. #define LCD_CMD_CURSOR_ON 0x02 /* Set cursor on */
  39. #define LCD_CMD_BLINK_ON 0x01 /* Set blink on */
  40. #define LCD_CMD_SHIFT 0x10 /* Shift cursor/display */
  41. #define LCD_CMD_DISPLAY_SHIFT 0x08 /* Shift display instead of cursor */
  42. #define LCD_CMD_SHIFT_RIGHT 0x04 /* Shift display/cursor to the right */
  43. #define LCD_CMD_FUNCTION_SET 0x20 /* Set function */
  44. #define LCD_CMD_DATA_LEN_8BITS 0x10 /* Set data length to 8 bits */
  45. #define LCD_CMD_TWO_LINES 0x08 /* Set to two display lines */
  46. #define LCD_CMD_FONT_5X10_DOTS 0x04 /* Set char font to 5x10 dots */
  47. #define LCD_CMD_SET_CGRAM_ADDR 0x40 /* Set char generator RAM address */
  48. #define LCD_CMD_SET_DDRAM_ADDR 0x80 /* Set display data RAM address */
  49. #define LCD_ESCAPE_LEN 24 /* Max chars for LCD escape command */
  50. #define LCD_ESCAPE_CHAR 27 /* Use char 27 for escape command */
  51. struct charlcd_priv {
  52. struct charlcd lcd;
  53. struct delayed_work bl_work;
  54. struct mutex bl_tempo_lock; /* Protects access to bl_tempo */
  55. bool bl_tempo;
  56. bool must_clear;
  57. /* contains the LCD config state */
  58. unsigned long int flags;
  59. /* Contains the LCD X and Y offset */
  60. struct {
  61. unsigned long int x;
  62. unsigned long int y;
  63. } addr;
  64. /* Current escape sequence and it's length or -1 if outside */
  65. struct {
  66. char buf[LCD_ESCAPE_LEN + 1];
  67. int len;
  68. } esc_seq;
  69. unsigned long long drvdata[0];
  70. };
  71. #define to_priv(p) container_of(p, struct charlcd_priv, lcd)
  72. /* Device single-open policy control */
  73. static atomic_t charlcd_available = ATOMIC_INIT(1);
  74. /* sleeps that many milliseconds with a reschedule */
  75. static void long_sleep(int ms)
  76. {
  77. schedule_timeout_interruptible(msecs_to_jiffies(ms));
  78. }
  79. /* turn the backlight on or off */
  80. static void charlcd_backlight(struct charlcd *lcd, int on)
  81. {
  82. struct charlcd_priv *priv = to_priv(lcd);
  83. if (!lcd->ops->backlight)
  84. return;
  85. mutex_lock(&priv->bl_tempo_lock);
  86. if (!priv->bl_tempo)
  87. lcd->ops->backlight(lcd, on);
  88. mutex_unlock(&priv->bl_tempo_lock);
  89. }
  90. static void charlcd_bl_off(struct work_struct *work)
  91. {
  92. struct delayed_work *dwork = to_delayed_work(work);
  93. struct charlcd_priv *priv =
  94. container_of(dwork, struct charlcd_priv, bl_work);
  95. mutex_lock(&priv->bl_tempo_lock);
  96. if (priv->bl_tempo) {
  97. priv->bl_tempo = false;
  98. if (!(priv->flags & LCD_FLAG_L))
  99. priv->lcd.ops->backlight(&priv->lcd, 0);
  100. }
  101. mutex_unlock(&priv->bl_tempo_lock);
  102. }
  103. /* turn the backlight on for a little while */
  104. void charlcd_poke(struct charlcd *lcd)
  105. {
  106. struct charlcd_priv *priv = to_priv(lcd);
  107. if (!lcd->ops->backlight)
  108. return;
  109. cancel_delayed_work_sync(&priv->bl_work);
  110. mutex_lock(&priv->bl_tempo_lock);
  111. if (!priv->bl_tempo && !(priv->flags & LCD_FLAG_L))
  112. lcd->ops->backlight(lcd, 1);
  113. priv->bl_tempo = true;
  114. schedule_delayed_work(&priv->bl_work, LCD_BL_TEMPO_PERIOD * HZ);
  115. mutex_unlock(&priv->bl_tempo_lock);
  116. }
  117. EXPORT_SYMBOL_GPL(charlcd_poke);
  118. static void charlcd_gotoxy(struct charlcd *lcd)
  119. {
  120. struct charlcd_priv *priv = to_priv(lcd);
  121. unsigned int addr;
  122. /*
  123. * we force the cursor to stay at the end of the
  124. * line if it wants to go farther
  125. */
  126. addr = priv->addr.x < lcd->bwidth ? priv->addr.x & (lcd->hwidth - 1)
  127. : lcd->bwidth - 1;
  128. if (priv->addr.y & 1)
  129. addr += lcd->hwidth;
  130. if (priv->addr.y & 2)
  131. addr += lcd->bwidth;
  132. lcd->ops->write_cmd(lcd, LCD_CMD_SET_DDRAM_ADDR | addr);
  133. }
  134. static void charlcd_home(struct charlcd *lcd)
  135. {
  136. struct charlcd_priv *priv = to_priv(lcd);
  137. priv->addr.x = 0;
  138. priv->addr.y = 0;
  139. charlcd_gotoxy(lcd);
  140. }
  141. static void charlcd_print(struct charlcd *lcd, char c)
  142. {
  143. struct charlcd_priv *priv = to_priv(lcd);
  144. if (priv->addr.x < lcd->bwidth) {
  145. if (lcd->char_conv)
  146. c = lcd->char_conv[(unsigned char)c];
  147. lcd->ops->write_data(lcd, c);
  148. priv->addr.x++;
  149. /* prevents the cursor from wrapping onto the next line */
  150. if (priv->addr.x == lcd->bwidth)
  151. charlcd_gotoxy(lcd);
  152. }
  153. }
  154. static void charlcd_clear_fast(struct charlcd *lcd)
  155. {
  156. int pos;
  157. charlcd_home(lcd);
  158. if (lcd->ops->clear_fast)
  159. lcd->ops->clear_fast(lcd);
  160. else
  161. for (pos = 0; pos < min(2, lcd->height) * lcd->hwidth; pos++)
  162. lcd->ops->write_data(lcd, ' ');
  163. charlcd_home(lcd);
  164. }
  165. /* clears the display and resets X/Y */
  166. static void charlcd_clear_display(struct charlcd *lcd)
  167. {
  168. struct charlcd_priv *priv = to_priv(lcd);
  169. lcd->ops->write_cmd(lcd, LCD_CMD_DISPLAY_CLEAR);
  170. priv->addr.x = 0;
  171. priv->addr.y = 0;
  172. /* we must wait a few milliseconds (15) */
  173. long_sleep(15);
  174. }
  175. static int charlcd_init_display(struct charlcd *lcd)
  176. {
  177. void (*write_cmd_raw)(struct charlcd *lcd, int cmd);
  178. struct charlcd_priv *priv = to_priv(lcd);
  179. u8 init;
  180. if (lcd->ifwidth != 4 && lcd->ifwidth != 8)
  181. return -EINVAL;
  182. priv->flags = ((lcd->height > 1) ? LCD_FLAG_N : 0) | LCD_FLAG_D |
  183. LCD_FLAG_C | LCD_FLAG_B;
  184. long_sleep(20); /* wait 20 ms after power-up for the paranoid */
  185. /*
  186. * 8-bit mode, 1 line, small fonts; let's do it 3 times, to make sure
  187. * the LCD is in 8-bit mode afterwards
  188. */
  189. init = LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS;
  190. if (lcd->ifwidth == 4) {
  191. init >>= 4;
  192. write_cmd_raw = lcd->ops->write_cmd_raw4;
  193. } else {
  194. write_cmd_raw = lcd->ops->write_cmd;
  195. }
  196. write_cmd_raw(lcd, init);
  197. long_sleep(10);
  198. write_cmd_raw(lcd, init);
  199. long_sleep(10);
  200. write_cmd_raw(lcd, init);
  201. long_sleep(10);
  202. if (lcd->ifwidth == 4) {
  203. /* Switch to 4-bit mode, 1 line, small fonts */
  204. lcd->ops->write_cmd_raw4(lcd, LCD_CMD_FUNCTION_SET >> 4);
  205. long_sleep(10);
  206. }
  207. /* set font height and lines number */
  208. lcd->ops->write_cmd(lcd,
  209. LCD_CMD_FUNCTION_SET |
  210. ((lcd->ifwidth == 8) ? LCD_CMD_DATA_LEN_8BITS : 0) |
  211. ((priv->flags & LCD_FLAG_F) ? LCD_CMD_FONT_5X10_DOTS : 0) |
  212. ((priv->flags & LCD_FLAG_N) ? LCD_CMD_TWO_LINES : 0));
  213. long_sleep(10);
  214. /* display off, cursor off, blink off */
  215. lcd->ops->write_cmd(lcd, LCD_CMD_DISPLAY_CTRL);
  216. long_sleep(10);
  217. lcd->ops->write_cmd(lcd,
  218. LCD_CMD_DISPLAY_CTRL | /* set display mode */
  219. ((priv->flags & LCD_FLAG_D) ? LCD_CMD_DISPLAY_ON : 0) |
  220. ((priv->flags & LCD_FLAG_C) ? LCD_CMD_CURSOR_ON : 0) |
  221. ((priv->flags & LCD_FLAG_B) ? LCD_CMD_BLINK_ON : 0));
  222. charlcd_backlight(lcd, (priv->flags & LCD_FLAG_L) ? 1 : 0);
  223. long_sleep(10);
  224. /* entry mode set : increment, cursor shifting */
  225. lcd->ops->write_cmd(lcd, LCD_CMD_ENTRY_MODE | LCD_CMD_CURSOR_INC);
  226. charlcd_clear_display(lcd);
  227. return 0;
  228. }
  229. /*
  230. * Parses an unsigned integer from a string, until a non-digit character
  231. * is found. The empty string is not accepted. No overflow checks are done.
  232. *
  233. * Returns whether the parsing was successful. Only in that case
  234. * the output parameters are written to.
  235. *
  236. * TODO: If the kernel adds an inplace version of kstrtoul(), this function
  237. * could be easily replaced by that.
  238. */
  239. static bool parse_n(const char *s, unsigned long *res, const char **next_s)
  240. {
  241. if (!isdigit(*s))
  242. return false;
  243. *res = 0;
  244. while (isdigit(*s)) {
  245. *res = *res * 10 + (*s - '0');
  246. ++s;
  247. }
  248. *next_s = s;
  249. return true;
  250. }
  251. /*
  252. * Parses a movement command of the form "(.*);", where the group can be
  253. * any number of subcommands of the form "(x|y)[0-9]+".
  254. *
  255. * Returns whether the command is valid. The position arguments are
  256. * only written if the parsing was successful.
  257. *
  258. * For instance:
  259. * - ";" returns (<original x>, <original y>).
  260. * - "x1;" returns (1, <original y>).
  261. * - "y2x1;" returns (1, 2).
  262. * - "x12y34x56;" returns (56, 34).
  263. * - "" fails.
  264. * - "x" fails.
  265. * - "x;" fails.
  266. * - "x1" fails.
  267. * - "xy12;" fails.
  268. * - "x12yy12;" fails.
  269. * - "xx" fails.
  270. */
  271. static bool parse_xy(const char *s, unsigned long *x, unsigned long *y)
  272. {
  273. unsigned long new_x = *x;
  274. unsigned long new_y = *y;
  275. for (;;) {
  276. if (!*s)
  277. return false;
  278. if (*s == ';')
  279. break;
  280. if (*s == 'x') {
  281. if (!parse_n(s + 1, &new_x, &s))
  282. return false;
  283. } else if (*s == 'y') {
  284. if (!parse_n(s + 1, &new_y, &s))
  285. return false;
  286. } else {
  287. return false;
  288. }
  289. }
  290. *x = new_x;
  291. *y = new_y;
  292. return true;
  293. }
  294. /*
  295. * These are the file operation function for user access to /dev/lcd
  296. * This function can also be called from inside the kernel, by
  297. * setting file and ppos to NULL.
  298. *
  299. */
  300. static inline int handle_lcd_special_code(struct charlcd *lcd)
  301. {
  302. struct charlcd_priv *priv = to_priv(lcd);
  303. /* LCD special codes */
  304. int processed = 0;
  305. char *esc = priv->esc_seq.buf + 2;
  306. int oldflags = priv->flags;
  307. /* check for display mode flags */
  308. switch (*esc) {
  309. case 'D': /* Display ON */
  310. priv->flags |= LCD_FLAG_D;
  311. processed = 1;
  312. break;
  313. case 'd': /* Display OFF */
  314. priv->flags &= ~LCD_FLAG_D;
  315. processed = 1;
  316. break;
  317. case 'C': /* Cursor ON */
  318. priv->flags |= LCD_FLAG_C;
  319. processed = 1;
  320. break;
  321. case 'c': /* Cursor OFF */
  322. priv->flags &= ~LCD_FLAG_C;
  323. processed = 1;
  324. break;
  325. case 'B': /* Blink ON */
  326. priv->flags |= LCD_FLAG_B;
  327. processed = 1;
  328. break;
  329. case 'b': /* Blink OFF */
  330. priv->flags &= ~LCD_FLAG_B;
  331. processed = 1;
  332. break;
  333. case '+': /* Back light ON */
  334. priv->flags |= LCD_FLAG_L;
  335. processed = 1;
  336. break;
  337. case '-': /* Back light OFF */
  338. priv->flags &= ~LCD_FLAG_L;
  339. processed = 1;
  340. break;
  341. case '*': /* Flash back light */
  342. charlcd_poke(lcd);
  343. processed = 1;
  344. break;
  345. case 'f': /* Small Font */
  346. priv->flags &= ~LCD_FLAG_F;
  347. processed = 1;
  348. break;
  349. case 'F': /* Large Font */
  350. priv->flags |= LCD_FLAG_F;
  351. processed = 1;
  352. break;
  353. case 'n': /* One Line */
  354. priv->flags &= ~LCD_FLAG_N;
  355. processed = 1;
  356. break;
  357. case 'N': /* Two Lines */
  358. priv->flags |= LCD_FLAG_N;
  359. processed = 1;
  360. break;
  361. case 'l': /* Shift Cursor Left */
  362. if (priv->addr.x > 0) {
  363. /* back one char if not at end of line */
  364. if (priv->addr.x < lcd->bwidth)
  365. lcd->ops->write_cmd(lcd, LCD_CMD_SHIFT);
  366. priv->addr.x--;
  367. }
  368. processed = 1;
  369. break;
  370. case 'r': /* shift cursor right */
  371. if (priv->addr.x < lcd->width) {
  372. /* allow the cursor to pass the end of the line */
  373. if (priv->addr.x < (lcd->bwidth - 1))
  374. lcd->ops->write_cmd(lcd,
  375. LCD_CMD_SHIFT | LCD_CMD_SHIFT_RIGHT);
  376. priv->addr.x++;
  377. }
  378. processed = 1;
  379. break;
  380. case 'L': /* shift display left */
  381. lcd->ops->write_cmd(lcd, LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT);
  382. processed = 1;
  383. break;
  384. case 'R': /* shift display right */
  385. lcd->ops->write_cmd(lcd,
  386. LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT |
  387. LCD_CMD_SHIFT_RIGHT);
  388. processed = 1;
  389. break;
  390. case 'k': { /* kill end of line */
  391. int x;
  392. for (x = priv->addr.x; x < lcd->bwidth; x++)
  393. lcd->ops->write_data(lcd, ' ');
  394. /* restore cursor position */
  395. charlcd_gotoxy(lcd);
  396. processed = 1;
  397. break;
  398. }
  399. case 'I': /* reinitialize display */
  400. charlcd_init_display(lcd);
  401. processed = 1;
  402. break;
  403. case 'G': {
  404. /* Generator : LGcxxxxx...xx; must have <c> between '0'
  405. * and '7', representing the numerical ASCII code of the
  406. * redefined character, and <xx...xx> a sequence of 16
  407. * hex digits representing 8 bytes for each character.
  408. * Most LCDs will only use 5 lower bits of the 7 first
  409. * bytes.
  410. */
  411. unsigned char cgbytes[8];
  412. unsigned char cgaddr;
  413. int cgoffset;
  414. int shift;
  415. char value;
  416. int addr;
  417. if (!strchr(esc, ';'))
  418. break;
  419. esc++;
  420. cgaddr = *(esc++) - '0';
  421. if (cgaddr > 7) {
  422. processed = 1;
  423. break;
  424. }
  425. cgoffset = 0;
  426. shift = 0;
  427. value = 0;
  428. while (*esc && cgoffset < 8) {
  429. shift ^= 4;
  430. if (*esc >= '0' && *esc <= '9') {
  431. value |= (*esc - '0') << shift;
  432. } else if (*esc >= 'A' && *esc <= 'F') {
  433. value |= (*esc - 'A' + 10) << shift;
  434. } else if (*esc >= 'a' && *esc <= 'f') {
  435. value |= (*esc - 'a' + 10) << shift;
  436. } else {
  437. esc++;
  438. continue;
  439. }
  440. if (shift == 0) {
  441. cgbytes[cgoffset++] = value;
  442. value = 0;
  443. }
  444. esc++;
  445. }
  446. lcd->ops->write_cmd(lcd, LCD_CMD_SET_CGRAM_ADDR | (cgaddr * 8));
  447. for (addr = 0; addr < cgoffset; addr++)
  448. lcd->ops->write_data(lcd, cgbytes[addr]);
  449. /* ensures that we stop writing to CGRAM */
  450. charlcd_gotoxy(lcd);
  451. processed = 1;
  452. break;
  453. }
  454. case 'x': /* gotoxy : LxXXX[yYYY]; */
  455. case 'y': /* gotoxy : LyYYY[xXXX]; */
  456. /* If the command is valid, move to the new address */
  457. if (parse_xy(esc, &priv->addr.x, &priv->addr.y))
  458. charlcd_gotoxy(lcd);
  459. /* Regardless of its validity, mark as processed */
  460. processed = 1;
  461. break;
  462. }
  463. /* TODO: This indent party here got ugly, clean it! */
  464. /* Check whether one flag was changed */
  465. if (oldflags == priv->flags)
  466. return processed;
  467. /* check whether one of B,C,D flags were changed */
  468. if ((oldflags ^ priv->flags) &
  469. (LCD_FLAG_B | LCD_FLAG_C | LCD_FLAG_D))
  470. /* set display mode */
  471. lcd->ops->write_cmd(lcd,
  472. LCD_CMD_DISPLAY_CTRL |
  473. ((priv->flags & LCD_FLAG_D) ? LCD_CMD_DISPLAY_ON : 0) |
  474. ((priv->flags & LCD_FLAG_C) ? LCD_CMD_CURSOR_ON : 0) |
  475. ((priv->flags & LCD_FLAG_B) ? LCD_CMD_BLINK_ON : 0));
  476. /* check whether one of F,N flags was changed */
  477. else if ((oldflags ^ priv->flags) & (LCD_FLAG_F | LCD_FLAG_N))
  478. lcd->ops->write_cmd(lcd,
  479. LCD_CMD_FUNCTION_SET |
  480. ((lcd->ifwidth == 8) ? LCD_CMD_DATA_LEN_8BITS : 0) |
  481. ((priv->flags & LCD_FLAG_F) ? LCD_CMD_FONT_5X10_DOTS : 0) |
  482. ((priv->flags & LCD_FLAG_N) ? LCD_CMD_TWO_LINES : 0));
  483. /* check whether L flag was changed */
  484. else if ((oldflags ^ priv->flags) & LCD_FLAG_L)
  485. charlcd_backlight(lcd, !!(priv->flags & LCD_FLAG_L));
  486. return processed;
  487. }
  488. static void charlcd_write_char(struct charlcd *lcd, char c)
  489. {
  490. struct charlcd_priv *priv = to_priv(lcd);
  491. /* first, we'll test if we're in escape mode */
  492. if ((c != '\n') && priv->esc_seq.len >= 0) {
  493. /* yes, let's add this char to the buffer */
  494. priv->esc_seq.buf[priv->esc_seq.len++] = c;
  495. priv->esc_seq.buf[priv->esc_seq.len] = '\0';
  496. } else {
  497. /* aborts any previous escape sequence */
  498. priv->esc_seq.len = -1;
  499. switch (c) {
  500. case LCD_ESCAPE_CHAR:
  501. /* start of an escape sequence */
  502. priv->esc_seq.len = 0;
  503. priv->esc_seq.buf[priv->esc_seq.len] = '\0';
  504. break;
  505. case '\b':
  506. /* go back one char and clear it */
  507. if (priv->addr.x > 0) {
  508. /*
  509. * check if we're not at the
  510. * end of the line
  511. */
  512. if (priv->addr.x < lcd->bwidth)
  513. /* back one char */
  514. lcd->ops->write_cmd(lcd, LCD_CMD_SHIFT);
  515. priv->addr.x--;
  516. }
  517. /* replace with a space */
  518. lcd->ops->write_data(lcd, ' ');
  519. /* back one char again */
  520. lcd->ops->write_cmd(lcd, LCD_CMD_SHIFT);
  521. break;
  522. case '\f':
  523. /* quickly clear the display */
  524. charlcd_clear_fast(lcd);
  525. break;
  526. case '\n':
  527. /*
  528. * flush the remainder of the current line and
  529. * go to the beginning of the next line
  530. */
  531. for (; priv->addr.x < lcd->bwidth; priv->addr.x++)
  532. lcd->ops->write_data(lcd, ' ');
  533. priv->addr.x = 0;
  534. priv->addr.y = (priv->addr.y + 1) % lcd->height;
  535. charlcd_gotoxy(lcd);
  536. break;
  537. case '\r':
  538. /* go to the beginning of the same line */
  539. priv->addr.x = 0;
  540. charlcd_gotoxy(lcd);
  541. break;
  542. case '\t':
  543. /* print a space instead of the tab */
  544. charlcd_print(lcd, ' ');
  545. break;
  546. default:
  547. /* simply print this char */
  548. charlcd_print(lcd, c);
  549. break;
  550. }
  551. }
  552. /*
  553. * now we'll see if we're in an escape mode and if the current
  554. * escape sequence can be understood.
  555. */
  556. if (priv->esc_seq.len >= 2) {
  557. int processed = 0;
  558. if (!strcmp(priv->esc_seq.buf, "[2J")) {
  559. /* clear the display */
  560. charlcd_clear_fast(lcd);
  561. processed = 1;
  562. } else if (!strcmp(priv->esc_seq.buf, "[H")) {
  563. /* cursor to home */
  564. charlcd_home(lcd);
  565. processed = 1;
  566. }
  567. /* codes starting with ^[[L */
  568. else if ((priv->esc_seq.len >= 3) &&
  569. (priv->esc_seq.buf[0] == '[') &&
  570. (priv->esc_seq.buf[1] == 'L')) {
  571. processed = handle_lcd_special_code(lcd);
  572. }
  573. /* LCD special escape codes */
  574. /*
  575. * flush the escape sequence if it's been processed
  576. * or if it is getting too long.
  577. */
  578. if (processed || (priv->esc_seq.len >= LCD_ESCAPE_LEN))
  579. priv->esc_seq.len = -1;
  580. } /* escape codes */
  581. }
  582. static struct charlcd *the_charlcd;
  583. static ssize_t charlcd_write(struct file *file, const char __user *buf,
  584. size_t count, loff_t *ppos)
  585. {
  586. const char __user *tmp = buf;
  587. char c;
  588. for (; count-- > 0; (*ppos)++, tmp++) {
  589. if (!in_interrupt() && (((count + 1) & 0x1f) == 0))
  590. /*
  591. * let's be a little nice with other processes
  592. * that need some CPU
  593. */
  594. schedule();
  595. if (get_user(c, tmp))
  596. return -EFAULT;
  597. charlcd_write_char(the_charlcd, c);
  598. }
  599. return tmp - buf;
  600. }
  601. static int charlcd_open(struct inode *inode, struct file *file)
  602. {
  603. struct charlcd_priv *priv = to_priv(the_charlcd);
  604. int ret;
  605. ret = -EBUSY;
  606. if (!atomic_dec_and_test(&charlcd_available))
  607. goto fail; /* open only once at a time */
  608. ret = -EPERM;
  609. if (file->f_mode & FMODE_READ) /* device is write-only */
  610. goto fail;
  611. if (priv->must_clear) {
  612. charlcd_clear_display(&priv->lcd);
  613. priv->must_clear = false;
  614. }
  615. return nonseekable_open(inode, file);
  616. fail:
  617. atomic_inc(&charlcd_available);
  618. return ret;
  619. }
  620. static int charlcd_release(struct inode *inode, struct file *file)
  621. {
  622. atomic_inc(&charlcd_available);
  623. return 0;
  624. }
  625. static const struct file_operations charlcd_fops = {
  626. .write = charlcd_write,
  627. .open = charlcd_open,
  628. .release = charlcd_release,
  629. .llseek = no_llseek,
  630. };
  631. static struct miscdevice charlcd_dev = {
  632. .minor = LCD_MINOR,
  633. .name = "lcd",
  634. .fops = &charlcd_fops,
  635. };
  636. static void charlcd_puts(struct charlcd *lcd, const char *s)
  637. {
  638. const char *tmp = s;
  639. int count = strlen(s);
  640. for (; count-- > 0; tmp++) {
  641. if (!in_interrupt() && (((count + 1) & 0x1f) == 0))
  642. /*
  643. * let's be a little nice with other processes
  644. * that need some CPU
  645. */
  646. schedule();
  647. charlcd_write_char(lcd, *tmp);
  648. }
  649. }
  650. /* initialize the LCD driver */
  651. static int charlcd_init(struct charlcd *lcd)
  652. {
  653. struct charlcd_priv *priv = to_priv(lcd);
  654. int ret;
  655. if (lcd->ops->backlight) {
  656. mutex_init(&priv->bl_tempo_lock);
  657. INIT_DELAYED_WORK(&priv->bl_work, charlcd_bl_off);
  658. }
  659. /*
  660. * before this line, we must NOT send anything to the display.
  661. * Since charlcd_init_display() needs to write data, we have to
  662. * enable mark the LCD initialized just before.
  663. */
  664. ret = charlcd_init_display(lcd);
  665. if (ret)
  666. return ret;
  667. /* display a short message */
  668. #ifdef CONFIG_PANEL_CHANGE_MESSAGE
  669. #ifdef CONFIG_PANEL_BOOT_MESSAGE
  670. charlcd_puts(lcd, "\x1b[Lc\x1b[Lb\x1b[L*" CONFIG_PANEL_BOOT_MESSAGE);
  671. #endif
  672. #else
  673. charlcd_puts(lcd, "\x1b[Lc\x1b[Lb\x1b[L*Linux-" UTS_RELEASE "\n");
  674. #endif
  675. /* clear the display on the next device opening */
  676. priv->must_clear = true;
  677. charlcd_home(lcd);
  678. return 0;
  679. }
  680. struct charlcd *charlcd_alloc(unsigned int drvdata_size)
  681. {
  682. struct charlcd_priv *priv;
  683. struct charlcd *lcd;
  684. priv = kzalloc(sizeof(*priv) + drvdata_size, GFP_KERNEL);
  685. if (!priv)
  686. return NULL;
  687. priv->esc_seq.len = -1;
  688. lcd = &priv->lcd;
  689. lcd->ifwidth = 8;
  690. lcd->bwidth = DEFAULT_LCD_BWIDTH;
  691. lcd->hwidth = DEFAULT_LCD_HWIDTH;
  692. lcd->drvdata = priv->drvdata;
  693. return lcd;
  694. }
  695. EXPORT_SYMBOL_GPL(charlcd_alloc);
  696. static int panel_notify_sys(struct notifier_block *this, unsigned long code,
  697. void *unused)
  698. {
  699. struct charlcd *lcd = the_charlcd;
  700. switch (code) {
  701. case SYS_DOWN:
  702. charlcd_puts(lcd,
  703. "\x0cReloading\nSystem...\x1b[Lc\x1b[Lb\x1b[L+");
  704. break;
  705. case SYS_HALT:
  706. charlcd_puts(lcd, "\x0cSystem Halted.\x1b[Lc\x1b[Lb\x1b[L+");
  707. break;
  708. case SYS_POWER_OFF:
  709. charlcd_puts(lcd, "\x0cPower off.\x1b[Lc\x1b[Lb\x1b[L+");
  710. break;
  711. default:
  712. break;
  713. }
  714. return NOTIFY_DONE;
  715. }
  716. static struct notifier_block panel_notifier = {
  717. panel_notify_sys,
  718. NULL,
  719. 0
  720. };
  721. int charlcd_register(struct charlcd *lcd)
  722. {
  723. int ret;
  724. ret = charlcd_init(lcd);
  725. if (ret)
  726. return ret;
  727. ret = misc_register(&charlcd_dev);
  728. if (ret)
  729. return ret;
  730. the_charlcd = lcd;
  731. register_reboot_notifier(&panel_notifier);
  732. return 0;
  733. }
  734. EXPORT_SYMBOL_GPL(charlcd_register);
  735. int charlcd_unregister(struct charlcd *lcd)
  736. {
  737. struct charlcd_priv *priv = to_priv(lcd);
  738. unregister_reboot_notifier(&panel_notifier);
  739. charlcd_puts(lcd, "\x0cLCD driver unloaded.\x1b[Lc\x1b[Lb\x1b[L-");
  740. misc_deregister(&charlcd_dev);
  741. the_charlcd = NULL;
  742. if (lcd->ops->backlight) {
  743. cancel_delayed_work_sync(&priv->bl_work);
  744. priv->lcd.ops->backlight(&priv->lcd, 0);
  745. }
  746. return 0;
  747. }
  748. EXPORT_SYMBOL_GPL(charlcd_unregister);
  749. MODULE_LICENSE("GPL");