History

auxdisplay: charlcd: Extract character LCD core from misc/panel

Extract the character LCD core from the Parallel port LCD/Keypad Panel driver in the misc subsystem, and convert it into a subdriver in the auxdisplay subsystem. This allows the character LCD core to be used by other drivers later. Compilation is controlled by its own Kconfig symbol CHARLCD, which is to be selected by its users, but can be enabled manually for compile-testing. All functions changed their prefix from "lcd_" to "charlcd_", and gained a "struct charlcd *" parameter to operate on a specific instance. While the driver API thus is ready to support multiple instances, the current limitation of a single display (/dev/lcd has a single misc minor assigned) is retained. No functional changes intended.

Geert Uytterhoeven committed 9 years ago

Commit 39f8ea41 parent 2eec1086 files · +927 −735Browse files

Unified · Split

6 files
  1. drivers/auxdisplay/Kconfig +3 −0
  2. drivers/auxdisplay/Makefile +1 −0
  3. drivers/auxdisplay/charlcd.c +790 −0
  4. drivers/misc/Kconfig +1 −0
  5. drivers/misc/panel.c +92 −735
  6. include/misc/charlcd.h +40 −0
drivers/auxdisplay/Kconfig+3−0
@@ -13,6 +13,9 @@ menuconfig AUXDISPLAY · 12 unmodified lines
1313
1414 If you say N, all options in this submenu will be skipped and disabled.
1515
16+config CHARLCD
17+ tristate "Character LCD core support" if COMPILE_TEST
18+
1619 if AUXDISPLAY
1720
1821 config KS0108
drivers/auxdisplay/Makefile+1−0
@@ -2,6 +2,7 @@ · 1 unmodified line
22 # Makefile for the kernel auxiliary displays device drivers.
33 #
44
5+obj-$(CONFIG_CHARLCD) += charlcd.o
56 obj-$(CONFIG_KS0108) += ks0108.o
67 obj-$(CONFIG_CFAG12864B) += cfag12864b.o cfag12864bfb.o
78 obj-$(CONFIG_IMG_ASCII_LCD) += img-ascii-lcd.o
drivers/auxdisplay/charlcd.c+790−0
@@ -0,0 +1,790 @@
1+/*
2+ * Character LCD driver for Linux
3+ *
4+ * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu>
5+ * Copyright (C) 2016-2017 Glider bvba
6+ *
7+ * This program is free software; you can redistribute it and/or
8+ * modify it under the terms of the GNU General Public License
9+ * as published by the Free Software Foundation; either version
10+ * 2 of the License, or (at your option) any later version.
11+ */
12+
13+#include <linux/atomic.h>
14+#include <linux/delay.h>
15+#include <linux/fs.h>
16+#include <linux/miscdevice.h>
17+#include <linux/module.h>
18+#include <linux/notifier.h>
19+#include <linux/reboot.h>
20+#include <linux/slab.h>
21+#include <linux/uaccess.h>
22+#include <linux/workqueue.h>
23+
24+#include <generated/utsrelease.h>
25+
26+#include <misc/charlcd.h>
27+
28+#define LCD_MINOR 156
29+
30+#define DEFAULT_LCD_BWIDTH 40
31+#define DEFAULT_LCD_HWIDTH 64
32+
33+/* Keep the backlight on this many seconds for each flash */
34+#define LCD_BL_TEMPO_PERIOD 4
35+
36+#define LCD_FLAG_B 0x0004 /* Blink on */
37+#define LCD_FLAG_C 0x0008 /* Cursor on */
38+#define LCD_FLAG_D 0x0010 /* Display on */
39+#define LCD_FLAG_F 0x0020 /* Large font mode */
40+#define LCD_FLAG_N 0x0040 /* 2-rows mode */
41+#define LCD_FLAG_L 0x0080 /* Backlight enabled */
42+
43+/* LCD commands */
44+#define LCD_CMD_DISPLAY_CLEAR 0x01 /* Clear entire display */
45+
46+#define LCD_CMD_ENTRY_MODE 0x04 /* Set entry mode */
47+#define LCD_CMD_CURSOR_INC 0x02 /* Increment cursor */
48+
49+#define LCD_CMD_DISPLAY_CTRL 0x08 /* Display control */
50+#define LCD_CMD_DISPLAY_ON 0x04 /* Set display on */
51+#define LCD_CMD_CURSOR_ON 0x02 /* Set cursor on */
52+#define LCD_CMD_BLINK_ON 0x01 /* Set blink on */
53+
54+#define LCD_CMD_SHIFT 0x10 /* Shift cursor/display */
55+#define LCD_CMD_DISPLAY_SHIFT 0x08 /* Shift display instead of cursor */
56+#define LCD_CMD_SHIFT_RIGHT 0x04 /* Shift display/cursor to the right */
57+
58+#define LCD_CMD_FUNCTION_SET 0x20 /* Set function */
59+#define LCD_CMD_DATA_LEN_8BITS 0x10 /* Set data length to 8 bits */
60+#define LCD_CMD_TWO_LINES 0x08 /* Set to two display lines */
61+#define LCD_CMD_FONT_5X10_DOTS 0x04 /* Set char font to 5x10 dots */
62+
63+#define LCD_CMD_SET_CGRAM_ADDR 0x40 /* Set char generator RAM address */
64+
65+#define LCD_CMD_SET_DDRAM_ADDR 0x80 /* Set display data RAM address */
66+
67+#define LCD_ESCAPE_LEN 24 /* Max chars for LCD escape command */
68+#define LCD_ESCAPE_CHAR 27 /* Use char 27 for escape command */
69+
70+struct charlcd_priv {
71+ struct charlcd lcd;
72+
73+ struct delayed_work bl_work;
74+ struct mutex bl_tempo_lock; /* Protects access to bl_tempo */
75+ bool bl_tempo;
76+
77+ bool must_clear;
78+
79+ /* contains the LCD config state */
80+ unsigned long int flags;
81+
82+ /* Contains the LCD X and Y offset */
83+ struct {
84+ unsigned long int x;
85+ unsigned long int y;
86+ } addr;
87+
88+ /* Current escape sequence and it's length or -1 if outside */
89+ struct {
90+ char buf[LCD_ESCAPE_LEN + 1];
91+ int len;
92+ } esc_seq;
93+
94+ unsigned long long drvdata[0];
95+};
96+
97+#define to_priv(p) container_of(p, struct charlcd_priv, lcd)
98+
99+/* Device single-open policy control */
100+static atomic_t charlcd_available = ATOMIC_INIT(1);
101+
102+/* sleeps that many milliseconds with a reschedule */
103+static void long_sleep(int ms)
104+{
105+ if (in_interrupt())
106+ mdelay(ms);
107+ else
108+ schedule_timeout_interruptible(msecs_to_jiffies(ms));
109+}
110+
111+/* turn the backlight on or off */
112+static void charlcd_backlight(struct charlcd *lcd, int on)
113+{
114+ struct charlcd_priv *priv = to_priv(lcd);
115+
116+ if (!lcd->ops->backlight)
117+ return;
118+
119+ mutex_lock(&priv->bl_tempo_lock);
120+ if (!priv->bl_tempo)
121+ lcd->ops->backlight(lcd, on);
122+ mutex_unlock(&priv->bl_tempo_lock);
123+}
124+
125+static void charlcd_bl_off(struct work_struct *work)
126+{
127+ struct delayed_work *dwork = to_delayed_work(work);
128+ struct charlcd_priv *priv =
129+ container_of(dwork, struct charlcd_priv, bl_work);
130+
131+ mutex_lock(&priv->bl_tempo_lock);
132+ if (priv->bl_tempo) {
133+ priv->bl_tempo = false;
134+ if (!(priv->flags & LCD_FLAG_L))
135+ priv->lcd.ops->backlight(&priv->lcd, 0);
136+ }
137+ mutex_unlock(&priv->bl_tempo_lock);
138+}
139+
140+/* turn the backlight on for a little while */
141+void charlcd_poke(struct charlcd *lcd)
142+{
143+ struct charlcd_priv *priv = to_priv(lcd);
144+
145+ if (!lcd->ops->backlight)
146+ return;
147+
148+ cancel_delayed_work_sync(&priv->bl_work);
149+
150+ mutex_lock(&priv->bl_tempo_lock);
151+ if (!priv->bl_tempo && !(priv->flags & LCD_FLAG_L))
152+ lcd->ops->backlight(lcd, 1);
153+ priv->bl_tempo = true;
154+ schedule_delayed_work(&priv->bl_work, LCD_BL_TEMPO_PERIOD * HZ);
155+ mutex_unlock(&priv->bl_tempo_lock);
156+}
157+EXPORT_SYMBOL_GPL(charlcd_poke);
158+
159+static void charlcd_gotoxy(struct charlcd *lcd)
160+{
161+ struct charlcd_priv *priv = to_priv(lcd);
162+
163+ lcd->ops->write_cmd(lcd,
164+ LCD_CMD_SET_DDRAM_ADDR | (priv->addr.y ? lcd->hwidth : 0) |
165+ /*
166+ * we force the cursor to stay at the end of the
167+ * line if it wants to go farther
168+ */
169+ ((priv->addr.x < lcd->bwidth) ? priv->addr.x & (lcd->hwidth - 1)
170+ : lcd->bwidth - 1));
171+}
172+
173+static void charlcd_home(struct charlcd *lcd)
174+{
175+ struct charlcd_priv *priv = to_priv(lcd);
176+
177+ priv->addr.x = 0;
178+ priv->addr.y = 0;
179+ charlcd_gotoxy(lcd);
180+}
181+
182+static void charlcd_print(struct charlcd *lcd, char c)
183+{
184+ struct charlcd_priv *priv = to_priv(lcd);
185+
186+ if (priv->addr.x < lcd->bwidth) {
187+ if (lcd->char_conv)
188+ c = lcd->char_conv[(unsigned char)c];
189+ lcd->ops->write_data(lcd, c);
190+ priv->addr.x++;
191+ }
192+ /* prevents the cursor from wrapping onto the next line */
193+ if (priv->addr.x == lcd->bwidth)
194+ charlcd_gotoxy(lcd);
195+}
196+
197+static void charlcd_clear_fast(struct charlcd *lcd)
198+{
199+ int pos;
200+
201+ charlcd_home(lcd);
202+
203+ if (lcd->ops->clear_fast)
204+ lcd->ops->clear_fast(lcd);
205+ else
206+ for (pos = 0; pos < lcd->height * lcd->hwidth; pos++)
207+ lcd->ops->write_data(lcd, ' ');
208+
209+ charlcd_home(lcd);
210+}
211+
212+/* clears the display and resets X/Y */
213+static void charlcd_clear_display(struct charlcd *lcd)
214+{
215+ struct charlcd_priv *priv = to_priv(lcd);
216+
217+ lcd->ops->write_cmd(lcd, LCD_CMD_DISPLAY_CLEAR);
218+ priv->addr.x = 0;
219+ priv->addr.y = 0;
220+ /* we must wait a few milliseconds (15) */
221+ long_sleep(15);
222+}
223+
224+static int charlcd_init_display(struct charlcd *lcd)
225+{
226+ struct charlcd_priv *priv = to_priv(lcd);
227+
228+ priv->flags = ((lcd->height > 1) ? LCD_FLAG_N : 0) | LCD_FLAG_D |
229+ LCD_FLAG_C | LCD_FLAG_B;
230+
231+ long_sleep(20); /* wait 20 ms after power-up for the paranoid */
232+
233+ /* 8bits, 1 line, small fonts; let's do it 3 times */
234+ lcd->ops->write_cmd(lcd, LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS);
235+ long_sleep(10);
236+ lcd->ops->write_cmd(lcd, LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS);
237+ long_sleep(10);
238+ lcd->ops->write_cmd(lcd, LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS);
239+ long_sleep(10);
240+
241+ /* set font height and lines number */
242+ lcd->ops->write_cmd(lcd,
243+ LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS |
244+ ((priv->flags & LCD_FLAG_F) ? LCD_CMD_FONT_5X10_DOTS : 0) |
245+ ((priv->flags & LCD_FLAG_N) ? LCD_CMD_TWO_LINES : 0));
246+ long_sleep(10);
247+
248+ /* display off, cursor off, blink off */
249+ lcd->ops->write_cmd(lcd, LCD_CMD_DISPLAY_CTRL);
250+ long_sleep(10);
251+
252+ lcd->ops->write_cmd(lcd,
253+ LCD_CMD_DISPLAY_CTRL | /* set display mode */
254+ ((priv->flags & LCD_FLAG_D) ? LCD_CMD_DISPLAY_ON : 0) |
255+ ((priv->flags & LCD_FLAG_C) ? LCD_CMD_CURSOR_ON : 0) |
256+ ((priv->flags & LCD_FLAG_B) ? LCD_CMD_BLINK_ON : 0));
257+
258+ charlcd_backlight(lcd, (priv->flags & LCD_FLAG_L) ? 1 : 0);
259+
260+ long_sleep(10);
261+
262+ /* entry mode set : increment, cursor shifting */
263+ lcd->ops->write_cmd(lcd, LCD_CMD_ENTRY_MODE | LCD_CMD_CURSOR_INC);
264+
265+ charlcd_clear_display(lcd);
266+ return 0;
267+}
268+
269+/*
270+ * These are the file operation function for user access to /dev/lcd
271+ * This function can also be called from inside the kernel, by
272+ * setting file and ppos to NULL.
273+ *
274+ */
275+
276+static inline int handle_lcd_special_code(struct charlcd *lcd)
277+{
278+ struct charlcd_priv *priv = to_priv(lcd);
279+
280+ /* LCD special codes */
281+
282+ int processed = 0;
283+
284+ char *esc = priv->esc_seq.buf + 2;
285+ int oldflags = priv->flags;
286+
287+ /* check for display mode flags */
288+ switch (*esc) {
289+ case 'D': /* Display ON */
290+ priv->flags |= LCD_FLAG_D;
291+ processed = 1;
292+ break;
293+ case 'd': /* Display OFF */
294+ priv->flags &= ~LCD_FLAG_D;
295+ processed = 1;
296+ break;
297+ case 'C': /* Cursor ON */
298+ priv->flags |= LCD_FLAG_C;
299+ processed = 1;
300+ break;
301+ case 'c': /* Cursor OFF */
302+ priv->flags &= ~LCD_FLAG_C;
303+ processed = 1;
304+ break;
305+ case 'B': /* Blink ON */
306+ priv->flags |= LCD_FLAG_B;
307+ processed = 1;
308+ break;
309+ case 'b': /* Blink OFF */
310+ priv->flags &= ~LCD_FLAG_B;
311+ processed = 1;
312+ break;
313+ case '+': /* Back light ON */
314+ priv->flags |= LCD_FLAG_L;
315+ processed = 1;
316+ break;
317+ case '-': /* Back light OFF */
318+ priv->flags &= ~LCD_FLAG_L;
319+ processed = 1;
320+ break;
321+ case '*': /* Flash back light */
322+ charlcd_poke(lcd);
323+ processed = 1;
324+ break;
325+ case 'f': /* Small Font */
326+ priv->flags &= ~LCD_FLAG_F;
327+ processed = 1;
328+ break;
329+ case 'F': /* Large Font */
330+ priv->flags |= LCD_FLAG_F;
331+ processed = 1;
332+ break;
333+ case 'n': /* One Line */
334+ priv->flags &= ~LCD_FLAG_N;
335+ processed = 1;
336+ break;
337+ case 'N': /* Two Lines */
338+ priv->flags |= LCD_FLAG_N;
339+ break;
340+ case 'l': /* Shift Cursor Left */
341+ if (priv->addr.x > 0) {
342+ /* back one char if not at end of line */
343+ if (priv->addr.x < lcd->bwidth)
344+ lcd->ops->write_cmd(lcd, LCD_CMD_SHIFT);
345+ priv->addr.x--;
346+ }
347+ processed = 1;
348+ break;
349+ case 'r': /* shift cursor right */
350+ if (priv->addr.x < lcd->width) {
351+ /* allow the cursor to pass the end of the line */
352+ if (priv->addr.x < (lcd->bwidth - 1))
353+ lcd->ops->write_cmd(lcd,
354+ LCD_CMD_SHIFT | LCD_CMD_SHIFT_RIGHT);
355+ priv->addr.x++;
356+ }
357+ processed = 1;
358+ break;
359+ case 'L': /* shift display left */
360+ lcd->ops->write_cmd(lcd, LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT);
361+ processed = 1;
362+ break;
363+ case 'R': /* shift display right */
364+ lcd->ops->write_cmd(lcd,
365+ LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT |
366+ LCD_CMD_SHIFT_RIGHT);
367+ processed = 1;
368+ break;
369+ case 'k': { /* kill end of line */
370+ int x;
371+
372+ for (x = priv->addr.x; x < lcd->bwidth; x++)
373+ lcd->ops->write_data(lcd, ' ');
374+
375+ /* restore cursor position */
376+ charlcd_gotoxy(lcd);
377+ processed = 1;
378+ break;
379+ }
380+ case 'I': /* reinitialize display */
381+ charlcd_init_display(lcd);
382+ processed = 1;
383+ break;
384+ case 'G': {
385+ /* Generator : LGcxxxxx...xx; must have <c> between '0'
386+ * and '7', representing the numerical ASCII code of the
387+ * redefined character, and <xx...xx> a sequence of 16
388+ * hex digits representing 8 bytes for each character.
389+ * Most LCDs will only use 5 lower bits of the 7 first
390+ * bytes.
391+ */
392+
393+ unsigned char cgbytes[8];
394+ unsigned char cgaddr;
395+ int cgoffset;
396+ int shift;
397+ char value;
398+ int addr;
399+
400+ if (!strchr(esc, ';'))
401+ break;
402+
403+ esc++;
404+
405+ cgaddr = *(esc++) - '0';
406+ if (cgaddr > 7) {
407+ processed = 1;
408+ break;
409+ }
410+
411+ cgoffset = 0;
412+ shift = 0;
413+ value = 0;
414+ while (*esc && cgoffset < 8) {
415+ shift ^= 4;
416+ if (*esc >= '0' && *esc <= '9') {
417+ value |= (*esc - '0') << shift;
418+ } else if (*esc >= 'A' && *esc <= 'Z') {
419+ value |= (*esc - 'A' + 10) << shift;
420+ } else if (*esc >= 'a' && *esc <= 'z') {
421+ value |= (*esc - 'a' + 10) << shift;
422+ } else {
423+ esc++;
424+ continue;
425+ }
426+
427+ if (shift == 0) {
428+ cgbytes[cgoffset++] = value;
429+ value = 0;
430+ }
431+
432+ esc++;
433+ }
434+
435+ lcd->ops->write_cmd(lcd, LCD_CMD_SET_CGRAM_ADDR | (cgaddr * 8));
436+ for (addr = 0; addr < cgoffset; addr++)
437+ lcd->ops->write_data(lcd, cgbytes[addr]);
438+
439+ /* ensures that we stop writing to CGRAM */
440+ charlcd_gotoxy(lcd);
441+ processed = 1;
442+ break;
443+ }
444+ case 'x': /* gotoxy : LxXXX[yYYY]; */
445+ case 'y': /* gotoxy : LyYYY[xXXX]; */
446+ if (!strchr(esc, ';'))
447+ break;
448+
449+ while (*esc) {
450+ if (*esc == 'x') {
451+ esc++;
452+ if (kstrtoul(esc, 10, &priv->addr.x) < 0)
453+ break;
454+ } else if (*esc == 'y') {
455+ esc++;
456+ if (kstrtoul(esc, 10, &priv->addr.y) < 0)
457+ break;
458+ } else {
459+ break;
460+ }
461+ }
462+
463+ charlcd_gotoxy(lcd);
464+ processed = 1;
465+ break;
466+ }
467+
468+ /* TODO: This indent party here got ugly, clean it! */
469+ /* Check whether one flag was changed */
470+ if (oldflags == priv->flags)
471+ return processed;
472+
473+ /* check whether one of B,C,D flags were changed */
474+ if ((oldflags ^ priv->flags) &
475+ (LCD_FLAG_B | LCD_FLAG_C | LCD_FLAG_D))
476+ /* set display mode */
477+ lcd->ops->write_cmd(lcd,
478+ LCD_CMD_DISPLAY_CTRL |
479+ ((priv->flags & LCD_FLAG_D) ? LCD_CMD_DISPLAY_ON : 0) |
480+ ((priv->flags & LCD_FLAG_C) ? LCD_CMD_CURSOR_ON : 0) |
481+ ((priv->flags & LCD_FLAG_B) ? LCD_CMD_BLINK_ON : 0));
482+ /* check whether one of F,N flags was changed */
483+ else if ((oldflags ^ priv->flags) & (LCD_FLAG_F | LCD_FLAG_N))
484+ lcd->ops->write_cmd(lcd,
485+ LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS |
486+ ((priv->flags & LCD_FLAG_F) ? LCD_CMD_FONT_5X10_DOTS : 0) |
487+ ((priv->flags & LCD_FLAG_N) ? LCD_CMD_TWO_LINES : 0));
488+ /* check whether L flag was changed */
489+ else if ((oldflags ^ priv->flags) & LCD_FLAG_L)
490+ charlcd_backlight(lcd, !!(priv->flags & LCD_FLAG_L));
491+
492+ return processed;
493+}
494+
495+static void charlcd_write_char(struct charlcd *lcd, char c)
496+{
497+ struct charlcd_priv *priv = to_priv(lcd);
498+
499+ /* first, we'll test if we're in escape mode */
500+ if ((c != '\n') && priv->esc_seq.len >= 0) {
501+ /* yes, let's add this char to the buffer */
502+ priv->esc_seq.buf[priv->esc_seq.len++] = c;
503+ priv->esc_seq.buf[priv->esc_seq.len] = 0;
504+ } else {
505+ /* aborts any previous escape sequence */
506+ priv->esc_seq.len = -1;
507+
508+ switch (c) {
509+ case LCD_ESCAPE_CHAR:
510+ /* start of an escape sequence */
511+ priv->esc_seq.len = 0;
512+ priv->esc_seq.buf[priv->esc_seq.len] = 0;
513+ break;
514+ case '\b':
515+ /* go back one char and clear it */
516+ if (priv->addr.x > 0) {
517+ /*
518+ * check if we're not at the
519+ * end of the line
520+ */
521+ if (priv->addr.x < lcd->bwidth)
522+ /* back one char */
523+ lcd->ops->write_cmd(lcd, LCD_CMD_SHIFT);
524+ priv->addr.x--;
525+ }
526+ /* replace with a space */
527+ lcd->ops->write_data(lcd, ' ');
528+ /* back one char again */
529+ lcd->ops->write_cmd(lcd, LCD_CMD_SHIFT);
530+ break;
531+ case '\014':
532+ /* quickly clear the display */
533+ charlcd_clear_fast(lcd);
534+ break;
535+ case '\n':
536+ /*
537+ * flush the remainder of the current line and
538+ * go to the beginning of the next line
539+ */
540+ for (; priv->addr.x < lcd->bwidth; priv->addr.x++)
541+ lcd->ops->write_data(lcd, ' ');
542+ priv->addr.x = 0;
543+ priv->addr.y = (priv->addr.y + 1) % lcd->height;
544+ charlcd_gotoxy(lcd);
545+ break;
546+ case '\r':
547+ /* go to the beginning of the same line */
548+ priv->addr.x = 0;
549+ charlcd_gotoxy(lcd);
550+ break;
551+ case '\t':
552+ /* print a space instead of the tab */
553+ charlcd_print(lcd, ' ');
554+ break;
555+ default:
556+ /* simply print this char */
557+ charlcd_print(lcd, c);
558+ break;
559+ }
560+ }
561+
562+ /*
563+ * now we'll see if we're in an escape mode and if the current
564+ * escape sequence can be understood.
565+ */
566+ if (priv->esc_seq.len >= 2) {
567+ int processed = 0;
568+
569+ if (!strcmp(priv->esc_seq.buf, "[2J")) {
570+ /* clear the display */
571+ charlcd_clear_fast(lcd);
572+ processed = 1;
573+ } else if (!strcmp(priv->esc_seq.buf, "[H")) {
574+ /* cursor to home */
575+ charlcd_home(lcd);
576+ processed = 1;
577+ }
578+ /* codes starting with ^[[L */
579+ else if ((priv->esc_seq.len >= 3) &&
580+ (priv->esc_seq.buf[0] == '[') &&
581+ (priv->esc_seq.buf[1] == 'L')) {
582+ processed = handle_lcd_special_code(lcd);
583+ }
584+
585+ /* LCD special escape codes */
586+ /*
587+ * flush the escape sequence if it's been processed
588+ * or if it is getting too long.
589+ */
590+ if (processed || (priv->esc_seq.len >= LCD_ESCAPE_LEN))
591+ priv->esc_seq.len = -1;
592+ } /* escape codes */
593+}
594+
595+static struct charlcd *the_charlcd;
596+
597+static ssize_t charlcd_write(struct file *file, const char __user *buf,
598+ size_t count, loff_t *ppos)
599+{
600+ const char __user *tmp = buf;
601+ char c;
602+
603+ for (; count-- > 0; (*ppos)++, tmp++) {
604+ if (!in_interrupt() && (((count + 1) & 0x1f) == 0))
605+ /*
606+ * let's be a little nice with other processes
607+ * that need some CPU
608+ */
609+ schedule();
610+
611+ if (get_user(c, tmp))
612+ return -EFAULT;
613+
614+ charlcd_write_char(the_charlcd, c);
615+ }
616+
617+ return tmp - buf;
618+}
619+
620+static int charlcd_open(struct inode *inode, struct file *file)
621+{
622+ struct charlcd_priv *priv = to_priv(the_charlcd);
623+
624+ if (!atomic_dec_and_test(&charlcd_available))
625+ return -EBUSY; /* open only once at a time */
626+
627+ if (file->f_mode & FMODE_READ) /* device is write-only */
628+ return -EPERM;
629+
630+ if (priv->must_clear) {
631+ charlcd_clear_display(&priv->lcd);
632+ priv->must_clear = false;
633+ }
634+ return nonseekable_open(inode, file);
635+}
636+
637+static int charlcd_release(struct inode *inode, struct file *file)
638+{
639+ atomic_inc(&charlcd_available);
640+ return 0;
641+}
642+
643+static const struct file_operations charlcd_fops = {
644+ .write = charlcd_write,
645+ .open = charlcd_open,
646+ .release = charlcd_release,
647+ .llseek = no_llseek,
648+};
649+
650+static struct miscdevice charlcd_dev = {
651+ .minor = LCD_MINOR,
652+ .name = "lcd",
653+ .fops = &charlcd_fops,
654+};
655+
656+static void charlcd_puts(struct charlcd *lcd, const char *s)
657+{
658+ const char *tmp = s;
659+ int count = strlen(s);
660+
661+ for (; count-- > 0; tmp++) {
662+ if (!in_interrupt() && (((count + 1) & 0x1f) == 0))
663+ /*
664+ * let's be a little nice with other processes
665+ * that need some CPU
666+ */
667+ schedule();
668+
669+ charlcd_write_char(lcd, *tmp);
670+ }
671+}
672+
673+/* initialize the LCD driver */
674+static int charlcd_init(struct charlcd *lcd)
675+{
676+ struct charlcd_priv *priv = to_priv(lcd);
677+ int ret;
678+
679+ if (lcd->ops->backlight) {
680+ mutex_init(&priv->bl_tempo_lock);
681+ INIT_DELAYED_WORK(&priv->bl_work, charlcd_bl_off);
682+ }
683+
684+ /*
685+ * before this line, we must NOT send anything to the display.
686+ * Since charlcd_init_display() needs to write data, we have to
687+ * enable mark the LCD initialized just before.
688+ */
689+ ret = charlcd_init_display(lcd);
690+ if (ret)
691+ return ret;
692+
693+ /* display a short message */
694+#ifdef CONFIG_PANEL_CHANGE_MESSAGE
695+#ifdef CONFIG_PANEL_BOOT_MESSAGE
696+ charlcd_puts(lcd, "\x1b[Lc\x1b[Lb\x1b[L*" CONFIG_PANEL_BOOT_MESSAGE);
697+#endif
698+#else
699+ charlcd_puts(lcd, "\x1b[Lc\x1b[Lb\x1b[L*Linux-" UTS_RELEASE "\n");
700+#endif
701+ /* clear the display on the next device opening */
702+ priv->must_clear = true;
703+ charlcd_home(lcd);
704+ return 0;
705+}
706+
707+struct charlcd *charlcd_alloc(unsigned int drvdata_size)
708+{
709+ struct charlcd_priv *priv;
710+ struct charlcd *lcd;
711+
712+ priv = kzalloc(sizeof(*priv) + drvdata_size, GFP_KERNEL);
713+ if (!priv)
714+ return NULL;
715+
716+ priv->esc_seq.len = -1;
717+
718+ lcd = &priv->lcd;
719+ lcd->bwidth = DEFAULT_LCD_BWIDTH;
720+ lcd->hwidth = DEFAULT_LCD_HWIDTH;
721+ lcd->drvdata = priv->drvdata;
722+
723+ return lcd;
724+}
725+EXPORT_SYMBOL_GPL(charlcd_alloc);
726+
727+static int panel_notify_sys(struct notifier_block *this, unsigned long code,
728+ void *unused)
729+{
730+ struct charlcd *lcd = the_charlcd;
731+
732+ switch (code) {
733+ case SYS_DOWN:
734+ charlcd_puts(lcd,
735+ "\x0cReloading\nSystem...\x1b[Lc\x1b[Lb\x1b[L+");
736+ break;
737+ case SYS_HALT:
738+ charlcd_puts(lcd, "\x0cSystem Halted.\x1b[Lc\x1b[Lb\x1b[L+");
739+ break;
740+ case SYS_POWER_OFF:
741+ charlcd_puts(lcd, "\x0cPower off.\x1b[Lc\x1b[Lb\x1b[L+");
742+ break;
743+ default:
744+ break;
745+ }
746+ return NOTIFY_DONE;
747+}
748+
749+static struct notifier_block panel_notifier = {
750+ panel_notify_sys,
751+ NULL,
752+ 0
753+};
754+
755+int charlcd_register(struct charlcd *lcd)
756+{
757+ int ret;
758+
759+ ret = charlcd_init(lcd);
760+ if (ret)
761+ return ret;
762+
763+ ret = misc_register(&charlcd_dev);
764+ if (ret)
765+ return ret;
766+
767+ the_charlcd = lcd;
768+ register_reboot_notifier(&panel_notifier);
769+ return 0;
770+}
771+EXPORT_SYMBOL_GPL(charlcd_register);
772+
773+int charlcd_unregister(struct charlcd *lcd)
774+{
775+ struct charlcd_priv *priv = to_priv(lcd);
776+
777+ unregister_reboot_notifier(&panel_notifier);
778+ charlcd_puts(lcd, "\x0cLCD driver unloaded.\x1b[Lc\x1b[Lb\x1b[L-");
779+ misc_deregister(&charlcd_dev);
780+ the_charlcd = NULL;
781+ if (lcd->ops->backlight) {
782+ cancel_delayed_work_sync(&priv->bl_work);
783+ priv->lcd.ops->backlight(&priv->lcd, 0);
784+ }
785+
786+ return 0;
787+}
788+EXPORT_SYMBOL_GPL(charlcd_unregister);
789+
790+MODULE_LICENSE("GPL");
drivers/misc/Kconfig+1−0
@@ -495,6 +495,7 @@ config VEXPRESS_SYSCFG · 494 unmodified lines
495495 config PANEL
496496 tristate "Parallel port LCD/Keypad Panel support"
497497 depends on PARPORT
498+ select CHARLCD
498499 ---help---
499500 Say Y here if you have an HD44780 or KS-0074 LCD connected to your
500501 parallel port. This driver also features 4 and 6-key keypads. The LCD
drivers/misc/panel.c+92−735
@@ -1,6 +1,7 @@
11 /*
22 * Front panel driver for Linux
33 * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu>
4+ * Copyright (C) 2016-2017 Glider bvba
45 *
56 * This program is free software; you can redistribute it and/or
67 * modify it under the terms of the GNU General Public License
@@ -54,15 +55,12 @@ · 47 unmodified lines
5455 #include <linux/ctype.h>
5556 #include <linux/parport.h>
5657 #include <linux/list.h>
57−#include <linux/notifier.h>
58−#include <linux/reboot.h>
59−#include <linux/workqueue.h>
60−#include <generated/utsrelease.h>
6158
6259 #include <linux/io.h>
6360 #include <linux/uaccess.h>
6461
65−#define LCD_MINOR 156
62+#include <misc/charlcd.h>
63+
6664 #define KEYPAD_MINOR 185
6765
6866 #define LCD_MAXBYTES 256 /* max burst write */
@@ -76,9 +74,6 @@ · 7 unmodified lines
7674 /* a key repeats this times INPUT_POLL_TIME */
7775 #define KEYPAD_REP_DELAY (2)
7876
79−/* keep the light on this many seconds for each flash */
80−#define FLASH_LIGHT_TEMPO (4)
81−
8277 /* converts an r_str() input to an active high, bits string : 000BAOSE */
8378 #define PNL_PINPUT(a) ((((unsigned char)(a)) ^ 0x7F) >> 3)
8479
@@ -120,40 +115,6 @@ · 35 unmodified lines
120115 #define PIN_SELECP 17
121116 #define PIN_NOT_SET 127
122117
123−#define LCD_FLAG_B 0x0004 /* blink on */
124−#define LCD_FLAG_C 0x0008 /* cursor on */
125−#define LCD_FLAG_D 0x0010 /* display on */
126−#define LCD_FLAG_F 0x0020 /* large font mode */
127−#define LCD_FLAG_N 0x0040 /* 2-rows mode */
128−#define LCD_FLAG_L 0x0080 /* backlight enabled */
129−
130−/* LCD commands */
131−#define LCD_CMD_DISPLAY_CLEAR 0x01 /* Clear entire display */
132−
133−#define LCD_CMD_ENTRY_MODE 0x04 /* Set entry mode */
134−#define LCD_CMD_CURSOR_INC 0x02 /* Increment cursor */
135−
136−#define LCD_CMD_DISPLAY_CTRL 0x08 /* Display control */
137−#define LCD_CMD_DISPLAY_ON 0x04 /* Set display on */
138−#define LCD_CMD_CURSOR_ON 0x02 /* Set cursor on */
139−#define LCD_CMD_BLINK_ON 0x01 /* Set blink on */
140−
141−#define LCD_CMD_SHIFT 0x10 /* Shift cursor/display */
142−#define LCD_CMD_DISPLAY_SHIFT 0x08 /* Shift display instead of cursor */
143−#define LCD_CMD_SHIFT_RIGHT 0x04 /* Shift display/cursor to the right */
144−
145−#define LCD_CMD_FUNCTION_SET 0x20 /* Set function */
146−#define LCD_CMD_DATA_LEN_8BITS 0x10 /* Set data length to 8 bits */
147−#define LCD_CMD_TWO_LINES 0x08 /* Set to two display lines */
148−#define LCD_CMD_FONT_5X10_DOTS 0x04 /* Set char font to 5x10 dots */
149−
150−#define LCD_CMD_SET_CGRAM_ADDR 0x40 /* Set char generator RAM address */
151−
152−#define LCD_CMD_SET_DDRAM_ADDR 0x80 /* Set display data RAM address */
153−
154−#define LCD_ESCAPE_LEN 24 /* max chars for LCD escape command */
155−#define LCD_ESCAPE_CHAR 27 /* use char 27 for escape command */
156−
157118 #define NOT_SET -1
158119
159120 /* macros to simplify use of the parallel port */
@@ -245,19 +206,10 @@ static wait_queue_head_t keypad_read_wait; · 85 unmodified lines
245206 static struct {
246207 bool enabled;
247208 bool initialized;
248− bool must_clear;
249209
250− int height;
251− int width;
252− int bwidth;
253− int hwidth;
254210 int charset;
255211 int proto;
256212
257− struct delayed_work bl_work;
258− struct mutex bl_tempo_lock; /* Protects access to bl_tempo */
259− bool bl_tempo;
260−
261213 /* TODO: use union here? */
262214 struct {
263215 int e;
@@ -268,20 +220,7 @@ static struct { · 4 unmodified lines
268220 int bl;
269221 } pins;
270222
271− /* contains the LCD config state */
272− unsigned long int flags;
273−
274− /* Contains the LCD X and Y offset */
275− struct {
276− unsigned long int x;
277− unsigned long int y;
278− } addr;
279−
280− /* Current escape sequence and it's length or -1 if outside */
281− struct {
282− char buf[LCD_ESCAPE_LEN + 1];
283− int len;
284− } esc_seq;
223+ struct charlcd *charlcd;
285224 } lcd;
286225
287226 /* Needed only for init */
@@ -464,17 +403,12 @@ static unsigned char lcd_bits[LCD_PORTS][LCD_BITS][BIT_STATES]; · 176 unmodified lines
464403 /* global variables */
465404
466405 /* Device single-open policy control */
467−static atomic_t lcd_available = ATOMIC_INIT(1);
468406 static atomic_t keypad_available = ATOMIC_INIT(1);
469407
470408 static struct pardevice *pprt;
471409
472410 static int keypad_initialized;
473411
474−static void (*lcd_write_cmd)(int);
475−static void (*lcd_write_data)(int);
476−static void (*lcd_clear_fast)(void);
477−
478412 static DEFINE_SPINLOCK(pprt_lock);
479413 static struct timer_list scan_timer;
480414
@@ -574,8 +508,6 @@ static int keypad_enabled = NOT_SET; · 93 unmodified lines
574508 module_param(keypad_enabled, int, 0000);
575509 MODULE_PARM_DESC(keypad_enabled, "Deprecated option, use keypad_type instead");
576510
577−static const unsigned char *lcd_char_conv;
578−
579511 /* for some LCD drivers (ks0074) we need a charset conversion table. */
580512 static const unsigned char lcd_char_conv_ks0074[256] = {
581513 /* 0|8 1|9 2|A 3|B 4|C 5|D 6|E 7|F */
@@ -752,15 +684,6 @@ static void pin_to_bits(int pin, unsigned char *d_val, unsigned char *c_val) · 170 unmodified lines
752684 }
753685 }
754686
755−/* sleeps that many milliseconds with a reschedule */
756−static void long_sleep(int ms)
757−{
758− if (in_interrupt())
759− mdelay(ms);
760− else
761− schedule_timeout_interruptible(msecs_to_jiffies(ms));
762−}
763−
764687 /*
765688 * send a serial byte to the LCD panel. The caller is responsible for locking
766689 * if needed.
@@ -792,8 +715,11 @@ static void lcd_send_serial(int byte) · 25 unmodified lines
792715 }
793716
794717 /* turn the backlight on or off */
795−static void __lcd_backlight(int on)
718+static void lcd_backlight(struct charlcd *charlcd, int on)
796719 {
720+ if (lcd.pins.bl == PIN_NONE)
721+ return;
722+
797723 /* The backlight is activated by setting the AUTOFEED line to +5V */
798724 spin_lock_irq(&pprt_lock);
799725 if (on)
@@ -804,46 +730,8 @@ static void __lcd_backlight(int on) · 4 unmodified lines
804730 spin_unlock_irq(&pprt_lock);
805731 }
806732
807−static void lcd_backlight(int on)
808−{
809− if (lcd.pins.bl == PIN_NONE)
810− return;
811−
812− mutex_lock(&lcd.bl_tempo_lock);
813− if (!lcd.bl_tempo)
814− __lcd_backlight(on);
815− mutex_unlock(&lcd.bl_tempo_lock);
816−}
817−
818−static void lcd_bl_off(struct work_struct *work)
819−{
820− mutex_lock(&lcd.bl_tempo_lock);
821− if (lcd.bl_tempo) {
822− lcd.bl_tempo = false;
823− if (!(lcd.flags & LCD_FLAG_L))
824− __lcd_backlight(0);
825− }
826− mutex_unlock(&lcd.bl_tempo_lock);
827−}
828−
829−/* turn the backlight on for a little while */
830−static void lcd_poke(void)
831−{
832− if (lcd.pins.bl == PIN_NONE)
833− return;
834−
835− cancel_delayed_work_sync(&lcd.bl_work);
836−
837− mutex_lock(&lcd.bl_tempo_lock);
838− if (!lcd.bl_tempo && !(lcd.flags & LCD_FLAG_L))
839− __lcd_backlight(1);
840− lcd.bl_tempo = true;
841− schedule_delayed_work(&lcd.bl_work, FLASH_LIGHT_TEMPO * HZ);
842− mutex_unlock(&lcd.bl_tempo_lock);
843−}
844−
845733 /* send a command to the LCD panel in serial mode */
846−static void lcd_write_cmd_s(int cmd)
734+static void lcd_write_cmd_s(struct charlcd *charlcd, int cmd)
847735 {
848736 spin_lock_irq(&pprt_lock);
849737 lcd_send_serial(0x1F); /* R/W=W, RS=0 */
@@ -854,7 +742,7 @@ static void lcd_write_cmd_s(int cmd) · 4 unmodified lines
854742 }
855743
856744 /* send data to the LCD panel in serial mode */
857−static void lcd_write_data_s(int data)
745+static void lcd_write_data_s(struct charlcd *charlcd, int data)
858746 {
859747 spin_lock_irq(&pprt_lock);
860748 lcd_send_serial(0x5F); /* R/W=W, RS=1 */
@@ -865,7 +753,7 @@ static void lcd_write_data_s(int data) · 4 unmodified lines
865753 }
866754
867755 /* send a command to the LCD panel in 8 bits parallel mode */
868−static void lcd_write_cmd_p8(int cmd)
756+static void lcd_write_cmd_p8(struct charlcd *charlcd, int cmd)
869757 {
870758 spin_lock_irq(&pprt_lock);
871759 /* present the data to the data port */
@@ -887,7 +775,7 @@ static void lcd_write_cmd_p8(int cmd) · 15 unmodified lines
887775 }
888776
889777 /* send data to the LCD panel in 8 bits parallel mode */
890−static void lcd_write_data_p8(int data)
778+static void lcd_write_data_p8(struct charlcd *charlcd, int data)
891779 {
892780 spin_lock_irq(&pprt_lock);
893781 /* present the data to the data port */
@@ -909,7 +797,7 @@ static void lcd_write_data_p8(int data) · 15 unmodified lines
909797 }
910798
911799 /* send a command to the TI LCD panel */
912−static void lcd_write_cmd_tilcd(int cmd)
800+static void lcd_write_cmd_tilcd(struct charlcd *charlcd, int cmd)
913801 {
914802 spin_lock_irq(&pprt_lock);
915803 /* present the data to the control port */
@@ -919,7 +807,7 @@ static void lcd_write_cmd_tilcd(int cmd) · 3 unmodified lines
919807 }
920808
921809 /* send data to the TI LCD panel */
922−static void lcd_write_data_tilcd(int data)
810+static void lcd_write_data_tilcd(struct charlcd *charlcd, int data)
923811 {
924812 spin_lock_irq(&pprt_lock);
925813 /* present the data to the data port */
@@ -928,47 +816,13 @@ static void lcd_write_data_tilcd(int data) · 2 unmodified lines
928816 spin_unlock_irq(&pprt_lock);
929817 }
930818
931−static void lcd_gotoxy(void)
932−{
933− lcd_write_cmd(LCD_CMD_SET_DDRAM_ADDR
934− | (lcd.addr.y ? lcd.hwidth : 0)
935− /*
936− * we force the cursor to stay at the end of the
937− * line if it wants to go farther
938− */
939− | ((lcd.addr.x < lcd.bwidth) ? lcd.addr.x &
940− (lcd.hwidth - 1) : lcd.bwidth - 1));
941−}
942−
943−static void lcd_home(void)
944−{
945− lcd.addr.x = 0;
946− lcd.addr.y = 0;
947− lcd_gotoxy();
948−}
949−
950−static void lcd_print(char c)
951−{
952− if (lcd.addr.x < lcd.bwidth) {
953− if (lcd_char_conv)
954− c = lcd_char_conv[(unsigned char)c];
955− lcd_write_data(c);
956− lcd.addr.x++;
957− }
958− /* prevents the cursor from wrapping onto the next line */
959− if (lcd.addr.x == lcd.bwidth)
960− lcd_gotoxy();
961−}
962−
963819 /* fills the display with spaces and resets X/Y */
964−static void lcd_clear_fast_s(void)
820+static void lcd_clear_fast_s(struct charlcd *charlcd)
965821 {
966822 int pos;
967823
968− lcd_home();
969−
970824 spin_lock_irq(&pprt_lock);
971− for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) {
825+ for (pos = 0; pos < charlcd->height * charlcd->hwidth; pos++) {
972826 lcd_send_serial(0x5F); /* R/W=W, RS=1 */
973827 lcd_send_serial(' ' & 0x0F);
974828 lcd_send_serial((' ' >> 4) & 0x0F);
@@ -976,19 +830,15 @@ static void lcd_clear_fast_s(void) · 1 unmodified line
976830 udelay(40);
977831 }
978832 spin_unlock_irq(&pprt_lock);
979−
980− lcd_home();
981833 }
982834
983835 /* fills the display with spaces and resets X/Y */
984−static void lcd_clear_fast_p8(void)
836+static void lcd_clear_fast_p8(struct charlcd *charlcd)
985837 {
986838 int pos;
987839
988− lcd_home();
989−
990840 spin_lock_irq(&pprt_lock);
991− for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) {
841+ for (pos = 0; pos < charlcd->height * charlcd->hwidth; pos++) {
992842 /* present the data to the data port */
993843 w_dtr(pprt, ' ');
994844
@@ -1010,488 +860,62 @@ static void lcd_clear_fast_p8(void) · 15 unmodified lines
1010860 udelay(45);
1011861 }
1012862 spin_unlock_irq(&pprt_lock);
1013−
1014− lcd_home();
1015863 }
1016864
1017865 /* fills the display with spaces and resets X/Y */
1018−static void lcd_clear_fast_tilcd(void)
866+static void lcd_clear_fast_tilcd(struct charlcd *charlcd)
1019867 {
1020868 int pos;
1021869
1022− lcd_home();
1023−
1024870 spin_lock_irq(&pprt_lock);
1025− for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) {
871+ for (pos = 0; pos < charlcd->height * charlcd->hwidth; pos++) {
1026872 /* present the data to the data port */
1027873 w_dtr(pprt, ' ');
1028874 udelay(60);
1029875 }
1030876
1031877 spin_unlock_irq(&pprt_lock);
1032−
1033− lcd_home();
1034−}
1035−
1036−/* clears the display and resets X/Y */
1037−static void lcd_clear_display(void)
1038−{
1039− lcd_write_cmd(LCD_CMD_DISPLAY_CLEAR);
1040− lcd.addr.x = 0;
1041− lcd.addr.y = 0;
1042− /* we must wait a few milliseconds (15) */
1043− long_sleep(15);
1044878 }
1045879
1046−static void lcd_init_display(void)
1047−{
1048− lcd.flags = ((lcd.height > 1) ? LCD_FLAG_N : 0)
1049− | LCD_FLAG_D | LCD_FLAG_C | LCD_FLAG_B;
1050−
1051− long_sleep(20); /* wait 20 ms after power-up for the paranoid */
1052−
1053− /* 8bits, 1 line, small fonts; let's do it 3 times */
1054− lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS);
1055− long_sleep(10);
1056− lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS);
1057− long_sleep(10);
1058− lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS);
1059− long_sleep(10);
1060−
1061− /* set font height and lines number */
1062− lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS
1063− | ((lcd.flags & LCD_FLAG_F) ? LCD_CMD_FONT_5X10_DOTS : 0)
1064− | ((lcd.flags & LCD_FLAG_N) ? LCD_CMD_TWO_LINES : 0)
1065− );
1066− long_sleep(10);
1067−
1068− /* display off, cursor off, blink off */
1069− lcd_write_cmd(LCD_CMD_DISPLAY_CTRL);
1070− long_sleep(10);
1071−
1072− lcd_write_cmd(LCD_CMD_DISPLAY_CTRL /* set display mode */
1073− | ((lcd.flags & LCD_FLAG_D) ? LCD_CMD_DISPLAY_ON : 0)
1074− | ((lcd.flags & LCD_FLAG_C) ? LCD_CMD_CURSOR_ON : 0)
1075− | ((lcd.flags & LCD_FLAG_B) ? LCD_CMD_BLINK_ON : 0)
1076− );
1077−
1078− lcd_backlight((lcd.flags & LCD_FLAG_L) ? 1 : 0);
1079−
1080− long_sleep(10);
1081−
1082− /* entry mode set : increment, cursor shifting */
1083− lcd_write_cmd(LCD_CMD_ENTRY_MODE | LCD_CMD_CURSOR_INC);
880+static struct charlcd_ops charlcd_serial_ops = {
881+ .write_cmd = lcd_write_cmd_s,
882+ .write_data = lcd_write_data_s,
883+ .clear_fast = lcd_clear_fast_s,
884+ .backlight = lcd_backlight,
885+};
1084886
1085− lcd_clear_display();
1086−}
887+static struct charlcd_ops charlcd_parallel_ops = {
888+ .write_cmd = lcd_write_cmd_p8,
889+ .write_data = lcd_write_data_p8,
890+ .clear_fast = lcd_clear_fast_p8,
891+ .backlight = lcd_backlight,
892+};
1087893
1088−/*
1089− * These are the file operation function for user access to /dev/lcd
1090− * This function can also be called from inside the kernel, by
1091− * setting file and ppos to NULL.
1092− *
1093− */
894+static struct charlcd_ops charlcd_tilcd_ops = {
895+ .write_cmd = lcd_write_cmd_tilcd,
896+ .write_data = lcd_write_data_tilcd,
897+ .clear_fast = lcd_clear_fast_tilcd,
898+ .backlight = lcd_backlight,
899+};
1094900
1095−static inline int handle_lcd_special_code(void)
901+/* initialize the LCD driver */
902+static void lcd_init(void)
1096903 {
1097− /* LCD special codes */
1098−
1099− int processed = 0;
904+ struct charlcd *charlcd;
1100905
1101− char *esc = lcd.esc_seq.buf + 2;
1102− int oldflags = lcd.flags;
1103−
1104− /* check for display mode flags */
1105− switch (*esc) {
1106− case 'D': /* Display ON */
1107− lcd.flags |= LCD_FLAG_D;
1108− processed = 1;
1109− break;
1110− case 'd': /* Display OFF */
1111− lcd.flags &= ~LCD_FLAG_D;
1112− processed = 1;
1113− break;
1114− case 'C': /* Cursor ON */
1115− lcd.flags |= LCD_FLAG_C;
1116− processed = 1;
1117− break;
1118− case 'c': /* Cursor OFF */
1119− lcd.flags &= ~LCD_FLAG_C;
1120− processed = 1;
1121− break;
1122− case 'B': /* Blink ON */
1123− lcd.flags |= LCD_FLAG_B;
1124− processed = 1;
1125− break;
1126− case 'b': /* Blink OFF */
1127− lcd.flags &= ~LCD_FLAG_B;
1128− processed = 1;
1129− break;
1130− case '+': /* Back light ON */
1131− lcd.flags |= LCD_FLAG_L;
1132− processed = 1;
1133− break;
1134− case '-': /* Back light OFF */
1135− lcd.flags &= ~LCD_FLAG_L;
1136− processed = 1;
1137− break;
1138− case '*':
1139− /* flash back light */
1140− lcd_poke();
1141− processed = 1;
1142− break;
1143− case 'f': /* Small Font */
1144− lcd.flags &= ~LCD_FLAG_F;
1145− processed = 1;
1146− break;
1147− case 'F': /* Large Font */
1148− lcd.flags |= LCD_FLAG_F;
1149− processed = 1;
1150− break;
1151− case 'n': /* One Line */
1152− lcd.flags &= ~LCD_FLAG_N;
1153− processed = 1;
1154− break;
1155− case 'N': /* Two Lines */
1156− lcd.flags |= LCD_FLAG_N;
1157− break;
1158− case 'l': /* Shift Cursor Left */
1159− if (lcd.addr.x > 0) {
1160− /* back one char if not at end of line */
1161− if (lcd.addr.x < lcd.bwidth)
1162− lcd_write_cmd(LCD_CMD_SHIFT);
1163− lcd.addr.x--;
1164− }
1165− processed = 1;
1166− break;
1167− case 'r': /* shift cursor right */
1168− if (lcd.addr.x < lcd.width) {
1169− /* allow the cursor to pass the end of the line */
1170− if (lcd.addr.x < (lcd.bwidth - 1))
1171− lcd_write_cmd(LCD_CMD_SHIFT |
1172− LCD_CMD_SHIFT_RIGHT);
1173− lcd.addr.x++;
1174− }
1175− processed = 1;
1176− break;
1177− case 'L': /* shift display left */
1178− lcd_write_cmd(LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT);
1179− processed = 1;
1180− break;
1181− case 'R': /* shift display right */
1182− lcd_write_cmd(LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT |
1183− LCD_CMD_SHIFT_RIGHT);
1184− processed = 1;
1185− break;
1186− case 'k': { /* kill end of line */
1187− int x;
1188−
1189− for (x = lcd.addr.x; x < lcd.bwidth; x++)
1190− lcd_write_data(' ');
1191−
1192− /* restore cursor position */
1193− lcd_gotoxy();
1194− processed = 1;
1195− break;
1196− }
1197− case 'I': /* reinitialize display */
1198− lcd_init_display();
1199− processed = 1;
1200− break;
1201− case 'G': {
1202− /* Generator : LGcxxxxx...xx; must have <c> between '0'
1203− * and '7', representing the numerical ASCII code of the
1204− * redefined character, and <xx...xx> a sequence of 16
1205− * hex digits representing 8 bytes for each character.
1206− * Most LCDs will only use 5 lower bits of the 7 first
1207− * bytes.
1208− */
1209−
1210− unsigned char cgbytes[8];
1211− unsigned char cgaddr;
1212− int cgoffset;
1213− int shift;
1214− char value;
1215− int addr;
1216−
1217− if (!strchr(esc, ';'))
1218− break;
1219−
1220− esc++;
1221−
1222− cgaddr = *(esc++) - '0';
1223− if (cgaddr > 7) {
1224− processed = 1;
1225− break;
1226− }
1227−
1228− cgoffset = 0;
1229− shift = 0;
1230− value = 0;
1231− while (*esc && cgoffset < 8) {
1232− shift ^= 4;
1233− if (*esc >= '0' && *esc <= '9') {
1234− value |= (*esc - '0') << shift;
1235− } else if (*esc >= 'A' && *esc <= 'Z') {
1236− value |= (*esc - 'A' + 10) << shift;
1237− } else if (*esc >= 'a' && *esc <= 'z') {
1238− value |= (*esc - 'a' + 10) << shift;
1239− } else {
1240− esc++;
1241− continue;
1242− }
1243−
1244− if (shift == 0) {
1245− cgbytes[cgoffset++] = value;
1246− value = 0;
1247− }
1248−
1249− esc++;
1250− }
1251−
1252− lcd_write_cmd(LCD_CMD_SET_CGRAM_ADDR | (cgaddr * 8));
1253− for (addr = 0; addr < cgoffset; addr++)
1254− lcd_write_data(cgbytes[addr]);
1255−
1256− /* ensures that we stop writing to CGRAM */
1257− lcd_gotoxy();
1258− processed = 1;
1259− break;
1260− }
1261− case 'x': /* gotoxy : LxXXX[yYYY]; */
1262− case 'y': /* gotoxy : LyYYY[xXXX]; */
1263− if (!strchr(esc, ';'))
1264− break;
1265−
1266− while (*esc) {
1267− if (*esc == 'x') {
1268− esc++;
1269− if (kstrtoul(esc, 10, &lcd.addr.x) < 0)
1270− break;
1271− } else if (*esc == 'y') {
1272− esc++;
1273− if (kstrtoul(esc, 10, &lcd.addr.y) < 0)
1274− break;
1275− } else {
1276− break;
1277− }
1278− }
1279−
1280− lcd_gotoxy();
1281− processed = 1;
1282− break;
1283− }
1284−
1285− /* TODO: This indent party here got ugly, clean it! */
1286− /* Check whether one flag was changed */
1287− if (oldflags != lcd.flags) {
1288− /* check whether one of B,C,D flags were changed */
1289− if ((oldflags ^ lcd.flags) &
1290− (LCD_FLAG_B | LCD_FLAG_C | LCD_FLAG_D))
1291− /* set display mode */
1292− lcd_write_cmd(LCD_CMD_DISPLAY_CTRL
1293− | ((lcd.flags & LCD_FLAG_D)
1294− ? LCD_CMD_DISPLAY_ON : 0)
1295− | ((lcd.flags & LCD_FLAG_C)
1296− ? LCD_CMD_CURSOR_ON : 0)
1297− | ((lcd.flags & LCD_FLAG_B)
1298− ? LCD_CMD_BLINK_ON : 0));
1299− /* check whether one of F,N flags was changed */
1300− else if ((oldflags ^ lcd.flags) & (LCD_FLAG_F | LCD_FLAG_N))
1301− lcd_write_cmd(LCD_CMD_FUNCTION_SET
1302− | LCD_CMD_DATA_LEN_8BITS
1303− | ((lcd.flags & LCD_FLAG_F)
1304− ? LCD_CMD_FONT_5X10_DOTS
1305− : 0)
1306− | ((lcd.flags & LCD_FLAG_N)
1307− ? LCD_CMD_TWO_LINES
1308− : 0));
1309− /* check whether L flag was changed */
1310− else if ((oldflags ^ lcd.flags) & (LCD_FLAG_L))
1311− lcd_backlight(!!(lcd.flags & LCD_FLAG_L));
1312− }
1313−
1314− return processed;
1315−}
1316−
1317−static void lcd_write_char(char c)
1318−{
1319− /* first, we'll test if we're in escape mode */
1320− if ((c != '\n') && lcd.esc_seq.len >= 0) {
1321− /* yes, let's add this char to the buffer */
1322− lcd.esc_seq.buf[lcd.esc_seq.len++] = c;
1323− lcd.esc_seq.buf[lcd.esc_seq.len] = 0;
1324− } else {
1325− /* aborts any previous escape sequence */
1326− lcd.esc_seq.len = -1;
1327−
1328− switch (c) {
1329− case LCD_ESCAPE_CHAR:
1330− /* start of an escape sequence */
1331− lcd.esc_seq.len = 0;
1332− lcd.esc_seq.buf[lcd.esc_seq.len] = 0;
1333− break;
1334− case '\b':
1335− /* go back one char and clear it */
1336− if (lcd.addr.x > 0) {
1337− /*
1338− * check if we're not at the
1339− * end of the line
1340− */
1341− if (lcd.addr.x < lcd.bwidth)
1342− /* back one char */
1343− lcd_write_cmd(LCD_CMD_SHIFT);
1344− lcd.addr.x--;
1345− }
1346− /* replace with a space */
1347− lcd_write_data(' ');
1348− /* back one char again */
1349− lcd_write_cmd(LCD_CMD_SHIFT);
1350− break;
1351− case '\014':
1352− /* quickly clear the display */
1353− lcd_clear_fast();
1354− break;
1355− case '\n':
1356− /*
1357− * flush the remainder of the current line and
1358− * go to the beginning of the next line
1359− */
1360− for (; lcd.addr.x < lcd.bwidth; lcd.addr.x++)
1361− lcd_write_data(' ');
1362− lcd.addr.x = 0;
1363− lcd.addr.y = (lcd.addr.y + 1) % lcd.height;
1364− lcd_gotoxy();
1365− break;
1366− case '\r':
1367− /* go to the beginning of the same line */
1368− lcd.addr.x = 0;
1369− lcd_gotoxy();
1370− break;
1371− case '\t':
1372− /* print a space instead of the tab */
1373− lcd_print(' ');
1374− break;
1375− default:
1376− /* simply print this char */
1377− lcd_print(c);
1378− break;
1379− }
1380− }
906+ charlcd = charlcd_alloc(0);
907+ if (!charlcd)
908+ return;
1381909
1382910 /*
1383− * now we'll see if we're in an escape mode and if the current
1384− * escape sequence can be understood.
911+ * Init lcd struct with load-time values to preserve exact
912+ * current functionality (at least for now).
1385913 */
1386− if (lcd.esc_seq.len >= 2) {
1387− int processed = 0;
1388−
1389− if (!strcmp(lcd.esc_seq.buf, "[2J")) {
1390− /* clear the display */
1391− lcd_clear_fast();
1392− processed = 1;
1393− } else if (!strcmp(lcd.esc_seq.buf, "[H")) {
1394− /* cursor to home */
1395− lcd_home();
1396− processed = 1;
1397− }
1398− /* codes starting with ^[[L */
1399− else if ((lcd.esc_seq.len >= 3) &&
1400− (lcd.esc_seq.buf[0] == '[') &&
1401− (lcd.esc_seq.buf[1] == 'L')) {
1402− processed = handle_lcd_special_code();
1403− }
1404−
1405− /* LCD special escape codes */
1406− /*
1407− * flush the escape sequence if it's been processed
1408− * or if it is getting too long.
1409− */
1410− if (processed || (lcd.esc_seq.len >= LCD_ESCAPE_LEN))
1411− lcd.esc_seq.len = -1;
1412− } /* escape codes */
1413−}
914+ charlcd->height = lcd_height;
915+ charlcd->width = lcd_width;
916+ charlcd->bwidth = lcd_bwidth;
917+ charlcd->hwidth = lcd_hwidth;
1414918
1415−static ssize_t lcd_write(struct file *file,
1416− const char __user *buf, size_t count, loff_t *ppos)
1417−{
1418− const char __user *tmp = buf;
1419− char c;
1420−
1421− for (; count-- > 0; (*ppos)++, tmp++) {
1422− if (!in_interrupt() && (((count + 1) & 0x1f) == 0))
1423− /*
1424− * let's be a little nice with other processes
1425− * that need some CPU
1426− */
1427− schedule();
1428−
1429− if (get_user(c, tmp))
1430− return -EFAULT;
1431−
1432− lcd_write_char(c);
1433− }
1434−
1435− return tmp - buf;
1436−}
1437−
1438−static int lcd_open(struct inode *inode, struct file *file)
1439−{
1440− if (!atomic_dec_and_test(&lcd_available))
1441− return -EBUSY; /* open only once at a time */
1442−
1443− if (file->f_mode & FMODE_READ) /* device is write-only */
1444− return -EPERM;
1445−
1446− if (lcd.must_clear) {
1447− lcd_clear_display();
1448− lcd.must_clear = false;
1449− }
1450− return nonseekable_open(inode, file);
1451−}
1452−
1453−static int lcd_release(struct inode *inode, struct file *file)
1454−{
1455− atomic_inc(&lcd_available);
1456− return 0;
1457−}
1458−
1459−static const struct file_operations lcd_fops = {
1460− .write = lcd_write,
1461− .open = lcd_open,
1462− .release = lcd_release,
1463− .llseek = no_llseek,
1464−};
1465−
1466−static struct miscdevice lcd_dev = {
1467− .minor = LCD_MINOR,
1468− .name = "lcd",
1469− .fops = &lcd_fops,
1470−};
1471−
1472−/* public function usable from the kernel for any purpose */
1473−static void panel_lcd_print(const char *s)
1474−{
1475− const char *tmp = s;
1476− int count = strlen(s);
1477−
1478− if (lcd.enabled && lcd.initialized) {
1479− for (; count-- > 0; tmp++) {
1480− if (!in_interrupt() && (((count + 1) & 0x1f) == 0))
1481− /*
1482− * let's be a little nice with other processes
1483− * that need some CPU
1484− */
1485− schedule();
1486−
1487− lcd_write_char(*tmp);
1488− }
1489− }
1490−}
1491−
1492−/* initialize the LCD driver */
1493−static void lcd_init(void)
1494−{
1495919 switch (selected_lcd_type) {
1496920 case LCD_TYPE_OLD:
1497921 /* parallel mode, 8 bits */
@@ -1500,10 +924,10 @@ static void lcd_init(void) · 2 unmodified lines
1500924 lcd.pins.e = PIN_STROBE;
1501925 lcd.pins.rs = PIN_AUTOLF;
1502926
1503− lcd.width = 40;
1504− lcd.bwidth = 40;
1505− lcd.hwidth = 64;
1506− lcd.height = 2;
927+ charlcd->width = 40;
928+ charlcd->bwidth = 40;
929+ charlcd->hwidth = 64;
930+ charlcd->height = 2;
1507931 break;
1508932 case LCD_TYPE_KS0074:
1509933 /* serial mode, ks0074 */
@@ -1513,10 +937,10 @@ static void lcd_init(void) · 3 unmodified lines
1513937 lcd.pins.cl = PIN_STROBE;
1514938 lcd.pins.da = PIN_D0;
1515939
1516− lcd.width = 16;
1517− lcd.bwidth = 40;
1518− lcd.hwidth = 16;
1519− lcd.height = 2;
940+ charlcd->width = 16;
941+ charlcd->bwidth = 40;
942+ charlcd->hwidth = 16;
943+ charlcd->height = 2;
1520944 break;
1521945 case LCD_TYPE_NEXCOM:
1522946 /* parallel mode, 8 bits, generic */
@@ -1526,10 +950,10 @@ static void lcd_init(void) · 3 unmodified lines
1526950 lcd.pins.rs = PIN_SELECP;
1527951 lcd.pins.rw = PIN_INITP;
1528952
1529− lcd.width = 16;
1530− lcd.bwidth = 40;
1531− lcd.hwidth = 64;
1532− lcd.height = 2;
953+ charlcd->width = 16;
954+ charlcd->bwidth = 40;
955+ charlcd->hwidth = 64;
956+ charlcd->height = 2;
1533957 break;
1534958 case LCD_TYPE_CUSTOM:
1535959 /* customer-defined */
@@ -1545,22 +969,22 @@ static void lcd_init(void) · 9 unmodified lines
1545969 lcd.pins.e = PIN_STROBE;
1546970 lcd.pins.rs = PIN_SELECP;
1547971
1548− lcd.width = 16;
1549− lcd.bwidth = 40;
1550− lcd.hwidth = 64;
1551− lcd.height = 2;
972+ charlcd->width = 16;
973+ charlcd->bwidth = 40;
974+ charlcd->hwidth = 64;
975+ charlcd->height = 2;
1552976 break;
1553977 }
1554978
1555979 /* Overwrite with module params set on loading */
1556980 if (lcd_height != NOT_SET)
1557− lcd.height = lcd_height;
981+ charlcd->height = lcd_height;
1558982 if (lcd_width != NOT_SET)
1559− lcd.width = lcd_width;
983+ charlcd->width = lcd_width;
1560984 if (lcd_bwidth != NOT_SET)
1561− lcd.bwidth = lcd_bwidth;
985+ charlcd->bwidth = lcd_bwidth;
1562986 if (lcd_hwidth != NOT_SET)
1563− lcd.hwidth = lcd_hwidth;
987+ charlcd->hwidth = lcd_hwidth;
1564988 if (lcd_charset != NOT_SET)
1565989 lcd.charset = lcd_charset;
1566990 if (lcd_proto != NOT_SET)
@@ -1579,19 +1003,17 @@ static void lcd_init(void) · 12 unmodified lines
15791003 lcd.pins.bl = lcd_bl_pin;
15801004
15811005 /* this is used to catch wrong and default values */
1582− if (lcd.width <= 0)
1583− lcd.width = DEFAULT_LCD_WIDTH;
1584− if (lcd.bwidth <= 0)
1585− lcd.bwidth = DEFAULT_LCD_BWIDTH;
1586− if (lcd.hwidth <= 0)
1587− lcd.hwidth = DEFAULT_LCD_HWIDTH;
1588− if (lcd.height <= 0)
1589− lcd.height = DEFAULT_LCD_HEIGHT;
1006+ if (charlcd->width <= 0)
1007+ charlcd->width = DEFAULT_LCD_WIDTH;
1008+ if (charlcd->bwidth <= 0)
1009+ charlcd->bwidth = DEFAULT_LCD_BWIDTH;
1010+ if (charlcd->hwidth <= 0)
1011+ charlcd->hwidth = DEFAULT_LCD_HWIDTH;
1012+ if (charlcd->height <= 0)
1013+ charlcd->height = DEFAULT_LCD_HEIGHT;
15901014
15911015 if (lcd.proto == LCD_PROTO_SERIAL) { /* SERIAL */
1592− lcd_write_cmd = lcd_write_cmd_s;
1593− lcd_write_data = lcd_write_data_s;
1594− lcd_clear_fast = lcd_clear_fast_s;
1016+ charlcd->ops = &charlcd_serial_ops;
15951017
15961018 if (lcd.pins.cl == PIN_NOT_SET)
15971019 lcd.pins.cl = DEFAULT_LCD_PIN_SCL;
@@ -1599,9 +1021,7 @@ static void lcd_init(void) · 1 unmodified line
15991021 lcd.pins.da = DEFAULT_LCD_PIN_SDA;
16001022
16011023 } else if (lcd.proto == LCD_PROTO_PARALLEL) { /* PARALLEL */
1602− lcd_write_cmd = lcd_write_cmd_p8;
1603− lcd_write_data = lcd_write_data_p8;
1604− lcd_clear_fast = lcd_clear_fast_p8;
1024+ charlcd->ops = &charlcd_parallel_ops;
16051025
16061026 if (lcd.pins.e == PIN_NOT_SET)
16071027 lcd.pins.e = DEFAULT_LCD_PIN_E;
@@ -1610,9 +1030,7 @@ static void lcd_init(void) · 2 unmodified lines
16101030 if (lcd.pins.rw == PIN_NOT_SET)
16111031 lcd.pins.rw = DEFAULT_LCD_PIN_RW;
16121032 } else {
1613− lcd_write_cmd = lcd_write_cmd_tilcd;
1614− lcd_write_data = lcd_write_data_tilcd;
1615− lcd_clear_fast = lcd_clear_fast_tilcd;
1033+ charlcd->ops = &charlcd_tilcd_ops;
16161034 }
16171035
16181036 if (lcd.pins.bl == PIN_NOT_SET)
@@ -1635,14 +1053,9 @@ static void lcd_init(void) · 16 unmodified lines
16351053 lcd.charset = DEFAULT_LCD_CHARSET;
16361054
16371055 if (lcd.charset == LCD_CHARSET_KS0074)
1638− lcd_char_conv = lcd_char_conv_ks0074;
1056+ charlcd->char_conv = lcd_char_conv_ks0074;
16391057 else
1640− lcd_char_conv = NULL;
1641−
1642− if (lcd.pins.bl != PIN_NONE) {
1643− mutex_init(&lcd.bl_tempo_lock);
1644− INIT_DELAYED_WORK(&lcd.bl_work, lcd_bl_off);
1645− }
1058+ charlcd->char_conv = NULL;
16461059
16471060 pin_to_bits(lcd.pins.e, lcd_bits[LCD_PORT_D][LCD_BIT_E],
16481061 lcd_bits[LCD_PORT_C][LCD_BIT_E]);
@@ -1657,25 +1070,8 @@ static void lcd_init(void) · 8 unmodified lines
16571070 pin_to_bits(lcd.pins.da, lcd_bits[LCD_PORT_D][LCD_BIT_DA],
16581071 lcd_bits[LCD_PORT_C][LCD_BIT_DA]);
16591072
1660− /*
1661− * before this line, we must NOT send anything to the display.
1662− * Since lcd_init_display() needs to write data, we have to
1663− * enable mark the LCD initialized just before.
1664− */
1073+ lcd.charlcd = charlcd;
16651074 lcd.initialized = true;
1666− lcd_init_display();
1667−
1668− /* display a short message */
1669−#ifdef CONFIG_PANEL_CHANGE_MESSAGE
1670−#ifdef CONFIG_PANEL_BOOT_MESSAGE
1671− panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*" CONFIG_PANEL_BOOT_MESSAGE);
1672−#endif
1673−#else
1674− panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*Linux-" UTS_RELEASE);
1675−#endif
1676− /* clear the display on the next device opening */
1677− lcd.must_clear = true;
1678− lcd_home();
16791075 }
16801076
16811077 /*
@@ -2011,7 +1407,7 @@ static void panel_scan_timer(void) · 329 unmodified lines
20111407 }
20121408
20131409 if (keypressed && lcd.enabled && lcd.initialized)
2014− lcd_poke();
1410+ charlcd_poke(lcd.charlcd);
20151411
20161412 mod_timer(&scan_timer, jiffies + INPUT_POLL_TIME);
20171413 }
@@ -2175,35 +1571,6 @@ static void keypad_init(void) · 157 unmodified lines
21751571 /* device initialization */
21761572 /**************************************************/
21771573
2178−static int panel_notify_sys(struct notifier_block *this, unsigned long code,
2179− void *unused)
2180−{
2181− if (lcd.enabled && lcd.initialized) {
2182− switch (code) {
2183− case SYS_DOWN:
2184− panel_lcd_print
2185− ("\x0cReloading\nSystem...\x1b[Lc\x1b[Lb\x1b[L+");
2186− break;
2187− case SYS_HALT:
2188− panel_lcd_print
2189− ("\x0cSystem Halted.\x1b[Lc\x1b[Lb\x1b[L+");
2190− break;
2191− case SYS_POWER_OFF:
2192− panel_lcd_print("\x0cPower off.\x1b[Lc\x1b[Lb\x1b[L+");
2193− break;
2194− default:
2195− break;
2196− }
2197− }
2198− return NOTIFY_DONE;
2199−}
2200−
2201−static struct notifier_block panel_notifier = {
2202− panel_notify_sys,
2203− NULL,
2204− 0
2205−};
2206−
22071574 static void panel_attach(struct parport *port)
22081575 {
22091576 struct pardev_cb panel_cb;
@@ -2239,7 +1606,7 @@ static void panel_attach(struct parport *port) · 29 unmodified lines
22391606 */
22401607 if (lcd.enabled) {
22411608 lcd_init();
2242− if (misc_register(&lcd_dev))
1609+ if (!lcd.charlcd || charlcd_register(lcd.charlcd))
22431610 goto err_unreg_device;
22441611 }
22451612
@@ -2248,13 +1615,14 @@ static void panel_attach(struct parport *port) · 2 unmodified lines
22481615 if (misc_register(&keypad_dev))
22491616 goto err_lcd_unreg;
22501617 }
2251− register_reboot_notifier(&panel_notifier);
22521618 return;
22531619
22541620 err_lcd_unreg:
22551621 if (lcd.enabled)
2256− misc_deregister(&lcd_dev);
1622+ charlcd_unregister(lcd.charlcd);
22571623 err_unreg_device:
1624+ kfree(lcd.charlcd);
1625+ lcd.charlcd = NULL;
22581626 parport_unregister_device(pprt);
22591627 pprt = NULL;
22601628 }
@@ -2278,20 +1646,16 @@ static void panel_detach(struct parport *port) · 17 unmodified lines
22781646 }
22791647
22801648 if (lcd.enabled) {
2281− panel_lcd_print("\x0cLCD driver unloaded.\x1b[Lc\x1b[Lb\x1b[L-");
2282− misc_deregister(&lcd_dev);
2283− if (lcd.pins.bl != PIN_NONE) {
2284− cancel_delayed_work_sync(&lcd.bl_work);
2285− __lcd_backlight(0);
2286− }
1649+ charlcd_unregister(lcd.charlcd);
22871650 lcd.initialized = false;
1651+ kfree(lcd.charlcd);
1652+ lcd.charlcd = NULL;
22881653 }
22891654
22901655 /* TODO: free all input signals */
22911656 parport_release(pprt);
22921657 parport_unregister_device(pprt);
22931658 pprt = NULL;
2294− unregister_reboot_notifier(&panel_notifier);
22951659 }
22961660
22971661 static struct parport_driver panel_driver = {
@@ -2369,10 +1733,6 @@ static int __init panel_init_module(void) · 71 unmodified lines
23691733 * Init lcd struct with load-time values to preserve exact
23701734 * current functionality (at least for now).
23711735 */
2372− lcd.height = lcd_height;
2373− lcd.width = lcd_width;
2374− lcd.bwidth = lcd_bwidth;
2375− lcd.hwidth = lcd_hwidth;
23761736 lcd.charset = lcd_charset;
23771737 lcd.proto = lcd_proto;
23781738 lcd.pins.e = lcd_e_pin;
@@ -2381,9 +1741,6 @@ static int __init panel_init_module(void) · 2 unmodified lines
23811741 lcd.pins.cl = lcd_cl_pin;
23821742 lcd.pins.da = lcd_da_pin;
23831743 lcd.pins.bl = lcd_bl_pin;
2384−
2385− /* Leave it for now, just in case */
2386− lcd.esc_seq.len = -1;
23871744 }
23881745
23891746 switch (selected_keypad_type) {
include/misc/charlcd.h+40−0
@@ -0,0 +1,40 @@
1+/*
2+ * Character LCD driver for Linux
3+ *
4+ * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu>
5+ * Copyright (C) 2016-2017 Glider bvba
6+ *
7+ * This program is free software; you can redistribute it and/or
8+ * modify it under the terms of the GNU General Public License
9+ * as published by the Free Software Foundation; either version
10+ * 2 of the License, or (at your option) any later version.
11+ */
12+
13+struct charlcd {
14+ const struct charlcd_ops *ops;
15+ const unsigned char *char_conv; /* Optional */
16+
17+ int height;
18+ int width;
19+ int bwidth; /* Default set by charlcd_alloc() */
20+ int hwidth; /* Default set by charlcd_alloc() */
21+
22+ void *drvdata; /* Set by charlcd_alloc() */
23+};
24+
25+struct charlcd_ops {
26+ /* Required */
27+ void (*write_cmd)(struct charlcd *lcd, int cmd);
28+ void (*write_data)(struct charlcd *lcd, int data);
29+
30+ /* Optional */
31+ void (*clear_fast)(struct charlcd *lcd);
32+ void (*backlight)(struct charlcd *lcd, int on);
33+};
34+
35+struct charlcd *charlcd_alloc(unsigned int drvdata_size);
36+
37+int charlcd_register(struct charlcd *lcd);
38+int charlcd_unregister(struct charlcd *lcd);
39+
40+void charlcd_poke(struct charlcd *lcd);