summaryrefslogtreecommitdiffstats
path: root/drivers/misc/panel.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/panel.c')
-rw-r--r--drivers/misc/panel.c191
1 files changed, 96 insertions, 95 deletions
diff --git a/drivers/misc/panel.c b/drivers/misc/panel.c
index 6030ac5b8c63..ef2ece0f26af 100644
--- a/drivers/misc/panel.c
+++ b/drivers/misc/panel.c
@@ -56,6 +56,7 @@
#include <linux/list.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
+#include <linux/workqueue.h>
#include <generated/utsrelease.h>
#include <linux/io.h>
@@ -64,8 +65,6 @@
#define LCD_MINOR 156
#define KEYPAD_MINOR 185
-#define PANEL_VERSION "0.9.5"
-
#define LCD_MAXBYTES 256 /* max burst write */
#define KEYPAD_BUFFER 64
@@ -77,8 +76,8 @@
/* a key repeats this times INPUT_POLL_TIME */
#define KEYPAD_REP_DELAY (2)
-/* keep the light on this times INPUT_POLL_TIME for each flash */
-#define FLASH_LIGHT_TEMPO (200)
+/* keep the light on this many seconds for each flash */
+#define FLASH_LIGHT_TEMPO (4)
/* converts an r_str() input to an active high, bits string : 000BAOSE */
#define PNL_PINPUT(a) ((((unsigned char)(a)) ^ 0x7F) >> 3)
@@ -121,8 +120,6 @@
#define PIN_SELECP 17
#define PIN_NOT_SET 127
-#define LCD_FLAG_S 0x0001
-#define LCD_FLAG_ID 0x0002
#define LCD_FLAG_B 0x0004 /* blink on */
#define LCD_FLAG_C 0x0008 /* cursor on */
#define LCD_FLAG_D 0x0010 /* display on */
@@ -256,7 +253,10 @@ static struct {
int hwidth;
int charset;
int proto;
- int light_tempo;
+
+ struct delayed_work bl_work;
+ struct mutex bl_tempo_lock; /* Protects access to bl_tempo */
+ bool bl_tempo;
/* TODO: use union here? */
struct {
@@ -661,8 +661,6 @@ static void lcd_get_bits(unsigned int port, int *val)
}
}
-static void init_scan_timer(void);
-
/* sets data port bits according to current signals values */
static int set_data_bits(void)
{
@@ -794,11 +792,8 @@ static void lcd_send_serial(int byte)
}
/* turn the backlight on or off */
-static void lcd_backlight(int on)
+static void __lcd_backlight(int on)
{
- if (lcd.pins.bl == PIN_NONE)
- return;
-
/* The backlight is activated by setting the AUTOFEED line to +5V */
spin_lock_irq(&pprt_lock);
if (on)
@@ -809,6 +804,44 @@ static void lcd_backlight(int on)
spin_unlock_irq(&pprt_lock);
}
+static void lcd_backlight(int on)
+{
+ if (lcd.pins.bl == PIN_NONE)
+ return;
+
+ mutex_lock(&lcd.bl_tempo_lock);
+ if (!lcd.bl_tempo)
+ __lcd_backlight(on);
+ mutex_unlock(&lcd.bl_tempo_lock);
+}
+
+static void lcd_bl_off(struct work_struct *work)
+{
+ mutex_lock(&lcd.bl_tempo_lock);
+ if (lcd.bl_tempo) {
+ lcd.bl_tempo = false;
+ if (!(lcd.flags & LCD_FLAG_L))
+ __lcd_backlight(0);
+ }
+ mutex_unlock(&lcd.bl_tempo_lock);
+}
+
+/* turn the backlight on for a little while */
+static void lcd_poke(void)
+{
+ if (lcd.pins.bl == PIN_NONE)
+ return;
+
+ cancel_delayed_work_sync(&lcd.bl_work);
+
+ mutex_lock(&lcd.bl_tempo_lock);
+ if (!lcd.bl_tempo && !(lcd.flags & LCD_FLAG_L))
+ __lcd_backlight(1);
+ lcd.bl_tempo = true;
+ schedule_delayed_work(&lcd.bl_work, FLASH_LIGHT_TEMPO * HZ);
+ mutex_unlock(&lcd.bl_tempo_lock);
+}
+
/* send a command to the LCD panel in serial mode */
static void lcd_write_cmd_s(int cmd)
{
@@ -907,6 +940,13 @@ static void lcd_gotoxy(void)
(lcd.hwidth - 1) : lcd.bwidth - 1));
}
+static void lcd_home(void)
+{
+ lcd.addr.x = 0;
+ lcd.addr.y = 0;
+ lcd_gotoxy();
+}
+
static void lcd_print(char c)
{
if (lcd.addr.x < lcd.bwidth) {
@@ -925,9 +965,7 @@ static void lcd_clear_fast_s(void)
{
int pos;
- lcd.addr.x = 0;
- lcd.addr.y = 0;
- lcd_gotoxy();
+ lcd_home();
spin_lock_irq(&pprt_lock);
for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) {
@@ -939,9 +977,7 @@ static void lcd_clear_fast_s(void)
}
spin_unlock_irq(&pprt_lock);
- lcd.addr.x = 0;
- lcd.addr.y = 0;
- lcd_gotoxy();
+ lcd_home();
}
/* fills the display with spaces and resets X/Y */
@@ -949,9 +985,7 @@ static void lcd_clear_fast_p8(void)
{
int pos;
- lcd.addr.x = 0;
- lcd.addr.y = 0;
- lcd_gotoxy();
+ lcd_home();
spin_lock_irq(&pprt_lock);
for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) {
@@ -977,9 +1011,7 @@ static void lcd_clear_fast_p8(void)
}
spin_unlock_irq(&pprt_lock);
- lcd.addr.x = 0;
- lcd.addr.y = 0;
- lcd_gotoxy();
+ lcd_home();
}
/* fills the display with spaces and resets X/Y */
@@ -987,9 +1019,7 @@ static void lcd_clear_fast_tilcd(void)
{
int pos;
- lcd.addr.x = 0;
- lcd.addr.y = 0;
- lcd_gotoxy();
+ lcd_home();
spin_lock_irq(&pprt_lock);
for (pos = 0; pos < lcd.height * lcd.hwidth; pos++) {
@@ -1000,9 +1030,7 @@ static void lcd_clear_fast_tilcd(void)
spin_unlock_irq(&pprt_lock);
- lcd.addr.x = 0;
- lcd.addr.y = 0;
- lcd_gotoxy();
+ lcd_home();
}
/* clears the display and resets X/Y */
@@ -1108,13 +1136,8 @@ static inline int handle_lcd_special_code(void)
processed = 1;
break;
case '*':
- /* flash back light using the keypad timer */
- if (scan_timer.function) {
- if (lcd.light_tempo == 0 &&
- ((lcd.flags & LCD_FLAG_L) == 0))
- lcd_backlight(1);
- lcd.light_tempo = FLASH_LIGHT_TEMPO;
- }
+ /* flash back light */
+ lcd_poke();
processed = 1;
break;
case 'f': /* Small Font */
@@ -1278,21 +1301,14 @@ static inline int handle_lcd_special_code(void)
lcd_write_cmd(LCD_CMD_FUNCTION_SET
| LCD_CMD_DATA_LEN_8BITS
| ((lcd.flags & LCD_FLAG_F)
- ? LCD_CMD_TWO_LINES : 0)
- | ((lcd.flags & LCD_FLAG_N)
? LCD_CMD_FONT_5X10_DOTS
+ : 0)
+ | ((lcd.flags & LCD_FLAG_N)
+ ? LCD_CMD_TWO_LINES
: 0));
/* check whether L flag was changed */
- else if ((oldflags ^ lcd.flags) & (LCD_FLAG_L)) {
- if (lcd.flags & (LCD_FLAG_L))
- lcd_backlight(1);
- else if (lcd.light_tempo == 0)
- /*
- * switch off the light only when the tempo
- * lighting is gone
- */
- lcd_backlight(0);
- }
+ else if ((oldflags ^ lcd.flags) & (LCD_FLAG_L))
+ lcd_backlight(!!(lcd.flags & LCD_FLAG_L));
}
return processed;
@@ -1376,9 +1392,7 @@ static void lcd_write_char(char c)
processed = 1;
} else if (!strcmp(lcd.esc_seq.buf, "[H")) {
/* cursor to home */
- lcd.addr.x = 0;
- lcd.addr.y = 0;
- lcd_gotoxy();
+ lcd_home();
processed = 1;
}
/* codes starting with ^[[L */
@@ -1625,8 +1639,10 @@ static void lcd_init(void)
else
lcd_char_conv = NULL;
- if (lcd.pins.bl != PIN_NONE)
- init_scan_timer();
+ if (lcd.pins.bl != PIN_NONE) {
+ mutex_init(&lcd.bl_tempo_lock);
+ INIT_DELAYED_WORK(&lcd.bl_work, lcd_bl_off);
+ }
pin_to_bits(lcd.pins.e, lcd_bits[LCD_PORT_D][LCD_BIT_E],
lcd_bits[LCD_PORT_C][LCD_BIT_E]);
@@ -1655,14 +1671,11 @@ static void lcd_init(void)
panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*" CONFIG_PANEL_BOOT_MESSAGE);
#endif
#else
- panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*Linux-" UTS_RELEASE "\nPanel-"
- PANEL_VERSION);
+ panel_lcd_print("\x1b[Lc\x1b[Lb\x1b[L*Linux-" UTS_RELEASE);
#endif
- lcd.addr.x = 0;
- lcd.addr.y = 0;
/* clear the display on the next device opening */
lcd.must_clear = true;
- lcd_gotoxy();
+ lcd_home();
}
/*
@@ -1997,19 +2010,8 @@ static void panel_scan_timer(void)
panel_process_inputs();
}
- if (lcd.enabled && lcd.initialized) {
- if (keypressed) {
- if (lcd.light_tempo == 0 &&
- ((lcd.flags & LCD_FLAG_L) == 0))
- lcd_backlight(1);
- lcd.light_tempo = FLASH_LIGHT_TEMPO;
- } else if (lcd.light_tempo > 0) {
- lcd.light_tempo--;
- if (lcd.light_tempo == 0 &&
- ((lcd.flags & LCD_FLAG_L) == 0))
- lcd_backlight(0);
- }
- }
+ if (keypressed && lcd.enabled && lcd.initialized)
+ lcd_poke();
mod_timer(&scan_timer, jiffies + INPUT_POLL_TIME);
}
@@ -2270,25 +2272,26 @@ static void panel_detach(struct parport *port)
if (scan_timer.function)
del_timer_sync(&scan_timer);
- if (pprt) {
- if (keypad.enabled) {
- misc_deregister(&keypad_dev);
- keypad_initialized = 0;
- }
+ if (keypad.enabled) {
+ misc_deregister(&keypad_dev);
+ keypad_initialized = 0;
+ }
- if (lcd.enabled) {
- panel_lcd_print("\x0cLCD driver " PANEL_VERSION
- "\nunloaded.\x1b[Lc\x1b[Lb\x1b[L-");
- misc_deregister(&lcd_dev);
- lcd.initialized = false;
+ if (lcd.enabled) {
+ panel_lcd_print("\x0cLCD driver unloaded.\x1b[Lc\x1b[Lb\x1b[L-");
+ misc_deregister(&lcd_dev);
+ if (lcd.pins.bl != PIN_NONE) {
+ cancel_delayed_work_sync(&lcd.bl_work);
+ __lcd_backlight(0);
}
-
- /* TODO: free all input signals */
- parport_release(pprt);
- parport_unregister_device(pprt);
- pprt = NULL;
- unregister_reboot_notifier(&panel_notifier);
+ lcd.initialized = false;
}
+
+ /* TODO: free all input signals */
+ parport_release(pprt);
+ parport_unregister_device(pprt);
+ pprt = NULL;
+ unregister_reboot_notifier(&panel_notifier);
}
static struct parport_driver panel_driver = {
@@ -2400,7 +2403,7 @@ static int __init panel_init_module(void)
if (!lcd.enabled && !keypad.enabled) {
/* no device enabled, let's exit */
- pr_err("driver version " PANEL_VERSION " disabled.\n");
+ pr_err("panel driver disabled.\n");
return -ENODEV;
}
@@ -2411,12 +2414,10 @@ static int __init panel_init_module(void)
}
if (pprt)
- pr_info("driver version " PANEL_VERSION
- " registered on parport%d (io=0x%lx).\n", parport,
- pprt->port->base);
+ pr_info("panel driver registered on parport%d (io=0x%lx).\n",
+ parport, pprt->port->base);
else
- pr_info("driver version " PANEL_VERSION
- " not yet registered\n");
+ pr_info("panel driver not yet registered\n");
return 0;
}