Merge tag 'mailbox-v6.6' of git://git.linaro.org/landing-teams/working/fujitsu/integr...
[platform/kernel/linux-starfive.git] / drivers / auxdisplay / charlcd.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Character LCD driver for Linux
4  *
5  * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu>
6  * Copyright (C) 2016-2017 Glider bvba
7  */
8
9 #include <linux/atomic.h>
10 #include <linux/ctype.h>
11 #include <linux/fs.h>
12 #include <linux/miscdevice.h>
13 #include <linux/module.h>
14 #include <linux/notifier.h>
15 #include <linux/reboot.h>
16 #include <linux/slab.h>
17 #include <linux/uaccess.h>
18 #include <linux/workqueue.h>
19
20 #include <generated/utsrelease.h>
21
22 #include "charlcd.h"
23
24 /* Keep the backlight on this many seconds for each flash */
25 #define LCD_BL_TEMPO_PERIOD     4
26
27 #define LCD_ESCAPE_LEN          24      /* Max chars for LCD escape command */
28 #define LCD_ESCAPE_CHAR         27      /* Use char 27 for escape command */
29
30 struct charlcd_priv {
31         struct charlcd lcd;
32
33         struct delayed_work bl_work;
34         struct mutex bl_tempo_lock;     /* Protects access to bl_tempo */
35         bool bl_tempo;
36
37         bool must_clear;
38
39         /* contains the LCD config state */
40         unsigned long flags;
41
42         /* Current escape sequence and it's length or -1 if outside */
43         struct {
44                 char buf[LCD_ESCAPE_LEN + 1];
45                 int len;
46         } esc_seq;
47
48         unsigned long long drvdata[];
49 };
50
51 #define charlcd_to_priv(p)      container_of(p, struct charlcd_priv, lcd)
52
53 /* Device single-open policy control */
54 static atomic_t charlcd_available = ATOMIC_INIT(1);
55
56 /* turn the backlight on or off */
57 void charlcd_backlight(struct charlcd *lcd, enum charlcd_onoff on)
58 {
59         struct charlcd_priv *priv = charlcd_to_priv(lcd);
60
61         if (!lcd->ops->backlight)
62                 return;
63
64         mutex_lock(&priv->bl_tempo_lock);
65         if (!priv->bl_tempo)
66                 lcd->ops->backlight(lcd, on);
67         mutex_unlock(&priv->bl_tempo_lock);
68 }
69 EXPORT_SYMBOL_GPL(charlcd_backlight);
70
71 static void charlcd_bl_off(struct work_struct *work)
72 {
73         struct delayed_work *dwork = to_delayed_work(work);
74         struct charlcd_priv *priv =
75                 container_of(dwork, struct charlcd_priv, bl_work);
76
77         mutex_lock(&priv->bl_tempo_lock);
78         if (priv->bl_tempo) {
79                 priv->bl_tempo = false;
80                 if (!(priv->flags & LCD_FLAG_L))
81                         priv->lcd.ops->backlight(&priv->lcd, CHARLCD_OFF);
82         }
83         mutex_unlock(&priv->bl_tempo_lock);
84 }
85
86 /* turn the backlight on for a little while */
87 void charlcd_poke(struct charlcd *lcd)
88 {
89         struct charlcd_priv *priv = charlcd_to_priv(lcd);
90
91         if (!lcd->ops->backlight)
92                 return;
93
94         cancel_delayed_work_sync(&priv->bl_work);
95
96         mutex_lock(&priv->bl_tempo_lock);
97         if (!priv->bl_tempo && !(priv->flags & LCD_FLAG_L))
98                 lcd->ops->backlight(lcd, CHARLCD_ON);
99         priv->bl_tempo = true;
100         schedule_delayed_work(&priv->bl_work, LCD_BL_TEMPO_PERIOD * HZ);
101         mutex_unlock(&priv->bl_tempo_lock);
102 }
103 EXPORT_SYMBOL_GPL(charlcd_poke);
104
105 static void charlcd_home(struct charlcd *lcd)
106 {
107         lcd->addr.x = 0;
108         lcd->addr.y = 0;
109         lcd->ops->home(lcd);
110 }
111
112 static void charlcd_print(struct charlcd *lcd, char c)
113 {
114         if (lcd->addr.x >= lcd->width)
115                 return;
116
117         if (lcd->char_conv)
118                 c = lcd->char_conv[(unsigned char)c];
119
120         if (!lcd->ops->print(lcd, c))
121                 lcd->addr.x++;
122
123         /* prevents the cursor from wrapping onto the next line */
124         if (lcd->addr.x == lcd->width)
125                 lcd->ops->gotoxy(lcd, lcd->addr.x - 1, lcd->addr.y);
126 }
127
128 static void charlcd_clear_display(struct charlcd *lcd)
129 {
130         lcd->ops->clear_display(lcd);
131         lcd->addr.x = 0;
132         lcd->addr.y = 0;
133 }
134
135 /*
136  * Parses a movement command of the form "(.*);", where the group can be
137  * any number of subcommands of the form "(x|y)[0-9]+".
138  *
139  * Returns whether the command is valid. The position arguments are
140  * only written if the parsing was successful.
141  *
142  * For instance:
143  *   - ";"          returns (<original x>, <original y>).
144  *   - "x1;"        returns (1, <original y>).
145  *   - "y2x1;"      returns (1, 2).
146  *   - "x12y34x56;" returns (56, 34).
147  *   - ""           fails.
148  *   - "x"          fails.
149  *   - "x;"         fails.
150  *   - "x1"         fails.
151  *   - "xy12;"      fails.
152  *   - "x12yy12;"   fails.
153  *   - "xx"         fails.
154  */
155 static bool parse_xy(const char *s, unsigned long *x, unsigned long *y)
156 {
157         unsigned long new_x = *x;
158         unsigned long new_y = *y;
159         char *p;
160
161         for (;;) {
162                 if (!*s)
163                         return false;
164
165                 if (*s == ';')
166                         break;
167
168                 if (*s == 'x') {
169                         new_x = simple_strtoul(s + 1, &p, 10);
170                         if (p == s + 1)
171                                 return false;
172                         s = p;
173                 } else if (*s == 'y') {
174                         new_y = simple_strtoul(s + 1, &p, 10);
175                         if (p == s + 1)
176                                 return false;
177                         s = p;
178                 } else {
179                         return false;
180                 }
181         }
182
183         *x = new_x;
184         *y = new_y;
185         return true;
186 }
187
188 /*
189  * These are the file operation function for user access to /dev/lcd
190  * This function can also be called from inside the kernel, by
191  * setting file and ppos to NULL.
192  *
193  */
194
195 static inline int handle_lcd_special_code(struct charlcd *lcd)
196 {
197         struct charlcd_priv *priv = charlcd_to_priv(lcd);
198
199         /* LCD special codes */
200
201         int processed = 0;
202
203         char *esc = priv->esc_seq.buf + 2;
204         int oldflags = priv->flags;
205
206         /* check for display mode flags */
207         switch (*esc) {
208         case 'D':       /* Display ON */
209                 priv->flags |= LCD_FLAG_D;
210                 if (priv->flags != oldflags)
211                         lcd->ops->display(lcd, CHARLCD_ON);
212
213                 processed = 1;
214                 break;
215         case 'd':       /* Display OFF */
216                 priv->flags &= ~LCD_FLAG_D;
217                 if (priv->flags != oldflags)
218                         lcd->ops->display(lcd, CHARLCD_OFF);
219
220                 processed = 1;
221                 break;
222         case 'C':       /* Cursor ON */
223                 priv->flags |= LCD_FLAG_C;
224                 if (priv->flags != oldflags)
225                         lcd->ops->cursor(lcd, CHARLCD_ON);
226
227                 processed = 1;
228                 break;
229         case 'c':       /* Cursor OFF */
230                 priv->flags &= ~LCD_FLAG_C;
231                 if (priv->flags != oldflags)
232                         lcd->ops->cursor(lcd, CHARLCD_OFF);
233
234                 processed = 1;
235                 break;
236         case 'B':       /* Blink ON */
237                 priv->flags |= LCD_FLAG_B;
238                 if (priv->flags != oldflags)
239                         lcd->ops->blink(lcd, CHARLCD_ON);
240
241                 processed = 1;
242                 break;
243         case 'b':       /* Blink OFF */
244                 priv->flags &= ~LCD_FLAG_B;
245                 if (priv->flags != oldflags)
246                         lcd->ops->blink(lcd, CHARLCD_OFF);
247
248                 processed = 1;
249                 break;
250         case '+':       /* Back light ON */
251                 priv->flags |= LCD_FLAG_L;
252                 if (priv->flags != oldflags)
253                         charlcd_backlight(lcd, CHARLCD_ON);
254
255                 processed = 1;
256                 break;
257         case '-':       /* Back light OFF */
258                 priv->flags &= ~LCD_FLAG_L;
259                 if (priv->flags != oldflags)
260                         charlcd_backlight(lcd, CHARLCD_OFF);
261
262                 processed = 1;
263                 break;
264         case '*':       /* Flash back light */
265                 charlcd_poke(lcd);
266                 processed = 1;
267                 break;
268         case 'f':       /* Small Font */
269                 priv->flags &= ~LCD_FLAG_F;
270                 if (priv->flags != oldflags)
271                         lcd->ops->fontsize(lcd, CHARLCD_FONTSIZE_SMALL);
272
273                 processed = 1;
274                 break;
275         case 'F':       /* Large Font */
276                 priv->flags |= LCD_FLAG_F;
277                 if (priv->flags != oldflags)
278                         lcd->ops->fontsize(lcd, CHARLCD_FONTSIZE_LARGE);
279
280                 processed = 1;
281                 break;
282         case 'n':       /* One Line */
283                 priv->flags &= ~LCD_FLAG_N;
284                 if (priv->flags != oldflags)
285                         lcd->ops->lines(lcd, CHARLCD_LINES_1);
286
287                 processed = 1;
288                 break;
289         case 'N':       /* Two Lines */
290                 priv->flags |= LCD_FLAG_N;
291                 if (priv->flags != oldflags)
292                         lcd->ops->lines(lcd, CHARLCD_LINES_2);
293
294                 processed = 1;
295                 break;
296         case 'l':       /* Shift Cursor Left */
297                 if (lcd->addr.x > 0) {
298                         if (!lcd->ops->shift_cursor(lcd, CHARLCD_SHIFT_LEFT))
299                                 lcd->addr.x--;
300                 }
301
302                 processed = 1;
303                 break;
304         case 'r':       /* shift cursor right */
305                 if (lcd->addr.x < lcd->width) {
306                         if (!lcd->ops->shift_cursor(lcd, CHARLCD_SHIFT_RIGHT))
307                                 lcd->addr.x++;
308                 }
309
310                 processed = 1;
311                 break;
312         case 'L':       /* shift display left */
313                 lcd->ops->shift_display(lcd, CHARLCD_SHIFT_LEFT);
314                 processed = 1;
315                 break;
316         case 'R':       /* shift display right */
317                 lcd->ops->shift_display(lcd, CHARLCD_SHIFT_RIGHT);
318                 processed = 1;
319                 break;
320         case 'k': {     /* kill end of line */
321                 int x, xs, ys;
322
323                 xs = lcd->addr.x;
324                 ys = lcd->addr.y;
325                 for (x = lcd->addr.x; x < lcd->width; x++)
326                         lcd->ops->print(lcd, ' ');
327
328                 /* restore cursor position */
329                 lcd->addr.x = xs;
330                 lcd->addr.y = ys;
331                 lcd->ops->gotoxy(lcd, lcd->addr.x, lcd->addr.y);
332                 processed = 1;
333                 break;
334         }
335         case 'I':       /* reinitialize display */
336                 lcd->ops->init_display(lcd);
337                 priv->flags = ((lcd->height > 1) ? LCD_FLAG_N : 0) | LCD_FLAG_D |
338                         LCD_FLAG_C | LCD_FLAG_B;
339                 processed = 1;
340                 break;
341         case 'G':
342                 if (lcd->ops->redefine_char)
343                         processed = lcd->ops->redefine_char(lcd, esc);
344                 else
345                         processed = 1;
346                 break;
347
348         case 'x':       /* gotoxy : LxXXX[yYYY]; */
349         case 'y':       /* gotoxy : LyYYY[xXXX]; */
350                 if (priv->esc_seq.buf[priv->esc_seq.len - 1] != ';')
351                         break;
352
353                 /* If the command is valid, move to the new address */
354                 if (parse_xy(esc, &lcd->addr.x, &lcd->addr.y))
355                         lcd->ops->gotoxy(lcd, lcd->addr.x, lcd->addr.y);
356
357                 /* Regardless of its validity, mark as processed */
358                 processed = 1;
359                 break;
360         }
361
362         return processed;
363 }
364
365 static void charlcd_write_char(struct charlcd *lcd, char c)
366 {
367         struct charlcd_priv *priv = charlcd_to_priv(lcd);
368
369         /* first, we'll test if we're in escape mode */
370         if ((c != '\n') && priv->esc_seq.len >= 0) {
371                 /* yes, let's add this char to the buffer */
372                 priv->esc_seq.buf[priv->esc_seq.len++] = c;
373                 priv->esc_seq.buf[priv->esc_seq.len] = '\0';
374         } else {
375                 /* aborts any previous escape sequence */
376                 priv->esc_seq.len = -1;
377
378                 switch (c) {
379                 case LCD_ESCAPE_CHAR:
380                         /* start of an escape sequence */
381                         priv->esc_seq.len = 0;
382                         priv->esc_seq.buf[priv->esc_seq.len] = '\0';
383                         break;
384                 case '\b':
385                         /* go back one char and clear it */
386                         if (lcd->addr.x > 0) {
387                                 /* back one char */
388                                 if (!lcd->ops->shift_cursor(lcd,
389                                                         CHARLCD_SHIFT_LEFT))
390                                         lcd->addr.x--;
391                         }
392                         /* replace with a space */
393                         charlcd_print(lcd, ' ');
394                         /* back one char again */
395                         if (!lcd->ops->shift_cursor(lcd, CHARLCD_SHIFT_LEFT))
396                                 lcd->addr.x--;
397
398                         break;
399                 case '\f':
400                         /* quickly clear the display */
401                         charlcd_clear_display(lcd);
402                         break;
403                 case '\n':
404                         /*
405                          * flush the remainder of the current line and
406                          * go to the beginning of the next line
407                          */
408                         for (; lcd->addr.x < lcd->width; lcd->addr.x++)
409                                 lcd->ops->print(lcd, ' ');
410
411                         lcd->addr.x = 0;
412                         lcd->addr.y = (lcd->addr.y + 1) % lcd->height;
413                         lcd->ops->gotoxy(lcd, lcd->addr.x, lcd->addr.y);
414                         break;
415                 case '\r':
416                         /* go to the beginning of the same line */
417                         lcd->addr.x = 0;
418                         lcd->ops->gotoxy(lcd, lcd->addr.x, lcd->addr.y);
419                         break;
420                 case '\t':
421                         /* print a space instead of the tab */
422                         charlcd_print(lcd, ' ');
423                         break;
424                 default:
425                         /* simply print this char */
426                         charlcd_print(lcd, c);
427                         break;
428                 }
429         }
430
431         /*
432          * now we'll see if we're in an escape mode and if the current
433          * escape sequence can be understood.
434          */
435         if (priv->esc_seq.len >= 2) {
436                 int processed = 0;
437
438                 if (!strcmp(priv->esc_seq.buf, "[2J")) {
439                         /* clear the display */
440                         charlcd_clear_display(lcd);
441                         processed = 1;
442                 } else if (!strcmp(priv->esc_seq.buf, "[H")) {
443                         /* cursor to home */
444                         charlcd_home(lcd);
445                         processed = 1;
446                 }
447                 /* codes starting with ^[[L */
448                 else if ((priv->esc_seq.len >= 3) &&
449                          (priv->esc_seq.buf[0] == '[') &&
450                          (priv->esc_seq.buf[1] == 'L')) {
451                         processed = handle_lcd_special_code(lcd);
452                 }
453
454                 /* LCD special escape codes */
455                 /*
456                  * flush the escape sequence if it's been processed
457                  * or if it is getting too long.
458                  */
459                 if (processed || (priv->esc_seq.len >= LCD_ESCAPE_LEN))
460                         priv->esc_seq.len = -1;
461         } /* escape codes */
462 }
463
464 static struct charlcd *the_charlcd;
465
466 static ssize_t charlcd_write(struct file *file, const char __user *buf,
467                              size_t count, loff_t *ppos)
468 {
469         const char __user *tmp = buf;
470         char c;
471
472         for (; count-- > 0; (*ppos)++, tmp++) {
473                 if (((count + 1) & 0x1f) == 0) {
474                         /*
475                          * charlcd_write() is invoked as a VFS->write() callback
476                          * and as such it is always invoked from preemptible
477                          * context and may sleep.
478                          */
479                         cond_resched();
480                 }
481
482                 if (get_user(c, tmp))
483                         return -EFAULT;
484
485                 charlcd_write_char(the_charlcd, c);
486         }
487
488         return tmp - buf;
489 }
490
491 static int charlcd_open(struct inode *inode, struct file *file)
492 {
493         struct charlcd_priv *priv = charlcd_to_priv(the_charlcd);
494         int ret;
495
496         ret = -EBUSY;
497         if (!atomic_dec_and_test(&charlcd_available))
498                 goto fail;      /* open only once at a time */
499
500         ret = -EPERM;
501         if (file->f_mode & FMODE_READ)  /* device is write-only */
502                 goto fail;
503
504         if (priv->must_clear) {
505                 priv->lcd.ops->clear_display(&priv->lcd);
506                 priv->must_clear = false;
507                 priv->lcd.addr.x = 0;
508                 priv->lcd.addr.y = 0;
509         }
510         return nonseekable_open(inode, file);
511
512  fail:
513         atomic_inc(&charlcd_available);
514         return ret;
515 }
516
517 static int charlcd_release(struct inode *inode, struct file *file)
518 {
519         atomic_inc(&charlcd_available);
520         return 0;
521 }
522
523 static const struct file_operations charlcd_fops = {
524         .write   = charlcd_write,
525         .open    = charlcd_open,
526         .release = charlcd_release,
527         .llseek  = no_llseek,
528 };
529
530 static struct miscdevice charlcd_dev = {
531         .minor  = LCD_MINOR,
532         .name   = "lcd",
533         .fops   = &charlcd_fops,
534 };
535
536 static void charlcd_puts(struct charlcd *lcd, const char *s)
537 {
538         const char *tmp = s;
539         int count = strlen(s);
540
541         for (; count-- > 0; tmp++) {
542                 if (((count + 1) & 0x1f) == 0)
543                         cond_resched();
544
545                 charlcd_write_char(lcd, *tmp);
546         }
547 }
548
549 #ifdef CONFIG_PANEL_BOOT_MESSAGE
550 #define LCD_INIT_TEXT CONFIG_PANEL_BOOT_MESSAGE
551 #else
552 #define LCD_INIT_TEXT "Linux-" UTS_RELEASE "\n"
553 #endif
554
555 #ifdef CONFIG_CHARLCD_BL_ON
556 #define LCD_INIT_BL "\x1b[L+"
557 #elif defined(CONFIG_CHARLCD_BL_FLASH)
558 #define LCD_INIT_BL "\x1b[L*"
559 #else
560 #define LCD_INIT_BL "\x1b[L-"
561 #endif
562
563 /* initialize the LCD driver */
564 static int charlcd_init(struct charlcd *lcd)
565 {
566         struct charlcd_priv *priv = charlcd_to_priv(lcd);
567         int ret;
568
569         priv->flags = ((lcd->height > 1) ? LCD_FLAG_N : 0) | LCD_FLAG_D |
570                       LCD_FLAG_C | LCD_FLAG_B;
571         if (lcd->ops->backlight) {
572                 mutex_init(&priv->bl_tempo_lock);
573                 INIT_DELAYED_WORK(&priv->bl_work, charlcd_bl_off);
574         }
575
576         /*
577          * before this line, we must NOT send anything to the display.
578          * Since charlcd_init_display() needs to write data, we have to
579          * enable mark the LCD initialized just before.
580          */
581         if (WARN_ON(!lcd->ops->init_display))
582                 return -EINVAL;
583
584         ret = lcd->ops->init_display(lcd);
585         if (ret)
586                 return ret;
587
588         /* display a short message */
589         charlcd_puts(lcd, "\x1b[Lc\x1b[Lb" LCD_INIT_BL LCD_INIT_TEXT);
590
591         /* clear the display on the next device opening */
592         priv->must_clear = true;
593         charlcd_home(lcd);
594         return 0;
595 }
596
597 struct charlcd *charlcd_alloc(void)
598 {
599         struct charlcd_priv *priv;
600         struct charlcd *lcd;
601
602         priv = kzalloc(sizeof(*priv), GFP_KERNEL);
603         if (!priv)
604                 return NULL;
605
606         priv->esc_seq.len = -1;
607
608         lcd = &priv->lcd;
609
610         return lcd;
611 }
612 EXPORT_SYMBOL_GPL(charlcd_alloc);
613
614 void charlcd_free(struct charlcd *lcd)
615 {
616         kfree(charlcd_to_priv(lcd));
617 }
618 EXPORT_SYMBOL_GPL(charlcd_free);
619
620 static int panel_notify_sys(struct notifier_block *this, unsigned long code,
621                             void *unused)
622 {
623         struct charlcd *lcd = the_charlcd;
624
625         switch (code) {
626         case SYS_DOWN:
627                 charlcd_puts(lcd,
628                              "\x0cReloading\nSystem...\x1b[Lc\x1b[Lb\x1b[L+");
629                 break;
630         case SYS_HALT:
631                 charlcd_puts(lcd, "\x0cSystem Halted.\x1b[Lc\x1b[Lb\x1b[L+");
632                 break;
633         case SYS_POWER_OFF:
634                 charlcd_puts(lcd, "\x0cPower off.\x1b[Lc\x1b[Lb\x1b[L+");
635                 break;
636         default:
637                 break;
638         }
639         return NOTIFY_DONE;
640 }
641
642 static struct notifier_block panel_notifier = {
643         .notifier_call = panel_notify_sys,
644 };
645
646 int charlcd_register(struct charlcd *lcd)
647 {
648         int ret;
649
650         ret = charlcd_init(lcd);
651         if (ret)
652                 return ret;
653
654         ret = misc_register(&charlcd_dev);
655         if (ret)
656                 return ret;
657
658         the_charlcd = lcd;
659         register_reboot_notifier(&panel_notifier);
660         return 0;
661 }
662 EXPORT_SYMBOL_GPL(charlcd_register);
663
664 int charlcd_unregister(struct charlcd *lcd)
665 {
666         struct charlcd_priv *priv = charlcd_to_priv(lcd);
667
668         unregister_reboot_notifier(&panel_notifier);
669         charlcd_puts(lcd, "\x0cLCD driver unloaded.\x1b[Lc\x1b[Lb\x1b[L-");
670         misc_deregister(&charlcd_dev);
671         the_charlcd = NULL;
672         if (lcd->ops->backlight) {
673                 cancel_delayed_work_sync(&priv->bl_work);
674                 priv->lcd.ops->backlight(&priv->lcd, CHARLCD_OFF);
675         }
676
677         return 0;
678 }
679 EXPORT_SYMBOL_GPL(charlcd_unregister);
680
681 MODULE_LICENSE("GPL");