Lines Matching +full:lcd +full:- +full:bl
1 // SPDX-License-Identifier: GPL-2.0+
4 * Copyright (C) 2000-2008, Willy Tarreau <w@1wt.eu>
5 * Copyright (C) 2016-2017 Glider bvba
7 * This code drives an LCD module (/dev/lcd), and a keypad (/dev/keypad)
10 * The LCD module may either be an HD44780-like 8-bit parallel LCD, or a 1-bit
15 * data output pins or to the ground. The combinations have to be hard-coded
18 * Several profiles are provided for commonly found LCD+keypad modules on the
22 * - the initialization/deinitialization process is very dirty and should
26 * - document 24 keys keyboard (3 rows of 8 cols, 32 diodes + 2 inputs)
27 * - make the LCD a part of a virtual screen of Vx*Vy
28 * - make the inputs list smp-safe
29 * - change the keyboard to a double mapping : signals -> key_id -> values
80 #define PNL_PBIDIR 0x20 /* bi-directional ports */
81 /* high to read data in or-ed with data out */
112 #define NOT_SET -1
115 #define r_ctr(x) (parport_read_control((x)->port))
116 #define r_dtr(x) (parport_read_data((x)->port))
117 #define r_str(x) (parport_read_status((x)->port))
118 #define w_ctr(x, y) (parport_write_control((x)->port, (y)))
119 #define w_dtr(x, y) (parport_write_data((x)->port, (y)))
173 * <-----unused------><gnd><d07><d06><d05><d04><d03><d02><d01><d00>
198 /* lcd-specific variables */
213 int bl; member
217 } lcd; variable
223 * Bit masks to convert LCD signals to parallel port outputs.
232 * one entry for each bit on the LCD
252 * LCD protocols
259 * LCD character sets
265 * LCD types
398 /* Device single-open policy control */
408 MODULE_DESCRIPTION("Generic parallel port LCD/Keypad driver");
428 "LCD type: 0=none, 1=compiled-in, 2=old, 3=serial ks0074, 4=hantronix, 5=nexcom");
432 MODULE_PARM_DESC(lcd_height, "Number of lines on the LCD");
436 MODULE_PARM_DESC(lcd_width, "Number of columns on the LCD");
440 MODULE_PARM_DESC(lcd_bwidth, "Internal LCD line width (40)");
444 MODULE_PARM_DESC(lcd_hwidth, "LCD line hardware address (64)");
448 MODULE_PARM_DESC(lcd_charset, "LCD character set: 0=standard, 1=KS0074");
453 "LCD communication: 0=parallel (//), 1=serial, 2=TI LCD Interface");
456 * These are the parallel port pins the LCD control signals are connected to.
458 * (negative) if the signal is negated. -MAXINT is used to indicate that the
467 "# of the // port pin connected to LCD 'E' signal, with polarity (-17..17)");
472 "# of the // port pin connected to LCD 'RS' signal, with polarity (-17..17)");
477 "# of the // port pin connected to LCD 'RW' signal, with polarity (-17..17)");
482 "# of the // port pin connected to serial LCD 'SCL' signal, with polarity (-17..17)");
487 "# of the // port pin connected to serial LCD 'SDA' signal, with polarity (-17..17)");
492 "# of the // port pin connected to LCD backlight, with polarity (-17..17)");
494 /* Deprecated module parameters - consider not using them anymore */
504 /* for some LCD drivers (ks0074) we need a charset conversion table. */
566 {"a-p-e-", "Down\n", "Down\n", ""},
567 {"a-p-E-", "Ret\n", "Ret\n", ""},
568 {"a-P-E-", "Esc\n", "Esc\n", ""},
569 {"a-P-e-", "Up\n", "Up\n", ""},
619 * Converts a parallel port pin (from -25 to 25) to data and control ports
621 * unconnected if it's on pin 0 or an invalid pin (<-25 or >25).
643 pin = -pin; in pin_to_bits()
653 case PIN_D0...PIN_D7: /* D0 - D7 = 2 - 9 */ in pin_to_bits()
654 d_bit = 1 << (pin - 2); in pin_to_bits()
681 * send a serial byte to the LCD panel. The caller is responsible for locking
690 * LCD reads D0 on STROBE's rising edge. in lcd_send_serial()
713 if (lcd.pins.bl == PIN_NONE) in lcd_backlight()
726 /* send a command to the LCD panel in serial mode */
737 /* send data to the LCD panel in serial mode */
748 /* send a command to the LCD panel in 8 bits parallel mode */
770 /* send data to the LCD panel in 8 bits parallel mode */
792 /* send a command to the TI LCD panel */
802 /* send data to the TI LCD panel */
818 for (pos = 0; pos < charlcd->height * charlcd->hwidth; pos++) { in lcd_clear_fast_s()
834 for (pos = 0; pos < charlcd->height * charlcd->hwidth; pos++) { in lcd_clear_fast_p8()
864 for (pos = 0; pos < charlcd->height * charlcd->hwidth; pos++) { in lcd_clear_fast_tilcd()
894 /* initialize the LCD driver */
904 * Init lcd struct with load-time values to preserve exact in lcd_init()
907 charlcd->height = lcd_height; in lcd_init()
908 charlcd->width = lcd_width; in lcd_init()
909 charlcd->bwidth = lcd_bwidth; in lcd_init()
910 charlcd->hwidth = lcd_hwidth; in lcd_init()
915 lcd.proto = LCD_PROTO_PARALLEL; in lcd_init()
916 lcd.charset = LCD_CHARSET_NORMAL; in lcd_init()
917 lcd.pins.e = PIN_STROBE; in lcd_init()
918 lcd.pins.rs = PIN_AUTOLF; in lcd_init()
920 charlcd->width = 40; in lcd_init()
921 charlcd->bwidth = 40; in lcd_init()
922 charlcd->hwidth = 64; in lcd_init()
923 charlcd->height = 2; in lcd_init()
927 lcd.proto = LCD_PROTO_SERIAL; in lcd_init()
928 lcd.charset = LCD_CHARSET_KS0074; in lcd_init()
929 lcd.pins.bl = PIN_AUTOLF; in lcd_init()
930 lcd.pins.cl = PIN_STROBE; in lcd_init()
931 lcd.pins.da = PIN_D0; in lcd_init()
933 charlcd->width = 16; in lcd_init()
934 charlcd->bwidth = 40; in lcd_init()
935 charlcd->hwidth = 16; in lcd_init()
936 charlcd->height = 2; in lcd_init()
940 lcd.proto = LCD_PROTO_PARALLEL; in lcd_init()
941 lcd.charset = LCD_CHARSET_NORMAL; in lcd_init()
942 lcd.pins.e = PIN_AUTOLF; in lcd_init()
943 lcd.pins.rs = PIN_SELECP; in lcd_init()
944 lcd.pins.rw = PIN_INITP; in lcd_init()
946 charlcd->width = 16; in lcd_init()
947 charlcd->bwidth = 40; in lcd_init()
948 charlcd->hwidth = 64; in lcd_init()
949 charlcd->height = 2; in lcd_init()
952 /* customer-defined */ in lcd_init()
953 lcd.proto = DEFAULT_LCD_PROTO; in lcd_init()
954 lcd.charset = DEFAULT_LCD_CHARSET; in lcd_init()
958 /* parallel mode, 8 bits, hantronix-like */ in lcd_init()
960 lcd.proto = LCD_PROTO_PARALLEL; in lcd_init()
961 lcd.charset = LCD_CHARSET_NORMAL; in lcd_init()
962 lcd.pins.e = PIN_STROBE; in lcd_init()
963 lcd.pins.rs = PIN_SELECP; in lcd_init()
965 charlcd->width = 16; in lcd_init()
966 charlcd->bwidth = 40; in lcd_init()
967 charlcd->hwidth = 64; in lcd_init()
968 charlcd->height = 2; in lcd_init()
974 charlcd->height = lcd_height; in lcd_init()
976 charlcd->width = lcd_width; in lcd_init()
978 charlcd->bwidth = lcd_bwidth; in lcd_init()
980 charlcd->hwidth = lcd_hwidth; in lcd_init()
982 lcd.charset = lcd_charset; in lcd_init()
984 lcd.proto = lcd_proto; in lcd_init()
986 lcd.pins.e = lcd_e_pin; in lcd_init()
988 lcd.pins.rs = lcd_rs_pin; in lcd_init()
990 lcd.pins.rw = lcd_rw_pin; in lcd_init()
992 lcd.pins.cl = lcd_cl_pin; in lcd_init()
994 lcd.pins.da = lcd_da_pin; in lcd_init()
996 lcd.pins.bl = lcd_bl_pin; in lcd_init()
999 if (charlcd->width <= 0) in lcd_init()
1000 charlcd->width = DEFAULT_LCD_WIDTH; in lcd_init()
1001 if (charlcd->bwidth <= 0) in lcd_init()
1002 charlcd->bwidth = DEFAULT_LCD_BWIDTH; in lcd_init()
1003 if (charlcd->hwidth <= 0) in lcd_init()
1004 charlcd->hwidth = DEFAULT_LCD_HWIDTH; in lcd_init()
1005 if (charlcd->height <= 0) in lcd_init()
1006 charlcd->height = DEFAULT_LCD_HEIGHT; in lcd_init()
1008 if (lcd.proto == LCD_PROTO_SERIAL) { /* SERIAL */ in lcd_init()
1009 charlcd->ops = &charlcd_serial_ops; in lcd_init()
1011 if (lcd.pins.cl == PIN_NOT_SET) in lcd_init()
1012 lcd.pins.cl = DEFAULT_LCD_PIN_SCL; in lcd_init()
1013 if (lcd.pins.da == PIN_NOT_SET) in lcd_init()
1014 lcd.pins.da = DEFAULT_LCD_PIN_SDA; in lcd_init()
1016 } else if (lcd.proto == LCD_PROTO_PARALLEL) { /* PARALLEL */ in lcd_init()
1017 charlcd->ops = &charlcd_parallel_ops; in lcd_init()
1019 if (lcd.pins.e == PIN_NOT_SET) in lcd_init()
1020 lcd.pins.e = DEFAULT_LCD_PIN_E; in lcd_init()
1021 if (lcd.pins.rs == PIN_NOT_SET) in lcd_init()
1022 lcd.pins.rs = DEFAULT_LCD_PIN_RS; in lcd_init()
1023 if (lcd.pins.rw == PIN_NOT_SET) in lcd_init()
1024 lcd.pins.rw = DEFAULT_LCD_PIN_RW; in lcd_init()
1026 charlcd->ops = &charlcd_tilcd_ops; in lcd_init()
1029 if (lcd.pins.bl == PIN_NOT_SET) in lcd_init()
1030 lcd.pins.bl = DEFAULT_LCD_PIN_BL; in lcd_init()
1032 if (lcd.pins.e == PIN_NOT_SET) in lcd_init()
1033 lcd.pins.e = PIN_NONE; in lcd_init()
1034 if (lcd.pins.rs == PIN_NOT_SET) in lcd_init()
1035 lcd.pins.rs = PIN_NONE; in lcd_init()
1036 if (lcd.pins.rw == PIN_NOT_SET) in lcd_init()
1037 lcd.pins.rw = PIN_NONE; in lcd_init()
1038 if (lcd.pins.bl == PIN_NOT_SET) in lcd_init()
1039 lcd.pins.bl = PIN_NONE; in lcd_init()
1040 if (lcd.pins.cl == PIN_NOT_SET) in lcd_init()
1041 lcd.pins.cl = PIN_NONE; in lcd_init()
1042 if (lcd.pins.da == PIN_NOT_SET) in lcd_init()
1043 lcd.pins.da = PIN_NONE; in lcd_init()
1045 if (lcd.charset == NOT_SET) in lcd_init()
1046 lcd.charset = DEFAULT_LCD_CHARSET; in lcd_init()
1048 if (lcd.charset == LCD_CHARSET_KS0074) in lcd_init()
1049 charlcd->char_conv = lcd_char_conv_ks0074; in lcd_init()
1051 charlcd->char_conv = NULL; in lcd_init()
1053 pin_to_bits(lcd.pins.e, lcd_bits[LCD_PORT_D][LCD_BIT_E], in lcd_init()
1055 pin_to_bits(lcd.pins.rs, lcd_bits[LCD_PORT_D][LCD_BIT_RS], in lcd_init()
1057 pin_to_bits(lcd.pins.rw, lcd_bits[LCD_PORT_D][LCD_BIT_RW], in lcd_init()
1059 pin_to_bits(lcd.pins.bl, lcd_bits[LCD_PORT_D][LCD_BIT_BL], in lcd_init()
1061 pin_to_bits(lcd.pins.cl, lcd_bits[LCD_PORT_D][LCD_BIT_CL], in lcd_init()
1063 pin_to_bits(lcd.pins.da, lcd_bits[LCD_PORT_D][LCD_BIT_DA], in lcd_init()
1066 lcd.charlcd = charlcd; in lcd_init()
1067 lcd.initialized = true; in lcd_init()
1081 if (file->f_flags & O_NONBLOCK) in keypad_read()
1082 return -EAGAIN; in keypad_read()
1086 return -EINTR; in keypad_read()
1089 for (; count-- > 0 && (keypad_buflen > 0); in keypad_read()
1090 ++i, ++tmp, --keypad_buflen) { in keypad_read()
1096 return tmp - buf; in keypad_read()
1103 ret = -EBUSY; in keypad_open()
1107 ret = -EPERM; in keypad_open()
1108 if (file->f_mode & FMODE_WRITE) /* device is read-only */ in keypad_open()
1141 while (max_len-- && keypad_buflen < KEYPAD_BUFFER && *string) { in keypad_send_key()
1187 /* grounded inputs are signals 40-44 */ in phys_scan_contacts()
1221 * transitions from single-key to multiple-key, but in input_state_high()
1234 * eg: 0 -(press A)-> A -(press B)-> AB : don't match A's release. in input_state_high()
1236 if (((phys_prev & input->mask) == input->value) && in input_state_high()
1237 ((phys_curr & input->mask) > input->value)) { in input_state_high()
1238 input->state = INPUT_ST_LOW; /* invalidate */ in input_state_high()
1243 if ((phys_curr & input->mask) == input->value) { in input_state_high()
1244 if ((input->type == INPUT_TYPE_STD) && in input_state_high()
1245 (input->high_timer == 0)) { in input_state_high()
1246 input->high_timer++; in input_state_high()
1247 if (input->u.std.press_fct) in input_state_high()
1248 input->u.std.press_fct(input->u.std.press_data); in input_state_high()
1249 } else if (input->type == INPUT_TYPE_KBD) { in input_state_high()
1253 if (input->high_timer == 0) { in input_state_high()
1254 char *press_str = input->u.kbd.press_str; in input_state_high()
1257 int s = sizeof(input->u.kbd.press_str); in input_state_high()
1263 if (input->u.kbd.repeat_str[0]) { in input_state_high()
1264 char *repeat_str = input->u.kbd.repeat_str; in input_state_high()
1266 if (input->high_timer >= KEYPAD_REP_START) { in input_state_high()
1267 int s = sizeof(input->u.kbd.repeat_str); in input_state_high()
1269 input->high_timer -= KEYPAD_REP_DELAY; in input_state_high()
1276 if (input->high_timer < 255) in input_state_high()
1277 input->high_timer++; in input_state_high()
1283 input->state = INPUT_ST_FALLING; in input_state_high()
1284 input->fall_timer = 0; in input_state_high()
1293 if (((phys_prev & input->mask) == input->value) && in input_state_falling()
1294 ((phys_curr & input->mask) > input->value)) { in input_state_falling()
1295 input->state = INPUT_ST_LOW; /* invalidate */ in input_state_falling()
1300 if ((phys_curr & input->mask) == input->value) { in input_state_falling()
1301 if (input->type == INPUT_TYPE_KBD) { in input_state_falling()
1305 if (input->u.kbd.repeat_str[0]) { in input_state_falling()
1306 char *repeat_str = input->u.kbd.repeat_str; in input_state_falling()
1308 if (input->high_timer >= KEYPAD_REP_START) { in input_state_falling()
1309 int s = sizeof(input->u.kbd.repeat_str); in input_state_falling()
1311 input->high_timer -= KEYPAD_REP_DELAY; in input_state_falling()
1318 if (input->high_timer < 255) in input_state_falling()
1319 input->high_timer++; in input_state_falling()
1321 input->state = INPUT_ST_HIGH; in input_state_falling()
1322 } else if (input->fall_timer >= input->fall_time) { in input_state_falling()
1324 if (input->type == INPUT_TYPE_STD) { in input_state_falling()
1325 void (*release_fct)(int) = input->u.std.release_fct; in input_state_falling()
1328 release_fct(input->u.std.release_data); in input_state_falling()
1329 } else if (input->type == INPUT_TYPE_KBD) { in input_state_falling()
1330 char *release_str = input->u.kbd.release_str; in input_state_falling()
1333 int s = sizeof(input->u.kbd.release_str); in input_state_falling()
1339 input->state = INPUT_ST_LOW; in input_state_falling()
1341 input->fall_timer++; in input_state_falling()
1353 switch (input->state) { in panel_process_inputs()
1355 if ((phys_curr & input->mask) != input->value) in panel_process_inputs()
1361 * eg: AB -(release B)-> A -(release A)-> 0 : in panel_process_inputs()
1364 if ((phys_prev & input->mask) == input->value) in panel_process_inputs()
1366 input->rise_timer = 0; in panel_process_inputs()
1367 input->state = INPUT_ST_RISING; in panel_process_inputs()
1370 if ((phys_curr & input->mask) != input->value) { in panel_process_inputs()
1371 input->state = INPUT_ST_LOW; in panel_process_inputs()
1374 if (input->rise_timer < input->rise_time) { in panel_process_inputs()
1376 input->rise_timer++; in panel_process_inputs()
1379 input->high_timer = 0; in panel_process_inputs()
1380 input->state = INPUT_ST_HIGH; in panel_process_inputs()
1406 if (keypressed && lcd.enabled && lcd.initialized) in panel_scan_timer()
1407 charlcd_poke(lcd.charlcd); in panel_scan_timer()
1422 /* converts a name of the form "({BbAaPpSsEe}{01234567-})*" to a series of bits.
1423 * if <omask> or <imask> are non-null, they will be or'ed with the bits
1446 in = idx - sigtab; in input_name2mask()
1453 out = *name - '0'; in input_name2mask()
1455 } else if (*name == '-') { in input_name2mask()
1491 if (!input_name2mask(name, &key->mask, &key->value, &scan_mask_i, in panel_bind_key()
1497 key->type = INPUT_TYPE_KBD; in panel_bind_key()
1498 key->state = INPUT_ST_LOW; in panel_bind_key()
1499 key->rise_time = 1; in panel_bind_key()
1500 key->fall_time = 1; in panel_bind_key()
1502 strncpy(key->u.kbd.press_str, press, sizeof(key->u.kbd.press_str)); in panel_bind_key()
1503 strncpy(key->u.kbd.repeat_str, repeat, sizeof(key->u.kbd.repeat_str)); in panel_bind_key()
1504 strncpy(key->u.kbd.release_str, release, in panel_bind_key()
1505 sizeof(key->u.kbd.release_str)); in panel_bind_key()
1506 list_add(&key->list, &logical_inputs); in panel_bind_key()
1530 if (!input_name2mask(name, &callback->mask, &callback->value,
1534 callback->type = INPUT_TYPE_STD;
1535 callback->state = INPUT_ST_LOW;
1536 callback->rise_time = 1;
1537 callback->fall_time = 1;
1538 callback->u.std.press_fct = press_fct;
1539 callback->u.std.press_data = press_data;
1540 callback->u.std.release_fct = release_fct;
1541 callback->u.std.release_data = release_data;
1542 list_add(&callback->list, &logical_inputs);
1575 if (port->number != parport) in panel_attach()
1579 pr_err("%s: port->number=%d parport=%d, already registered!\n", in panel_attach()
1580 __func__, port->number, parport); in panel_attach()
1590 pr_err("%s: port->number=%d parport=%d, parport_register_device() failed\n", in panel_attach()
1591 __func__, port->number, parport); in panel_attach()
1601 /* must init LCD first, just in case an IRQ from the keypad is in panel_attach()
1604 if (lcd.enabled) { in panel_attach()
1606 if (!lcd.charlcd || charlcd_register(lcd.charlcd)) in panel_attach()
1620 if (lcd.enabled) in panel_attach()
1621 charlcd_unregister(lcd.charlcd); in panel_attach()
1623 charlcd_free(lcd.charlcd); in panel_attach()
1624 lcd.charlcd = NULL; in panel_attach()
1631 if (port->number != parport) in panel_detach()
1635 pr_err("%s: port->number=%d parport=%d, nothing to unregister.\n", in panel_detach()
1636 __func__, port->number, parport); in panel_detach()
1647 if (lcd.enabled) { in panel_detach()
1648 charlcd_unregister(lcd.charlcd); in panel_detach()
1649 lcd.initialized = false; in panel_detach()
1650 charlcd_free(lcd.charlcd); in panel_detach()
1651 lcd.charlcd = NULL; in panel_detach()
1696 /* 8 bits, 2*16 hantronix-like, no keypad */ in panel_init_module()
1713 * Overwrite selection with module param values (both keypad and lcd), in panel_init_module()
1728 lcd.enabled = (selected_lcd_type > 0); in panel_init_module()
1730 if (lcd.enabled) { in panel_init_module()
1732 * Init lcd struct with load-time values to preserve exact in panel_init_module()
1735 lcd.charset = lcd_charset; in panel_init_module()
1736 lcd.proto = lcd_proto; in panel_init_module()
1737 lcd.pins.e = lcd_e_pin; in panel_init_module()
1738 lcd.pins.rs = lcd_rs_pin; in panel_init_module()
1739 lcd.pins.rw = lcd_rw_pin; in panel_init_module()
1740 lcd.pins.cl = lcd_cl_pin; in panel_init_module()
1741 lcd.pins.da = lcd_da_pin; in panel_init_module()
1742 lcd.pins.bl = lcd_bl_pin; in panel_init_module()
1760 if (!lcd.enabled && !keypad.enabled) { in panel_init_module()
1763 return -ENODEV; in panel_init_module()
1774 parport, pprt->port->base); in panel_init_module()
1792 * c-indent-level: 4
1793 * tab-width: 8