| .. | .. |
|---|
| 20 | 20 | |
|---|
| 21 | 21 | #include <generated/utsrelease.h> |
|---|
| 22 | 22 | |
|---|
| 23 | | -#include <misc/charlcd.h> |
|---|
| 24 | | - |
|---|
| 25 | | -#define LCD_MINOR 156 |
|---|
| 23 | +#include "charlcd.h" |
|---|
| 26 | 24 | |
|---|
| 27 | 25 | #define DEFAULT_LCD_BWIDTH 40 |
|---|
| 28 | 26 | #define DEFAULT_LCD_HWIDTH 64 |
|---|
| .. | .. |
|---|
| 88 | 86 | int len; |
|---|
| 89 | 87 | } esc_seq; |
|---|
| 90 | 88 | |
|---|
| 91 | | - unsigned long long drvdata[0]; |
|---|
| 89 | + unsigned long long drvdata[]; |
|---|
| 92 | 90 | }; |
|---|
| 93 | 91 | |
|---|
| 94 | | -#define to_priv(p) container_of(p, struct charlcd_priv, lcd) |
|---|
| 92 | +#define charlcd_to_priv(p) container_of(p, struct charlcd_priv, lcd) |
|---|
| 95 | 93 | |
|---|
| 96 | 94 | /* Device single-open policy control */ |
|---|
| 97 | 95 | static atomic_t charlcd_available = ATOMIC_INIT(1); |
|---|
| .. | .. |
|---|
| 105 | 103 | /* turn the backlight on or off */ |
|---|
| 106 | 104 | static void charlcd_backlight(struct charlcd *lcd, int on) |
|---|
| 107 | 105 | { |
|---|
| 108 | | - struct charlcd_priv *priv = to_priv(lcd); |
|---|
| 106 | + struct charlcd_priv *priv = charlcd_to_priv(lcd); |
|---|
| 109 | 107 | |
|---|
| 110 | 108 | if (!lcd->ops->backlight) |
|---|
| 111 | 109 | return; |
|---|
| .. | .. |
|---|
| 134 | 132 | /* turn the backlight on for a little while */ |
|---|
| 135 | 133 | void charlcd_poke(struct charlcd *lcd) |
|---|
| 136 | 134 | { |
|---|
| 137 | | - struct charlcd_priv *priv = to_priv(lcd); |
|---|
| 135 | + struct charlcd_priv *priv = charlcd_to_priv(lcd); |
|---|
| 138 | 136 | |
|---|
| 139 | 137 | if (!lcd->ops->backlight) |
|---|
| 140 | 138 | return; |
|---|
| .. | .. |
|---|
| 152 | 150 | |
|---|
| 153 | 151 | static void charlcd_gotoxy(struct charlcd *lcd) |
|---|
| 154 | 152 | { |
|---|
| 155 | | - struct charlcd_priv *priv = to_priv(lcd); |
|---|
| 153 | + struct charlcd_priv *priv = charlcd_to_priv(lcd); |
|---|
| 156 | 154 | unsigned int addr; |
|---|
| 157 | 155 | |
|---|
| 158 | 156 | /* |
|---|
| .. | .. |
|---|
| 170 | 168 | |
|---|
| 171 | 169 | static void charlcd_home(struct charlcd *lcd) |
|---|
| 172 | 170 | { |
|---|
| 173 | | - struct charlcd_priv *priv = to_priv(lcd); |
|---|
| 171 | + struct charlcd_priv *priv = charlcd_to_priv(lcd); |
|---|
| 174 | 172 | |
|---|
| 175 | 173 | priv->addr.x = 0; |
|---|
| 176 | 174 | priv->addr.y = 0; |
|---|
| .. | .. |
|---|
| 179 | 177 | |
|---|
| 180 | 178 | static void charlcd_print(struct charlcd *lcd, char c) |
|---|
| 181 | 179 | { |
|---|
| 182 | | - struct charlcd_priv *priv = to_priv(lcd); |
|---|
| 180 | + struct charlcd_priv *priv = charlcd_to_priv(lcd); |
|---|
| 183 | 181 | |
|---|
| 184 | 182 | if (priv->addr.x < lcd->bwidth) { |
|---|
| 185 | 183 | if (lcd->char_conv) |
|---|
| .. | .. |
|---|
| 211 | 209 | /* clears the display and resets X/Y */ |
|---|
| 212 | 210 | static void charlcd_clear_display(struct charlcd *lcd) |
|---|
| 213 | 211 | { |
|---|
| 214 | | - struct charlcd_priv *priv = to_priv(lcd); |
|---|
| 212 | + struct charlcd_priv *priv = charlcd_to_priv(lcd); |
|---|
| 215 | 213 | |
|---|
| 216 | 214 | lcd->ops->write_cmd(lcd, LCD_CMD_DISPLAY_CLEAR); |
|---|
| 217 | 215 | priv->addr.x = 0; |
|---|
| .. | .. |
|---|
| 223 | 221 | static int charlcd_init_display(struct charlcd *lcd) |
|---|
| 224 | 222 | { |
|---|
| 225 | 223 | void (*write_cmd_raw)(struct charlcd *lcd, int cmd); |
|---|
| 226 | | - struct charlcd_priv *priv = to_priv(lcd); |
|---|
| 224 | + struct charlcd_priv *priv = charlcd_to_priv(lcd); |
|---|
| 227 | 225 | u8 init; |
|---|
| 228 | 226 | |
|---|
| 229 | 227 | if (lcd->ifwidth != 4 && lcd->ifwidth != 8) |
|---|
| .. | .. |
|---|
| 288 | 286 | } |
|---|
| 289 | 287 | |
|---|
| 290 | 288 | /* |
|---|
| 291 | | - * Parses an unsigned integer from a string, until a non-digit character |
|---|
| 292 | | - * is found. The empty string is not accepted. No overflow checks are done. |
|---|
| 293 | | - * |
|---|
| 294 | | - * Returns whether the parsing was successful. Only in that case |
|---|
| 295 | | - * the output parameters are written to. |
|---|
| 296 | | - * |
|---|
| 297 | | - * TODO: If the kernel adds an inplace version of kstrtoul(), this function |
|---|
| 298 | | - * could be easily replaced by that. |
|---|
| 299 | | - */ |
|---|
| 300 | | -static bool parse_n(const char *s, unsigned long *res, const char **next_s) |
|---|
| 301 | | -{ |
|---|
| 302 | | - if (!isdigit(*s)) |
|---|
| 303 | | - return false; |
|---|
| 304 | | - |
|---|
| 305 | | - *res = 0; |
|---|
| 306 | | - while (isdigit(*s)) { |
|---|
| 307 | | - *res = *res * 10 + (*s - '0'); |
|---|
| 308 | | - ++s; |
|---|
| 309 | | - } |
|---|
| 310 | | - |
|---|
| 311 | | - *next_s = s; |
|---|
| 312 | | - return true; |
|---|
| 313 | | -} |
|---|
| 314 | | - |
|---|
| 315 | | -/* |
|---|
| 316 | 289 | * Parses a movement command of the form "(.*);", where the group can be |
|---|
| 317 | 290 | * any number of subcommands of the form "(x|y)[0-9]+". |
|---|
| 318 | 291 | * |
|---|
| .. | .. |
|---|
| 336 | 309 | { |
|---|
| 337 | 310 | unsigned long new_x = *x; |
|---|
| 338 | 311 | unsigned long new_y = *y; |
|---|
| 312 | + char *p; |
|---|
| 339 | 313 | |
|---|
| 340 | 314 | for (;;) { |
|---|
| 341 | 315 | if (!*s) |
|---|
| .. | .. |
|---|
| 345 | 319 | break; |
|---|
| 346 | 320 | |
|---|
| 347 | 321 | if (*s == 'x') { |
|---|
| 348 | | - if (!parse_n(s + 1, &new_x, &s)) |
|---|
| 322 | + new_x = simple_strtoul(s + 1, &p, 10); |
|---|
| 323 | + if (p == s + 1) |
|---|
| 349 | 324 | return false; |
|---|
| 325 | + s = p; |
|---|
| 350 | 326 | } else if (*s == 'y') { |
|---|
| 351 | | - if (!parse_n(s + 1, &new_y, &s)) |
|---|
| 327 | + new_y = simple_strtoul(s + 1, &p, 10); |
|---|
| 328 | + if (p == s + 1) |
|---|
| 352 | 329 | return false; |
|---|
| 330 | + s = p; |
|---|
| 353 | 331 | } else { |
|---|
| 354 | 332 | return false; |
|---|
| 355 | 333 | } |
|---|
| .. | .. |
|---|
| 369 | 347 | |
|---|
| 370 | 348 | static inline int handle_lcd_special_code(struct charlcd *lcd) |
|---|
| 371 | 349 | { |
|---|
| 372 | | - struct charlcd_priv *priv = to_priv(lcd); |
|---|
| 350 | + struct charlcd_priv *priv = charlcd_to_priv(lcd); |
|---|
| 373 | 351 | |
|---|
| 374 | 352 | /* LCD special codes */ |
|---|
| 375 | 353 | |
|---|
| .. | .. |
|---|
| 507 | 485 | shift = 0; |
|---|
| 508 | 486 | value = 0; |
|---|
| 509 | 487 | while (*esc && cgoffset < 8) { |
|---|
| 510 | | - shift ^= 4; |
|---|
| 511 | | - if (*esc >= '0' && *esc <= '9') { |
|---|
| 512 | | - value |= (*esc - '0') << shift; |
|---|
| 513 | | - } else if (*esc >= 'A' && *esc <= 'F') { |
|---|
| 514 | | - value |= (*esc - 'A' + 10) << shift; |
|---|
| 515 | | - } else if (*esc >= 'a' && *esc <= 'f') { |
|---|
| 516 | | - value |= (*esc - 'a' + 10) << shift; |
|---|
| 517 | | - } else { |
|---|
| 518 | | - esc++; |
|---|
| 519 | | - continue; |
|---|
| 520 | | - } |
|---|
| 488 | + int half; |
|---|
| 521 | 489 | |
|---|
| 490 | + shift ^= 4; |
|---|
| 491 | + |
|---|
| 492 | + half = hex_to_bin(*esc++); |
|---|
| 493 | + if (half < 0) |
|---|
| 494 | + continue; |
|---|
| 495 | + |
|---|
| 496 | + value |= half << shift; |
|---|
| 522 | 497 | if (shift == 0) { |
|---|
| 523 | 498 | cgbytes[cgoffset++] = value; |
|---|
| 524 | 499 | value = 0; |
|---|
| 525 | 500 | } |
|---|
| 526 | | - |
|---|
| 527 | | - esc++; |
|---|
| 528 | 501 | } |
|---|
| 529 | 502 | |
|---|
| 530 | 503 | lcd->ops->write_cmd(lcd, LCD_CMD_SET_CGRAM_ADDR | (cgaddr * 8)); |
|---|
| .. | .. |
|---|
| 580 | 553 | |
|---|
| 581 | 554 | static void charlcd_write_char(struct charlcd *lcd, char c) |
|---|
| 582 | 555 | { |
|---|
| 583 | | - struct charlcd_priv *priv = to_priv(lcd); |
|---|
| 556 | + struct charlcd_priv *priv = charlcd_to_priv(lcd); |
|---|
| 584 | 557 | |
|---|
| 585 | 558 | /* first, we'll test if we're in escape mode */ |
|---|
| 586 | 559 | if ((c != '\n') && priv->esc_seq.len >= 0) { |
|---|
| .. | .. |
|---|
| 705 | 678 | |
|---|
| 706 | 679 | static int charlcd_open(struct inode *inode, struct file *file) |
|---|
| 707 | 680 | { |
|---|
| 708 | | - struct charlcd_priv *priv = to_priv(the_charlcd); |
|---|
| 681 | + struct charlcd_priv *priv = charlcd_to_priv(the_charlcd); |
|---|
| 709 | 682 | int ret; |
|---|
| 710 | 683 | |
|---|
| 711 | 684 | ret = -EBUSY; |
|---|
| .. | .. |
|---|
| 763 | 736 | } |
|---|
| 764 | 737 | } |
|---|
| 765 | 738 | |
|---|
| 739 | +#ifdef CONFIG_PANEL_BOOT_MESSAGE |
|---|
| 740 | +#define LCD_INIT_TEXT CONFIG_PANEL_BOOT_MESSAGE |
|---|
| 741 | +#else |
|---|
| 742 | +#define LCD_INIT_TEXT "Linux-" UTS_RELEASE "\n" |
|---|
| 743 | +#endif |
|---|
| 744 | + |
|---|
| 745 | +#ifdef CONFIG_CHARLCD_BL_ON |
|---|
| 746 | +#define LCD_INIT_BL "\x1b[L+" |
|---|
| 747 | +#elif defined(CONFIG_CHARLCD_BL_FLASH) |
|---|
| 748 | +#define LCD_INIT_BL "\x1b[L*" |
|---|
| 749 | +#else |
|---|
| 750 | +#define LCD_INIT_BL "\x1b[L-" |
|---|
| 751 | +#endif |
|---|
| 752 | + |
|---|
| 766 | 753 | /* initialize the LCD driver */ |
|---|
| 767 | 754 | static int charlcd_init(struct charlcd *lcd) |
|---|
| 768 | 755 | { |
|---|
| 769 | | - struct charlcd_priv *priv = to_priv(lcd); |
|---|
| 756 | + struct charlcd_priv *priv = charlcd_to_priv(lcd); |
|---|
| 770 | 757 | int ret; |
|---|
| 771 | 758 | |
|---|
| 772 | 759 | if (lcd->ops->backlight) { |
|---|
| .. | .. |
|---|
| 784 | 771 | return ret; |
|---|
| 785 | 772 | |
|---|
| 786 | 773 | /* display a short message */ |
|---|
| 787 | | -#ifdef CONFIG_PANEL_CHANGE_MESSAGE |
|---|
| 788 | | -#ifdef CONFIG_PANEL_BOOT_MESSAGE |
|---|
| 789 | | - charlcd_puts(lcd, "\x1b[Lc\x1b[Lb\x1b[L*" CONFIG_PANEL_BOOT_MESSAGE); |
|---|
| 790 | | -#endif |
|---|
| 791 | | -#else |
|---|
| 792 | | - charlcd_puts(lcd, "\x1b[Lc\x1b[Lb\x1b[L*Linux-" UTS_RELEASE "\n"); |
|---|
| 793 | | -#endif |
|---|
| 774 | + charlcd_puts(lcd, "\x1b[Lc\x1b[Lb" LCD_INIT_BL LCD_INIT_TEXT); |
|---|
| 775 | + |
|---|
| 794 | 776 | /* clear the display on the next device opening */ |
|---|
| 795 | 777 | priv->must_clear = true; |
|---|
| 796 | 778 | charlcd_home(lcd); |
|---|
| .. | .. |
|---|
| 817 | 799 | return lcd; |
|---|
| 818 | 800 | } |
|---|
| 819 | 801 | EXPORT_SYMBOL_GPL(charlcd_alloc); |
|---|
| 802 | + |
|---|
| 803 | +void charlcd_free(struct charlcd *lcd) |
|---|
| 804 | +{ |
|---|
| 805 | + kfree(charlcd_to_priv(lcd)); |
|---|
| 806 | +} |
|---|
| 807 | +EXPORT_SYMBOL_GPL(charlcd_free); |
|---|
| 820 | 808 | |
|---|
| 821 | 809 | static int panel_notify_sys(struct notifier_block *this, unsigned long code, |
|---|
| 822 | 810 | void *unused) |
|---|
| .. | .. |
|---|
| 866 | 854 | |
|---|
| 867 | 855 | int charlcd_unregister(struct charlcd *lcd) |
|---|
| 868 | 856 | { |
|---|
| 869 | | - struct charlcd_priv *priv = to_priv(lcd); |
|---|
| 857 | + struct charlcd_priv *priv = charlcd_to_priv(lcd); |
|---|
| 870 | 858 | |
|---|
| 871 | 859 | unregister_reboot_notifier(&panel_notifier); |
|---|
| 872 | 860 | charlcd_puts(lcd, "\x0cLCD driver unloaded.\x1b[Lc\x1b[Lb\x1b[L-"); |
|---|