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
13 13
14 If you say N, all options in this submenu will be skipped and disabled.14 If you say N, all options in this submenu will be skipped and disabled.
15 15
16config CHARLCD
17 tristate "Character LCD core support" if COMPILE_TEST
18
16if AUXDISPLAY19if AUXDISPLAY
17 20
18config KS010821config KS0108
drivers/auxdisplay/Makefile+1−0
@@ -2,6 +2,7 @@ · 1 unmodified line
2# Makefile for the kernel auxiliary displays device drivers.2# Makefile for the kernel auxiliary displays device drivers.
3#3#
4 4
5obj-$(CONFIG_CHARLCD) += charlcd.o
5obj-$(CONFIG_KS0108) += ks0108.o6obj-$(CONFIG_KS0108) += ks0108.o
6obj-$(CONFIG_CFAG12864B) += cfag12864b.o cfag12864bfb.o7obj-$(CONFIG_CFAG12864B) += cfag12864b.o cfag12864bfb.o
7obj-$(CONFIG_IMG_ASCII_LCD) += img-ascii-lcd.o8obj-$(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
70struct 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 */
100static atomic_t charlcd_available = ATOMIC_INIT(1);
101
102/* sleeps that many milliseconds with a reschedule */
103static 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 */
112static 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
125static 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 */
141void 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}
157EXPORT_SYMBOL_GPL(charlcd_poke);
158
159static 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
173static 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
182static 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
197static 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 */
213static 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
224static 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
276static 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
495static 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
595static struct charlcd *the_charlcd;
596
597static 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
620static 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
637static int charlcd_release(struct inode *inode, struct file *file)
638{
639 atomic_inc(&charlcd_available);
640 return 0;
641}
642
643static const struct file_operations charlcd_fops = {
644 .write = charlcd_write,
645 .open = charlcd_open,
646 .release = charlcd_release,
647 .llseek = no_llseek,
648};
649
650static struct miscdevice charlcd_dev = {
651 .minor = LCD_MINOR,
652 .name = "lcd",
653 .fops = &charlcd_fops,
654};
655
656static 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 */
674static 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
707struct 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}
725EXPORT_SYMBOL_GPL(charlcd_alloc);
726
727static 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
749static struct notifier_block panel_notifier = {
750 panel_notify_sys,
751 NULL,
752 0
753};
754
755int 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}
771EXPORT_SYMBOL_GPL(charlcd_register);
772
773int 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}
788EXPORT_SYMBOL_GPL(charlcd_unregister);
789
790MODULE_LICENSE("GPL");
drivers/misc/Kconfig+1−0
@@ -495,6 +495,7 @@ config VEXPRESS_SYSCFG · 494 unmodified lines
495config PANEL495config PANEL
496 tristate "Parallel port LCD/Keypad Panel support"496 tristate "Parallel port LCD/Keypad Panel support"
497 depends on PARPORT497 depends on PARPORT
498 select CHARLCD
498 ---help---499 ---help---
499 Say Y here if you have an HD44780 or KS-0074 LCD connected to your500 Say Y here if you have an HD44780 or KS-0074 LCD connected to your
500 parallel port. This driver also features 4 and 6-key keypads. The LCD501 parallel port. This driver also features 4 and 6-key keypads. The LCD
drivers/misc/panel.c+92−735
@@ -1,6 +1,7 @@
1/*1/*
2 * Front panel driver for Linux2 * Front panel driver for Linux
3 * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu>3 * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu>
4 * Copyright (C) 2016-2017 Glider bvba
4 *5 *
5 * This program is free software; you can redistribute it and/or6 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License7 * modify it under the terms of the GNU General Public License
@@ -54,15 +55,12 @@ · 47 unmodified lines
54#include <linux/ctype.h>55#include <linux/ctype.h>
55#include <linux/parport.h>56#include <linux/parport.h>
56#include <linux/list.h>57#include <linux/list.h>
57#include <linux/notifier.h>
58#include <linux/reboot.h>
59#include <linux/workqueue.h>
60#include <generated/utsrelease.h>
61 58
62#include <linux/io.h>59#include <linux/io.h>
63#include <linux/uaccess.h>60#include <linux/uaccess.h>
64 61
65#define LCD_MINOR 15662#include <misc/charlcd.h>
63
66#define KEYPAD_MINOR 18564#define KEYPAD_MINOR 185
67 65
68#define LCD_MAXBYTES 256 /* max burst write */66#define LCD_MAXBYTES 256 /* max burst write */
@@ -76,9 +74,6 @@ · 7 unmodified lines
76/* a key repeats this times INPUT_POLL_TIME */74/* a key repeats this times INPUT_POLL_TIME */
77#define KEYPAD_REP_DELAY (2)75#define KEYPAD_REP_DELAY (2)
78 76
79/* keep the light on this many seconds for each flash */
80#define FLASH_LIGHT_TEMPO (4)
81
82/* converts an r_str() input to an active high, bits string : 000BAOSE */77/* converts an r_str() input to an active high, bits string : 000BAOSE */
83#define PNL_PINPUT(a) ((((unsigned char)(a)) ^ 0x7F) >> 3)78#define PNL_PINPUT(a) ((((unsigned char)(a)) ^ 0x7F) >> 3)
84 79
@@ -120,40 +115,6 @@ · 35 unmodified lines
120#define PIN_SELECP 17115#define PIN_SELECP 17
121#define PIN_NOT_SET 127116#define PIN_NOT_SET 127
122 117
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
157#define NOT_SET -1118#define NOT_SET -1
158 119
159/* macros to simplify use of the parallel port */120/* macros to simplify use of the parallel port */
@@ -245,19 +206,10 @@ static wait_queue_head_t keypad_read_wait; · 85 unmodified lines
245static struct {206static struct {
246 bool enabled;207 bool enabled;
247 bool initialized;208 bool initialized;
248 bool must_clear;
249 209
250 int height;
251 int width;
252 int bwidth;
253 int hwidth;
254 int charset;210 int charset;
255 int proto;211 int proto;
256 212
257 struct delayed_work bl_work;
258 struct mutex bl_tempo_lock; /* Protects access to bl_tempo */
259 bool bl_tempo;
260
261 /* TODO: use union here? */213 /* TODO: use union here? */
262 struct {214 struct {
263 int e;215 int e;
@@ -268,20 +220,7 @@ static struct { · 4 unmodified lines
268 int bl;220 int bl;
269 } pins;221 } pins;
270 222
271 /* contains the LCD config state */223 struct charlcd *charlcd;
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;
285} lcd;224} lcd;
286 225
287/* Needed only for init */226/* Needed only for init */
@@ -464,17 +403,12 @@ static unsigned char lcd_bits[LCD_PORTS][LCD_BITS][BIT_STATES]; · 176 unmodified lines
464/* global variables */403/* global variables */
465 404
466/* Device single-open policy control */405/* Device single-open policy control */
467static atomic_t lcd_available = ATOMIC_INIT(1);
468static atomic_t keypad_available = ATOMIC_INIT(1);406static atomic_t keypad_available = ATOMIC_INIT(1);
469 407
470static struct pardevice *pprt;408static struct pardevice *pprt;
471 409
472static int keypad_initialized;410static int keypad_initialized;
473 411
474static void (*lcd_write_cmd)(int);
475static void (*lcd_write_data)(int);
476static void (*lcd_clear_fast)(void);
477
478static DEFINE_SPINLOCK(pprt_lock);412static DEFINE_SPINLOCK(pprt_lock);
479static struct timer_list scan_timer;413static struct timer_list scan_timer;
480 414
@@ -574,8 +508,6 @@ static int keypad_enabled = NOT_SET; · 93 unmodified lines
574module_param(keypad_enabled, int, 0000);508module_param(keypad_enabled, int, 0000);
575MODULE_PARM_DESC(keypad_enabled, "Deprecated option, use keypad_type instead");509MODULE_PARM_DESC(keypad_enabled, "Deprecated option, use keypad_type instead");
576 510
577static const unsigned char *lcd_char_conv;
578
579/* for some LCD drivers (ks0074) we need a charset conversion table. */511/* for some LCD drivers (ks0074) we need a charset conversion table. */
580static const unsigned char lcd_char_conv_ks0074[256] = {512static const unsigned char lcd_char_conv_ks0074[256] = {
581 /* 0|8 1|9 2|A 3|B 4|C 5|D 6|E 7|F */513 /* 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
752 }684 }
753}685}
754 686
755/* sleeps that many milliseconds with a reschedule */
756static 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
764/*687/*
765 * send a serial byte to the LCD panel. The caller is responsible for locking688 * send a serial byte to the LCD panel. The caller is responsible for locking
766 * if needed.689 * if needed.
@@ -792,8 +715,11 @@ static void lcd_send_serial(int byte) · 25 unmodified lines
792}715}
793 716
794/* turn the backlight on or off */717/* turn the backlight on or off */
795static void __lcd_backlight(int on)718static void lcd_backlight(struct charlcd *charlcd, int on)
796{719{
720 if (lcd.pins.bl == PIN_NONE)
721 return;
722
797 /* The backlight is activated by setting the AUTOFEED line to +5V */723 /* The backlight is activated by setting the AUTOFEED line to +5V */
798 spin_lock_irq(&pprt_lock);724 spin_lock_irq(&pprt_lock);
799 if (on)725 if (on)
@@ -804,46 +730,8 @@ static void __lcd_backlight(int on) · 4 unmodified lines
804 spin_unlock_irq(&pprt_lock);730 spin_unlock_irq(&pprt_lock);
805}731}
806 732
807static 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
818static 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 */
830static 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
845/* send a command to the LCD panel in serial mode */733/* send a command to the LCD panel in serial mode */
846static void lcd_write_cmd_s(int cmd)734static void lcd_write_cmd_s(struct charlcd *charlcd, int cmd)
847{735{
848 spin_lock_irq(&pprt_lock);736 spin_lock_irq(&pprt_lock);
849 lcd_send_serial(0x1F); /* R/W=W, RS=0 */737 lcd_send_serial(0x1F); /* R/W=W, RS=0 */
@@ -854,7 +742,7 @@ static void lcd_write_cmd_s(int cmd) · 4 unmodified lines
854}742}
855 743
856/* send data to the LCD panel in serial mode */744/* send data to the LCD panel in serial mode */
857static void lcd_write_data_s(int data)745static void lcd_write_data_s(struct charlcd *charlcd, int data)
858{746{
859 spin_lock_irq(&pprt_lock);747 spin_lock_irq(&pprt_lock);
860 lcd_send_serial(0x5F); /* R/W=W, RS=1 */748 lcd_send_serial(0x5F); /* R/W=W, RS=1 */
@@ -865,7 +753,7 @@ static void lcd_write_data_s(int data) · 4 unmodified lines
865}753}
866 754
867/* send a command to the LCD panel in 8 bits parallel mode */755/* send a command to the LCD panel in 8 bits parallel mode */
868static void lcd_write_cmd_p8(int cmd)756static void lcd_write_cmd_p8(struct charlcd *charlcd, int cmd)
869{757{
870 spin_lock_irq(&pprt_lock);758 spin_lock_irq(&pprt_lock);
871 /* present the data to the data port */759 /* present the data to the data port */
@@ -887,7 +775,7 @@ static void lcd_write_cmd_p8(int cmd) · 15 unmodified lines
887}775}
888 776
889/* send data to the LCD panel in 8 bits parallel mode */777/* send data to the LCD panel in 8 bits parallel mode */
890static void lcd_write_data_p8(int data)778static void lcd_write_data_p8(struct charlcd *charlcd, int data)
891{779{
892 spin_lock_irq(&pprt_lock);780 spin_lock_irq(&pprt_lock);
893 /* present the data to the data port */781 /* present the data to the data port */
@@ -909,7 +797,7 @@ static void lcd_write_data_p8(int data) · 15 unmodified lines
909}797}
910 798
911/* send a command to the TI LCD panel */799/* send a command to the TI LCD panel */
912static void lcd_write_cmd_tilcd(int cmd)800static void lcd_write_cmd_tilcd(struct charlcd *charlcd, int cmd)
913{801{
914 spin_lock_irq(&pprt_lock);802 spin_lock_irq(&pprt_lock);
915 /* present the data to the control port */803 /* present the data to the control port */
@@ -919,7 +807,7 @@ static void lcd_write_cmd_tilcd(int cmd) · 3 unmodified lines
919}807}
920 808
921/* send data to the TI LCD panel */809/* send data to the TI LCD panel */
922static void lcd_write_data_tilcd(int data)810static void lcd_write_data_tilcd(struct charlcd *charlcd, int data)
923{811{
924 spin_lock_irq(&pprt_lock);812 spin_lock_irq(&pprt_lock);
925 /* present the data to the data port */813 /* present the data to the data port */
@@ -928,47 +816,13 @@ static void lcd_write_data_tilcd(int data) · 2 unmodified lines
928 spin_unlock_irq(&pprt_lock);816 spin_unlock_irq(&pprt_lock);
929}817}
930 818
931static 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
943static void lcd_home(void)
944{
945 lcd.addr.x = 0;
946 lcd.addr.y = 0;
947 lcd_gotoxy();
948}
949
950static 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
963/* fills the display with spaces and resets X/Y */819/* fills the display with spaces and resets X/Y */
964static void lcd_clear_fast_s(void)820static void lcd_clear_fast_s(struct charlcd *charlcd)
965{821{
966 int pos;822 int pos;
967 823
968 lcd_home();
969
970 spin_lock_irq(&pprt_lock);824 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++) {
972 lcd_send_serial(0x5F); /* R/W=W, RS=1 */826 lcd_send_serial(0x5F); /* R/W=W, RS=1 */
973 lcd_send_serial(' ' & 0x0F);827 lcd_send_serial(' ' & 0x0F);
974 lcd_send_serial((' ' >> 4) & 0x0F);828 lcd_send_serial((' ' >> 4) & 0x0F);
@@ -976,19 +830,15 @@ static void lcd_clear_fast_s(void) · 1 unmodified line
976 udelay(40);830 udelay(40);
977 }831 }
978 spin_unlock_irq(&pprt_lock);832 spin_unlock_irq(&pprt_lock);
979
980 lcd_home();
981}833}
982 834
983/* fills the display with spaces and resets X/Y */835/* fills the display with spaces and resets X/Y */
984static void lcd_clear_fast_p8(void)836static void lcd_clear_fast_p8(struct charlcd *charlcd)
985{837{
986 int pos;838 int pos;
987 839
988 lcd_home();
989
990 spin_lock_irq(&pprt_lock);840 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++) {
992 /* present the data to the data port */842 /* present the data to the data port */
993 w_dtr(pprt, ' ');843 w_dtr(pprt, ' ');
994 844
@@ -1010,488 +860,62 @@ static void lcd_clear_fast_p8(void) · 15 unmodified lines
1010 udelay(45);860 udelay(45);
1011 }861 }
1012 spin_unlock_irq(&pprt_lock);862 spin_unlock_irq(&pprt_lock);
1013
1014 lcd_home();
1015}863}
1016 864
1017/* fills the display with spaces and resets X/Y */865/* fills the display with spaces and resets X/Y */
1018static void lcd_clear_fast_tilcd(void)866static void lcd_clear_fast_tilcd(struct charlcd *charlcd)
1019{867{
1020 int pos;868 int pos;
1021 869
1022 lcd_home();
1023
1024 spin_lock_irq(&pprt_lock);870 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++) {
1026 /* present the data to the data port */872 /* present the data to the data port */
1027 w_dtr(pprt, ' ');873 w_dtr(pprt, ' ');
1028 udelay(60);874 udelay(60);
1029 }875 }
1030 876
1031 spin_unlock_irq(&pprt_lock);877 spin_unlock_irq(&pprt_lock);
1032
1033 lcd_home();
1034}
1035
1036/* clears the display and resets X/Y */
1037static 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);
1044}878}
1045 879
1046static void lcd_init_display(void)880static struct charlcd_ops charlcd_serial_ops = {
1047{881 .write_cmd = lcd_write_cmd_s,
1048 lcd.flags = ((lcd.height > 1) ? LCD_FLAG_N : 0)882 .write_data = lcd_write_data_s,
1049 | LCD_FLAG_D | LCD_FLAG_C | LCD_FLAG_B;883 .clear_fast = lcd_clear_fast_s,
1050 884 .backlight = lcd_backlight,
1051 long_sleep(20); /* wait 20 ms after power-up for the paranoid */885};
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);
1084 886
1085 lcd_clear_display();887static struct charlcd_ops charlcd_parallel_ops = {
1086}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};
1087 893
1088/*894static struct charlcd_ops charlcd_tilcd_ops = {
1089 * These are the file operation function for user access to /dev/lcd895 .write_cmd = lcd_write_cmd_tilcd,
1090 * This function can also be called from inside the kernel, by896 .write_data = lcd_write_data_tilcd,
1091 * setting file and ppos to NULL.897 .clear_fast = lcd_clear_fast_tilcd,
1092 *898 .backlight = lcd_backlight,
1093 */899};
1094 900
1095static inline int handle_lcd_special_code(void)901/* initialize the LCD driver */
902static void lcd_init(void)
1096{903{
1097 /* LCD special codes */904 struct charlcd *charlcd;
1098
1099 int processed = 0;
1100 905
1101 char *esc = lcd.esc_seq.buf + 2;906 charlcd = charlcd_alloc(0);
1102 int oldflags = lcd.flags;907 if (!charlcd)
1103 908 return;
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
1317static 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 }
1381 909
1382 /*910 /*
1383 * now we'll see if we're in an escape mode and if the current911 * Init lcd struct with load-time values to preserve exact
1384 * escape sequence can be understood.912 * current functionality (at least for now).
1385 */913 */
1386 if (lcd.esc_seq.len >= 2) {914 charlcd->height = lcd_height;
1387 int processed = 0;915 charlcd->width = lcd_width;
1388 916 charlcd->bwidth = lcd_bwidth;
1389 if (!strcmp(lcd.esc_seq.buf, "[2J")) {917 charlcd->hwidth = lcd_hwidth;
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}
1414 918
1415static 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
1438static 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
1453static int lcd_release(struct inode *inode, struct file *file)
1454{
1455 atomic_inc(&lcd_available);
1456 return 0;
1457}
1458
1459static const struct file_operations lcd_fops = {
1460 .write = lcd_write,
1461 .open = lcd_open,
1462 .release = lcd_release,
1463 .llseek = no_llseek,
1464};
1465
1466static 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 */
1473static 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 */
1493static void lcd_init(void)
1494{
1495 switch (selected_lcd_type) {919 switch (selected_lcd_type) {
1496 case LCD_TYPE_OLD:920 case LCD_TYPE_OLD:
1497 /* parallel mode, 8 bits */921 /* parallel mode, 8 bits */
@@ -1500,10 +924,10 @@ static void lcd_init(void) · 2 unmodified lines
1500 lcd.pins.e = PIN_STROBE;924 lcd.pins.e = PIN_STROBE;
1501 lcd.pins.rs = PIN_AUTOLF;925 lcd.pins.rs = PIN_AUTOLF;
1502 926
1503 lcd.width = 40;927 charlcd->width = 40;
1504 lcd.bwidth = 40;928 charlcd->bwidth = 40;
1505 lcd.hwidth = 64;929 charlcd->hwidth = 64;
1506 lcd.height = 2;930 charlcd->height = 2;
1507 break;931 break;
1508 case LCD_TYPE_KS0074:932 case LCD_TYPE_KS0074:
1509 /* serial mode, ks0074 */933 /* serial mode, ks0074 */
@@ -1513,10 +937,10 @@ static void lcd_init(void) · 3 unmodified lines
1513 lcd.pins.cl = PIN_STROBE;937 lcd.pins.cl = PIN_STROBE;
1514 lcd.pins.da = PIN_D0;938 lcd.pins.da = PIN_D0;
1515 939
1516 lcd.width = 16;940 charlcd->width = 16;
1517 lcd.bwidth = 40;941 charlcd->bwidth = 40;
1518 lcd.hwidth = 16;942 charlcd->hwidth = 16;
1519 lcd.height = 2;943 charlcd->height = 2;
1520 break;944 break;
1521 case LCD_TYPE_NEXCOM:945 case LCD_TYPE_NEXCOM:
1522 /* parallel mode, 8 bits, generic */946 /* parallel mode, 8 bits, generic */
@@ -1526,10 +950,10 @@ static void lcd_init(void) · 3 unmodified lines
1526 lcd.pins.rs = PIN_SELECP;950 lcd.pins.rs = PIN_SELECP;
1527 lcd.pins.rw = PIN_INITP;951 lcd.pins.rw = PIN_INITP;
1528 952
1529 lcd.width = 16;953 charlcd->width = 16;
1530 lcd.bwidth = 40;954 charlcd->bwidth = 40;
1531 lcd.hwidth = 64;955 charlcd->hwidth = 64;
1532 lcd.height = 2;956 charlcd->height = 2;
1533 break;957 break;
1534 case LCD_TYPE_CUSTOM:958 case LCD_TYPE_CUSTOM:
1535 /* customer-defined */959 /* customer-defined */
@@ -1545,22 +969,22 @@ static void lcd_init(void) · 9 unmodified lines
1545 lcd.pins.e = PIN_STROBE;969 lcd.pins.e = PIN_STROBE;
1546 lcd.pins.rs = PIN_SELECP;970 lcd.pins.rs = PIN_SELECP;
1547 971
1548 lcd.width = 16;972 charlcd->width = 16;
1549 lcd.bwidth = 40;973 charlcd->bwidth = 40;
1550 lcd.hwidth = 64;974 charlcd->hwidth = 64;
1551 lcd.height = 2;975 charlcd->height = 2;
1552 break;976 break;
1553 }977 }
1554 978
1555 /* Overwrite with module params set on loading */979 /* Overwrite with module params set on loading */
1556 if (lcd_height != NOT_SET)980 if (lcd_height != NOT_SET)
1557 lcd.height = lcd_height;981 charlcd->height = lcd_height;
1558 if (lcd_width != NOT_SET)982 if (lcd_width != NOT_SET)
1559 lcd.width = lcd_width;983 charlcd->width = lcd_width;
1560 if (lcd_bwidth != NOT_SET)984 if (lcd_bwidth != NOT_SET)
1561 lcd.bwidth = lcd_bwidth;985 charlcd->bwidth = lcd_bwidth;
1562 if (lcd_hwidth != NOT_SET)986 if (lcd_hwidth != NOT_SET)
1563 lcd.hwidth = lcd_hwidth;987 charlcd->hwidth = lcd_hwidth;
1564 if (lcd_charset != NOT_SET)988 if (lcd_charset != NOT_SET)
1565 lcd.charset = lcd_charset;989 lcd.charset = lcd_charset;
1566 if (lcd_proto != NOT_SET)990 if (lcd_proto != NOT_SET)
@@ -1579,19 +1003,17 @@ static void lcd_init(void) · 12 unmodified lines
1579 lcd.pins.bl = lcd_bl_pin;1003 lcd.pins.bl = lcd_bl_pin;
1580 1004
1581 /* this is used to catch wrong and default values */1005 /* this is used to catch wrong and default values */
1582 if (lcd.width <= 0)1006 if (charlcd->width <= 0)
1583 lcd.width = DEFAULT_LCD_WIDTH;1007 charlcd->width = DEFAULT_LCD_WIDTH;
1584 if (lcd.bwidth <= 0)1008 if (charlcd->bwidth <= 0)
1585 lcd.bwidth = DEFAULT_LCD_BWIDTH;1009 charlcd->bwidth = DEFAULT_LCD_BWIDTH;
1586 if (lcd.hwidth <= 0)1010 if (charlcd->hwidth <= 0)
1587 lcd.hwidth = DEFAULT_LCD_HWIDTH;1011 charlcd->hwidth = DEFAULT_LCD_HWIDTH;
1588 if (lcd.height <= 0)1012 if (charlcd->height <= 0)
1589 lcd.height = DEFAULT_LCD_HEIGHT;1013 charlcd->height = DEFAULT_LCD_HEIGHT;
1590 1014
1591 if (lcd.proto == LCD_PROTO_SERIAL) { /* SERIAL */1015 if (lcd.proto == LCD_PROTO_SERIAL) { /* SERIAL */
1592 lcd_write_cmd = lcd_write_cmd_s;1016 charlcd->ops = &charlcd_serial_ops;
1593 lcd_write_data = lcd_write_data_s;
1594 lcd_clear_fast = lcd_clear_fast_s;
1595 1017
1596 if (lcd.pins.cl == PIN_NOT_SET)1018 if (lcd.pins.cl == PIN_NOT_SET)
1597 lcd.pins.cl = DEFAULT_LCD_PIN_SCL;1019 lcd.pins.cl = DEFAULT_LCD_PIN_SCL;
@@ -1599,9 +1021,7 @@ static void lcd_init(void) · 1 unmodified line
1599 lcd.pins.da = DEFAULT_LCD_PIN_SDA;1021 lcd.pins.da = DEFAULT_LCD_PIN_SDA;
1600 1022
1601 } else if (lcd.proto == LCD_PROTO_PARALLEL) { /* PARALLEL */1023 } else if (lcd.proto == LCD_PROTO_PARALLEL) { /* PARALLEL */
1602 lcd_write_cmd = lcd_write_cmd_p8;1024 charlcd->ops = &charlcd_parallel_ops;
1603 lcd_write_data = lcd_write_data_p8;
1604 lcd_clear_fast = lcd_clear_fast_p8;
1605 1025
1606 if (lcd.pins.e == PIN_NOT_SET)1026 if (lcd.pins.e == PIN_NOT_SET)
1607 lcd.pins.e = DEFAULT_LCD_PIN_E;1027 lcd.pins.e = DEFAULT_LCD_PIN_E;
@@ -1610,9 +1030,7 @@ static void lcd_init(void) · 2 unmodified lines
1610 if (lcd.pins.rw == PIN_NOT_SET)1030 if (lcd.pins.rw == PIN_NOT_SET)
1611 lcd.pins.rw = DEFAULT_LCD_PIN_RW;1031 lcd.pins.rw = DEFAULT_LCD_PIN_RW;
1612 } else {1032 } else {
1613 lcd_write_cmd = lcd_write_cmd_tilcd;1033 charlcd->ops = &charlcd_tilcd_ops;
1614 lcd_write_data = lcd_write_data_tilcd;
1615 lcd_clear_fast = lcd_clear_fast_tilcd;
1616 }1034 }
1617 1035
1618 if (lcd.pins.bl == PIN_NOT_SET)1036 if (lcd.pins.bl == PIN_NOT_SET)
@@ -1635,14 +1053,9 @@ static void lcd_init(void) · 16 unmodified lines
1635 lcd.charset = DEFAULT_LCD_CHARSET;1053 lcd.charset = DEFAULT_LCD_CHARSET;
1636 1054
1637 if (lcd.charset == LCD_CHARSET_KS0074)1055 if (lcd.charset == LCD_CHARSET_KS0074)
1638 lcd_char_conv = lcd_char_conv_ks0074;1056 charlcd->char_conv = lcd_char_conv_ks0074;
1639 else1057 else
1640 lcd_char_conv = NULL;1058 charlcd->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 }
1646 1059
1647 pin_to_bits(lcd.pins.e, lcd_bits[LCD_PORT_D][LCD_BIT_E],1060 pin_to_bits(lcd.pins.e, lcd_bits[LCD_PORT_D][LCD_BIT_E],
1648 lcd_bits[LCD_PORT_C][LCD_BIT_E]);1061 lcd_bits[LCD_PORT_C][LCD_BIT_E]);
@@ -1657,25 +1070,8 @@ static void lcd_init(void) · 8 unmodified lines
1657 pin_to_bits(lcd.pins.da, lcd_bits[LCD_PORT_D][LCD_BIT_DA],1070 pin_to_bits(lcd.pins.da, lcd_bits[LCD_PORT_D][LCD_BIT_DA],
1658 lcd_bits[LCD_PORT_C][LCD_BIT_DA]);1071 lcd_bits[LCD_PORT_C][LCD_BIT_DA]);
1659 1072
1660 /*1073 lcd.charlcd = charlcd;
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 */
1665 lcd.initialized = true;1074 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();
1679}1075}
1680 1076
1681/*1077/*
@@ -2011,7 +1407,7 @@ static void panel_scan_timer(void) · 329 unmodified lines
2011 }1407 }
2012 1408
2013 if (keypressed && lcd.enabled && lcd.initialized)1409 if (keypressed && lcd.enabled && lcd.initialized)
2014 lcd_poke();1410 charlcd_poke(lcd.charlcd);
2015 1411
2016 mod_timer(&scan_timer, jiffies + INPUT_POLL_TIME);1412 mod_timer(&scan_timer, jiffies + INPUT_POLL_TIME);
2017}1413}
@@ -2175,35 +1571,6 @@ static void keypad_init(void) · 157 unmodified lines
2175/* device initialization */1571/* device initialization */
2176/**************************************************/1572/**************************************************/
2177 1573
2178static 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
2201static struct notifier_block panel_notifier = {
2202 panel_notify_sys,
2203 NULL,
2204 0
2205};
2206
2207static void panel_attach(struct parport *port)1574static void panel_attach(struct parport *port)
2208{1575{
2209 struct pardev_cb panel_cb;1576 struct pardev_cb panel_cb;
@@ -2239,7 +1606,7 @@ static void panel_attach(struct parport *port) · 29 unmodified lines
2239 */1606 */
2240 if (lcd.enabled) {1607 if (lcd.enabled) {
2241 lcd_init();1608 lcd_init();
2242 if (misc_register(&lcd_dev))1609 if (!lcd.charlcd || charlcd_register(lcd.charlcd))
2243 goto err_unreg_device;1610 goto err_unreg_device;
2244 }1611 }
2245 1612
@@ -2248,13 +1615,14 @@ static void panel_attach(struct parport *port) · 2 unmodified lines
2248 if (misc_register(&keypad_dev))1615 if (misc_register(&keypad_dev))
2249 goto err_lcd_unreg;1616 goto err_lcd_unreg;
2250 }1617 }
2251 register_reboot_notifier(&panel_notifier);
2252 return;1618 return;
2253 1619
2254err_lcd_unreg:1620err_lcd_unreg:
2255 if (lcd.enabled)1621 if (lcd.enabled)
2256 misc_deregister(&lcd_dev);1622 charlcd_unregister(lcd.charlcd);
2257err_unreg_device:1623err_unreg_device:
1624 kfree(lcd.charlcd);
1625 lcd.charlcd = NULL;
2258 parport_unregister_device(pprt);1626 parport_unregister_device(pprt);
2259 pprt = NULL;1627 pprt = NULL;
2260}1628}
@@ -2278,20 +1646,16 @@ static void panel_detach(struct parport *port) · 17 unmodified lines
2278 }1646 }
2279 1647
2280 if (lcd.enabled) {1648 if (lcd.enabled) {
2281 panel_lcd_print("\x0cLCD driver unloaded.\x1b[Lc\x1b[Lb\x1b[L-");1649 charlcd_unregister(lcd.charlcd);
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 }
2287 lcd.initialized = false;1650 lcd.initialized = false;
1651 kfree(lcd.charlcd);
1652 lcd.charlcd = NULL;
2288 }1653 }
2289 1654
2290 /* TODO: free all input signals */1655 /* TODO: free all input signals */
2291 parport_release(pprt);1656 parport_release(pprt);
2292 parport_unregister_device(pprt);1657 parport_unregister_device(pprt);
2293 pprt = NULL;1658 pprt = NULL;
2294 unregister_reboot_notifier(&panel_notifier);
2295}1659}
2296 1660
2297static struct parport_driver panel_driver = {1661static struct parport_driver panel_driver = {
@@ -2369,10 +1733,6 @@ static int __init panel_init_module(void) · 71 unmodified lines
2369 * Init lcd struct with load-time values to preserve exact1733 * Init lcd struct with load-time values to preserve exact
2370 * current functionality (at least for now).1734 * current functionality (at least for now).
2371 */1735 */
2372 lcd.height = lcd_height;
2373 lcd.width = lcd_width;
2374 lcd.bwidth = lcd_bwidth;
2375 lcd.hwidth = lcd_hwidth;
2376 lcd.charset = lcd_charset;1736 lcd.charset = lcd_charset;
2377 lcd.proto = lcd_proto;1737 lcd.proto = lcd_proto;
2378 lcd.pins.e = lcd_e_pin;1738 lcd.pins.e = lcd_e_pin;
@@ -2381,9 +1741,6 @@ static int __init panel_init_module(void) · 2 unmodified lines
2381 lcd.pins.cl = lcd_cl_pin;1741 lcd.pins.cl = lcd_cl_pin;
2382 lcd.pins.da = lcd_da_pin;1742 lcd.pins.da = lcd_da_pin;
2383 lcd.pins.bl = lcd_bl_pin;1743 lcd.pins.bl = lcd_bl_pin;
2384
2385 /* Leave it for now, just in case */
2386 lcd.esc_seq.len = -1;
2387 }1744 }
2388 1745
2389 switch (selected_keypad_type) {1746 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
13struct 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
25struct 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
35struct charlcd *charlcd_alloc(unsigned int drvdata_size);
36
37int charlcd_register(struct charlcd *lcd);
38int charlcd_unregister(struct charlcd *lcd);
39
40void charlcd_poke(struct charlcd *lcd);