diff options
Diffstat (limited to 'target/linux/ep93xx/patches-2.6.30/002-lcd-linux-hd44780.patch')
-rw-r--r-- | target/linux/ep93xx/patches-2.6.30/002-lcd-linux-hd44780.patch | 4342 |
1 files changed, 0 insertions, 4342 deletions
diff --git a/target/linux/ep93xx/patches-2.6.30/002-lcd-linux-hd44780.patch b/target/linux/ep93xx/patches-2.6.30/002-lcd-linux-hd44780.patch deleted file mode 100644 index 7480b28..0000000 --- a/target/linux/ep93xx/patches-2.6.30/002-lcd-linux-hd44780.patch +++ /dev/null @@ -1,4342 +0,0 @@ -Index: linux-2.6.30.9/arch/arm/Kconfig -=================================================================== ---- linux-2.6.30.9.orig/arch/arm/Kconfig 2009-10-05 17:38:08.000000000 +0200 -+++ linux-2.6.30.9/arch/arm/Kconfig 2009-11-24 02:01:42.000000000 +0100 -@@ -1407,6 +1407,8 @@ - - source "drivers/accessibility/Kconfig" - -+source "drivers/lcd-linux/Kconfig" -+ - source "drivers/leds/Kconfig" - - source "drivers/rtc/Kconfig" -Index: linux-2.6.30.9/drivers/Makefile -=================================================================== ---- linux-2.6.30.9.orig/drivers/Makefile 2009-10-05 17:38:08.000000000 +0200 -+++ linux-2.6.30.9/drivers/Makefile 2009-11-24 02:01:42.000000000 +0100 -@@ -106,4 +106,5 @@ - obj-$(CONFIG_SSB) += ssb/ - obj-$(CONFIG_VIRTIO) += virtio/ - obj-$(CONFIG_STAGING) += staging/ -+obj-$(CONFIG_LCD_LINUX) += lcd-linux/ - obj-y += platform/ -Index: linux-2.6.30.9/drivers/lcd-linux/Config.in -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.30.9/drivers/lcd-linux/Config.in 2009-11-24 02:01:42.000000000 +0100 -@@ -0,0 +1,8 @@ -+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then -+ mainmenu_option next_comment -+ comment 'LCD support' -+ -+ tristate 'LCD-Linux layer' CONFIG_LCD_LINUX -+ dep_tristate ' HD44780 controller' CONFIG_LCD_HD44780 $CONFIG_LCD_LINUX -+ endmenu -+fi -Index: linux-2.6.30.9/drivers/lcd-linux/Kconfig -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.30.9/drivers/lcd-linux/Kconfig 2009-11-24 02:01:42.000000000 +0100 -@@ -0,0 +1,33 @@ -+menu "LCD-Linux support" -+ depends on EXPERIMENTAL -+ -+config LCD_LINUX -+ tristate "LCD-Linux layer" -+ default m -+ help -+ LCD-Linux provides an easy way to drive LCD displays under -+ Linux by creating a character which can be read or written. -+ It features complete VT102 emulation and recognizes -+ many escape sequences. If you want to use it you must also -+ choose an appropriate driver, otherwise it will not be -+ very useful. For more information see -+ http://lcd-linux.sourceforge.net/ -+ -+ To compile LCD-Linux as a module, choose M here: -+ the module will be called lcd-linux. -+ -+config LCD_HD44780 -+ tristate "HD44780 controller" -+ depends on LCD_LINUX && MACH_SIM_ONE -+ default m -+ help -+ This is a LCD-Linux driver for LCD displays based on the -+ Hitachi HD44780 (and compatible) controllers connected -+ to the SimOne LCD port. -+ -+ To compile this driver as a module, choose M here: -+ the module will be called hd44780. -+ -+ If unsure, say N. -+ -+endmenu -Index: linux-2.6.30.9/drivers/lcd-linux/Makefile -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.30.9/drivers/lcd-linux/Makefile 2009-11-24 02:01:42.000000000 +0100 -@@ -0,0 +1,8 @@ -+# -+# -+# Standard Makefile to statically compile LCD-Linux into the kernel -+# Linux 2.6 -+ -+obj-$(CONFIG_LCD_LINUX) += lcd-linux.o -+obj-$(CONFIG_LCD_HD44780) += hd44780.o -+ -Index: linux-2.6.30.9/drivers/lcd-linux/cgram/default.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.30.9/drivers/lcd-linux/cgram/default.h 2009-11-24 02:01:42.000000000 +0100 -@@ -0,0 +1,37 @@ -+/* default.h -+ * -+ * -+ * -+ * Default user defined characters for lcdmod. -+ * -+ * Copyright (C) by Michael McLellan (mikey@cs.auckland.ac.nz) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * -+ */ -+ -+static void init_charmap(void) -+{ -+} -+ -+static unsigned char cg0[] = { 0x1f, 0x1f, 0x11, 0x0f, 0x11, 0x1e, 0x01, 0x1f }; -+static unsigned char cg1[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f }; -+static unsigned char cg2[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f }; -+static unsigned char cg3[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f }; -+static unsigned char cg4[] = { 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f }; -+static unsigned char cg5[] = { 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f }; -+static unsigned char cg6[] = { 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f }; -+static unsigned char cg7[] = { 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f }; -Index: linux-2.6.30.9/drivers/lcd-linux/charmap.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.30.9/drivers/lcd-linux/charmap.h 2009-11-24 02:01:42.000000000 +0100 -@@ -0,0 +1,79 @@ -+/* charmap.h -+ * -+ * -+ * -+ * Character mapping for HD44780 devices by Mark Haemmerling <mail@markh.de>. -+ * -+ * Translates ISO 8859-1 to HD44780 charset. -+ * HD44780 charset reference: http://markh.de/hd44780-charset.png -+ * -+ * Initial table taken from lcd.o Linux kernel driver by -+ * Nils Faerber <nilsf@users.sourceforge.net>. Thanks! -+ * -+ * This file is released under the GNU General Public License. Refer to the -+ * COPYING file distributed with this package. -+ * -+ * Following translations are being performed: -+ * - maps umlaut accent characters to the corresponding umlaut characters -+ * - maps other accent characters to the characters without accents -+ * - maps beta (=ringel-S), micro and Yen -+ * -+ * Alternative mappings: -+ * - #112 ("p") -> #240 (large "p"), orig. mapped -> #112 -+ * - #113 ("q") -> #241 (large "q"), orig. mapped -> #113 -+ * -+ * HD44780 misses backslash -+ * -+ */ -+ -+static unsigned char charmap[] = { -+ -+/* 0 - 31 */ -+ 0, 1, 2, 3, 4, 5, 6, 7, -+ 8, 9, 10, 11, 12, 13, 14, 15, -+ 16, 17, 18, 19, 20, 21, 22, 23, -+ 24, 25, 26, 27, 28, 29, 30, 31, -+ -+/* 32 - 63 */ -+ 32, 33, 34, 35, 36, 37, 38, 39, -+ 40, 41, 42, 43, 44, 45, 46, 47, -+ 48, 49, 50, 51, 52, 53, 54, 55, -+ 56, 57, 58, 59, 60, 61, 62, 63, -+ -+/* 64 - 95 */ -+ 64, 65, 66, 67, 68, 69, 70, 71, -+ 72, 73, 74, 75, 76, 77, 78, 79, -+ 80, 81, 82, 83, 84, 85, 86, 87, -+ 88, 89, 90, 91, 47, 93, 94, 95, -+ -+/* 96 - 127 */ -+ 96, 97, 98, 99, 100, 101, 102, 103, -+104, 105, 106, 107, 108, 109, 110, 111, -+112, 113, 114, 115, 116, 117, 118, 119, -+120, 121, 122, 123, 124, 125, 126, 127, -+ -+/* 128 - 159 */ -+128, 129, 130, 131, 132, 133, 134, 135, -+136, 137, 138, 139, 140, 141, 142, 143, -+144, 145, 146, 147, 148, 149, 150, 151, -+152, 153, 154, 155, 156, 157, 158, 159, -+ -+/* 160 - 191 */ -+160, 33, 236, 237, 164, 92, 124, 167, -+ 34, 169, 170, 171, 172, 173, 174, 175, -+223, 177, 178, 179, 39, 249, 247, 165, -+ 44, 185, 186, 187, 188, 189, 190, 63, -+ -+/* 192 - 223 */ -+ 65, 65, 65, 65, 225, 65, 65, 67, -+ 69, 69, 69, 69, 73, 73, 73, 73, -+ 68, 78, 79, 79, 79, 79, 239, 120, -+ 48, 85, 85, 85, 245, 89, 240, 226, -+ -+/* 224 - 255 */ -+ 97, 97, 97, 97, 225, 97, 97, 99, -+101, 101, 101, 101, 105, 105, 105, 105, -+111, 110, 111, 111, 111, 111, 239, 253, -+ 48, 117, 117, 117, 245, 121, 240, 255 -+ -+}; -Index: linux-2.6.30.9/drivers/lcd-linux/commands.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.30.9/drivers/lcd-linux/commands.h 2009-11-24 02:01:42.000000000 +0100 -@@ -0,0 +1,77 @@ -+/* commands.h -+ * -+ * -+ * -+ * LCD-Linux: -+ * Driver for HD44780 compatible displays connected to the parallel port. -+ * -+ * HD44780 commands. -+ * -+ * Copyright (C) 2004 - 2007 Mattia Jona-Lasinio (mjona@users.sourceforge.net) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ */ -+ -+#ifndef HD44780_COMMANDS_H -+#define HD44780_COMMANDS_H -+ -+/*** HD44780 Command Set ***/ -+ -+/* Clear Display*/ -+#define CLR_DISP 0x01 /* Clear entire display; cursor at row 0, column 0 */ -+ -+/* Return Home */ -+#define RET_HOME 0x02 /* Cursor at row 0, column 0; display content doesn't change */ -+ -+/* Entry Mode Set */ -+#define ENTRY_MODE_SET 0x04 -+#define DISP_SHIFT_ON (ENTRY_MODE_SET | 0x01) /* Shift display, not cursor after data write */ -+#define DISP_SHIFT_OFF (ENTRY_MODE_SET | 0x00) /* Shift cursor, not display after data write */ -+#define CURS_INC (ENTRY_MODE_SET | 0x02) /* Shift on the right after data read/write */ -+#define CURS_DEC (ENTRY_MODE_SET | 0x00) /* Shift on the left after data read/write */ -+ -+/* Display on/off Control */ -+#define DISP_ONOFF_CNTR 0x08 -+#define BLINK_ON (DISP_ONOFF_CNTR | 0x01) /* Cursor blinking on */ -+#define BLINK_OFF (DISP_ONOFF_CNTR | 0x00) /* Cursor blinking off */ -+#define CURS_ON (DISP_ONOFF_CNTR | 0x02) /* Display Cursor */ -+#define CURS_OFF (DISP_ONOFF_CNTR | 0x00) /* Hide Cursor */ -+#define DISP_ON (DISP_ONOFF_CNTR | 0x04) /* Turn on display updating */ -+#define DISP_OFF (DISP_ONOFF_CNTR | 0x00) /* Freeze display content */ -+ -+/* Cursor or Display Shift */ -+#define CURS_DISP_SHIFT 0x10 -+#define SHIFT_RIGHT (CURS_DISP_SHIFT | 0x04) /* Shift on the right */ -+#define SHIFT_LEFT (CURS_DISP_SHIFT | 0x00) /* Shift on the left */ -+#define SHIFT_DISP (CURS_DISP_SHIFT | 0x08) /* Shift display */ -+#define SHIFT_CURS (CURS_DISP_SHIFT | 0x00) /* Shift cursor */ -+ -+/* Function Set */ -+#define FUNC_SET 0x20 -+#define FONT_5X10 (FUNC_SET | 0x04) /* Select 5x10 dots font */ -+#define FONT_5X8 (FUNC_SET | 0x00) /* Select 5x8 dots font */ -+#define DISP_2_LINES (FUNC_SET | 0x08) /* Select 2 lines display (only 5x8 font allowed) */ -+#define DISP_1_LINE (FUNC_SET | 0x00) /* Select 1 line display */ -+#define BUS_8_BITS (FUNC_SET | 0x10) /* Set 8 data bits */ -+#define BUS_4_BITS (FUNC_SET | 0x00) /* Set 4 data bits */ -+ -+/* Set CGRAM Address */ -+#define CGRAM_IO 0x40 /* Base CGRAM address */ -+ -+/* Set DDRAM Address */ -+#define DDRAM_IO 0x80 /* Base DDRAM address */ -+ -+#endif /* commands included */ -Index: linux-2.6.30.9/drivers/lcd-linux/config.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.30.9/drivers/lcd-linux/config.h 2009-11-24 02:01:42.000000000 +0100 -@@ -0,0 +1,73 @@ -+/* config.h -+ * -+ * -+ * -+ * Configure file for LCD-Linux. Here you must specify your hardware setup and -+ * timings constants. The default values will probably be right for you. -+ * -+ * Copyright (C) 2005 - 2007 Mattia Jona-Lasinio (mjona@users.sourceforge.net) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * -+ */ -+ -+/* Setup the default user defined characters in CGRAM */ -+#include "cgram/default.h" -+ -+/* Don't modify the default timing constants -+ * unless you know what you are doing. -+ */ -+ -+/* Execution times (in microseconds) */ -+#define T_READ 60 /* Read execution time (min 43 us) */ -+#define T_WRITE 60 /* Write execution time (min 43 us) */ -+#define T_BF 2 /* Busy flag polling time (min 1 us) */ -+ -+/* Timings in nanoseconds */ -+#define T_AS 200 /* Address set-up time (min 140 ns) */ -+#define T_EH 500 /* Enable high time (min 450 ns) */ -+#define T_EL 600 /* Enable low time (min 500 ns) */ -+ -+/* Various constants */ -+#define DFLT_NUM_CNTR 1 /* Default number of controllers the display has */ -+#define DFLT_CNTR_ROWS 2 /* Default number of rows per controller */ -+#define DFLT_CNTR_COLS 16 /* Default number of columns the display has */ -+#define DFLT_VS_ROWS 25 /* Default number of rows for the virtual screen */ -+#define DFLT_VS_COLS 80 /* Default number of columns for the virtual screen */ -+#define DFLT_TABSTOP 3 /* Default length of tabs */ -+#define DFLT_FLAGS (HD44780_CHECK_BF | HD44780_4BITS_BUS ) /* Default flags */ -+ -+#define MAX_CNTR_ROWS 4 /* The HD44780 supports up to 4 lines as a fake 2 lines mode */ -+#define MAX_CNTR_COLS 80 /* The HD44780 supports up to 80 characters (1*80; 2*40; etc) */ -+ -+#define SETUP 4 -+#define HIGH_NIBBLE_WRITE(x) (((x) >> (4-SETUP)) & (0x0f << SETUP)) -+#define LOW_NIBBLE_WRITE(x) (((x) << SETUP) & (0x0f << SETUP)) -+#define HIGH_NIBBLE_READ(x) (((x) & (0x0f << SETUP)) << (4-SETUP)) -+#define LOW_NIBBLE_READ(x) (((x) & (0x0f << SETUP)) >> SETUP) -+ -+ -+#define SIMONE_LCD_RS EP93XX_GPIO_LINE_A(2) /* OUT */ -+#define SIMONE_LCD_RD EP93XX_GPIO_LINE_A(3) /* OUT */ -+#define SIMONE_LCD_EN EP93XX_GPIO_LINE_B(4) /* EGPIO12 OUT */ -+#define SIMONE_LCD_BCKLIGHT EP93XX_GPIO_LINE_B(5) /* EGPIO13 OUT */ -+ -+#define SIMONE_LCD_DATA0 EP93XX_GPIO_LINE_A(4) -+#define SIMONE_LCD_DATA1 EP93XX_GPIO_LINE_A(5) -+#define SIMONE_LCD_DATA2 EP93XX_GPIO_LINE_A(6) -+#define SIMONE_LCD_DATA3 EP93XX_GPIO_LINE_A(7) -+ -+ -Index: linux-2.6.30.9/drivers/lcd-linux/hd44780.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.30.9/drivers/lcd-linux/hd44780.c 2009-11-24 02:05:29.000000000 +0100 -@@ -0,0 +1,860 @@ -+/* hd44780.c -+ * -+ * -+ * -+ * LCD-Linux: -+ * Driver for HD44780 compatible displays connected to the parallel port. -+ * -+ * Copyright (C) 2005 - 2007 Mattia Jona-Lasinio (mjona@users.sourceforge.net) -+ * Adapted to Sim.One Hardware by Nuccio Raciti (raciti.nuccio@gmail.com) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ */ -+ -+ -+#include <linux/autoconf.h> -+ -+ -+#ifdef CONFIG_PROC_FS -+#define USE_PROC -+#else -+#undef USE_PROC -+#endif -+ -+#include <linux/bitops.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+ -+#include <linux/delay.h> -+#include <linux/fs.h> -+ -+#include <asm/uaccess.h> -+#include <linux/init.h> -+ -+#include <asm/io.h> -+#include <linux/ioport.h> -+#include <asm/gpio.h> -+ -+#ifdef USE_PROC -+#include <linux/proc_fs.h> -+#endif -+ -+#define LCD_LINUX_MAIN -+#include <linux/hd44780.h> -+ -+#include "charmap.h" -+#include "commands.h" -+#include "config.h" -+ -+/** Function prototypes **/ -+static void read_display(unsigned char *byte, unsigned char bitmask); -+static void write_display(unsigned char byte, unsigned char bitmask); -+ -+/* Initialization */ -+static int hd44780_validate_driver(void); -+static int hd44780_init_port(void); -+static int hd44780_cleanup_port(void); -+static int hd44780_init_display(void); -+static int hd44780_cleanup_display(void); -+ -+/* Write */ -+static void hd44780_address_mode(int); -+static void hd44780_clear_display(void); -+static void hd44780_write_char(unsigned int, unsigned short); -+static void hd44780_write_cgram_char(unsigned char, unsigned char *); -+ -+/* Read */ -+static void check_bf(unsigned char); -+static void hd44780_read_char(unsigned int, unsigned short *); -+static void hd44780_read_cgram_char(unsigned char, unsigned char *); -+ -+/* Input handling */ -+static int hd44780_handle_custom_char(unsigned int); -+static int hd44780_handle_custom_ioctl(unsigned int,unsigned long , unsigned int); -+ -+/* Proc operations */ -+#ifdef USE_PROC -+static void create_proc_entries(void); -+static void remove_proc_entries(void); -+#endif -+ -+/* hd44780 access */ -+#define ACCESS_TO_READ 0 -+#define ACCESS_TO_WRITE 1 -+#define ACCESS_TO_DATA 2 -+ -+/* hd44780_flags */ -+#define _CHECK_BF 0 /* Do busy-flag checking */ -+#define _4BITS_BUS 1 /* The bus is 4 bits long */ -+#define _5X10_FONT 2 /* Use 5x10 font */ -+#define CURSOR_BLINK 3 /* Make the cursor blinking */ -+#define SHOW_CURSOR 4 /* Make the cursor visible */ -+#define DISPLAY_ON 5 /* Display status: on or off */ -+#define INC_ADDR 6 /* Increment address after data read/write */ -+#define BACKLIGHT 7 /* Display backlight: on or off */ -+#define CGRAM_STATE 9 /* Controller status bitmask (bits 9->15): DDRAM or CGRAM access */ -+#define ESC_MASK 0x00ff0000 -+#define PROC_MASK 0x0f000000 -+ -+#define SET_STATE(state, mask) (hd44780_flags = (hd44780_flags & ~(mask)) | ((state) & (mask))) -+#define SET_ESC_STATE(state) SET_STATE((state) << 16, ESC_MASK) -+#define SET_PROC_LEVEL(level) SET_STATE((level) << 24, PROC_MASK) -+#define ESC_STATE ((hd44780_flags & ESC_MASK) >> 16) -+#define PROC_LEVEL ((hd44780_flags & PROC_MASK) >> 24) -+ -+/* globals */ -+static unsigned int disp_size; /* Display size (rows*columns) */ -+static unsigned int disp_offset[1]; /* Physical cursor position on the display */ -+static unsigned long hd44780_flags; /* Driver flags for internal use only */ -+ -+static struct lcd_parameters par = { -+ .name = HD44780_STRING, -+ .minor = HD44780_MINOR, -+ .flags = DFLT_FLAGS, -+ .tabstop = DFLT_TABSTOP, -+ .num_cntr = 1, -+ .cntr_rows = DFLT_CNTR_ROWS, -+ .cntr_cols = DFLT_CNTR_COLS, -+ .vs_rows = DFLT_VS_ROWS, -+ .vs_cols = DFLT_VS_COLS, -+ .cgram_chars = 8, -+ .cgram_bytes = 8, -+ .cgram_char0 = 0, -+}; -+/* End of globals */ -+ -+#ifdef MODULE -+#include <linux/device.h> -+MODULE_ALIAS_CHARDEV(LCD_MAJOR, HD44780_MINOR); -+#include <linux/kmod.h> -+ -+static unsigned short flags = DFLT_FLAGS; -+static unsigned short tabstop = DFLT_TABSTOP; -+static unsigned short cntr_rows = DFLT_CNTR_ROWS; -+static unsigned short cntr_cols = DFLT_CNTR_COLS; -+static unsigned short vs_rows = DFLT_VS_ROWS; -+static unsigned short vs_cols = DFLT_VS_COLS; -+static unsigned short minor = HD44780_MINOR; -+ -+MODULE_DESCRIPTION("LCD SimOne driver for HD44780 compatible controllers."); -+MODULE_AUTHOR("Nuccio Raciti (raciti.nuccio@gmail.com)"); -+#ifdef MODULE_LICENSE -+MODULE_LICENSE("GPL"); -+#endif -+module_param(flags, ushort, 0444); -+module_param(cntr_rows, ushort, 0444); -+module_param(cntr_cols, ushort, 0444); -+module_param(vs_rows, ushort, 0444); -+module_param(vs_cols, ushort, 0444); -+module_param(tabstop, ushort, 0444); -+module_param(minor, ushort, 0444); -+ -+MODULE_PARM_DESC(flags, "Various flags (see Documentation)"); -+MODULE_PARM_DESC(cntr_rows, "Number of rows per controller on the LCD: 1, 2, 4 (default: " string(DFLT_CNTR_ROWS) ")"); -+MODULE_PARM_DESC(cntr_cols, "Number of columns on the LCD (default: " string(DFLT_CNTR_COLS) ", max: " string(MAX_CNTR_COLS) ")"); -+MODULE_PARM_DESC(vs_rows, "Number of rows of the virtual screen (default: " string(DFLT_VS_ROWS) ")"); -+MODULE_PARM_DESC(vs_cols, "Number of columns of the virtual screen (default: " string(DFLT_VS_COLS) ")"); -+MODULE_PARM_DESC(tabstop, "Tab character length (default: " string(DFLT_TABSTOP) ")"); -+MODULE_PARM_DESC(minor, "Assigned minor number (default: " string(HD44780_MINOR) ")"); -+#else -+ -+/* -+ * Parse boot command line -+ * -+ * hd44780=cntr_rows,cntr_cols,vs_rows,vs_cols,flags,minor,tabstop -+ */ -+static int __init hd44780_boot_init(char *cmdline) -+{ -+ char *str = cmdline; -+ int idx = 0; -+ unsigned short *args[] = { -+ &par.cntr_rows, -+ &par.cntr_cols, -+ &par.vs_rows, -+ &par.vs_cols, -+ &par.flags, -+ &par.num_cntr, -+ &par.minor, -+ &par.tabstop, -+ }; -+ -+ while (*cmdline && idx < (sizeof(args)/sizeof(unsigned short *))) { -+ switch (*str) { -+ case ',': -+ *str++ = 0; -+ case 0: -+ if (strlen(cmdline)) -+ *args[idx] = simple_strtoul(cmdline, NULL, 0); -+ ++idx; -+ cmdline = str; -+ break; -+ default: -+ ++str; -+ break; -+ } -+ } -+ -+ return (1); -+} -+ -+__setup("hd44780=", hd44780_boot_init); -+#endif /* MODULE */ -+ -+/* Macros for iterator handling */ -+static inline unsigned int iterator_inc_(unsigned int iterator, const unsigned int module) -+{ -+ return ((++iterator)%module); -+} -+ -+static inline unsigned int iterator_dec_(unsigned int iterator, const unsigned int module) -+{ -+ return (iterator ? --iterator : module-1); -+} -+ -+#define iterator_inc(iterator, module) (iterator = iterator_inc_(iterator, module)) -+#define iterator_dec(iterator, module) (iterator = iterator_dec_(iterator, module)) -+ -+static inline void set_lines(unsigned char bitmask) -+{ -+ gpio_set_value(SIMONE_LCD_EN, 0); /* Disable */ -+ -+ if(bitmask & ACCESS_TO_WRITE ) { -+ gpio_direction_output (SIMONE_LCD_DATA0 , 0); -+ gpio_direction_output (SIMONE_LCD_DATA1 , 0); -+ gpio_direction_output (SIMONE_LCD_DATA2 , 0); -+ gpio_direction_output (SIMONE_LCD_DATA3 , 0); -+ gpio_set_value(SIMONE_LCD_RD, 0); /* Write */ -+ } else { -+ -+ gpio_direction_input (SIMONE_LCD_DATA0); -+ gpio_direction_input (SIMONE_LCD_DATA1); -+ gpio_direction_input (SIMONE_LCD_DATA2); -+ gpio_direction_input (SIMONE_LCD_DATA3); -+ gpio_set_value(SIMONE_LCD_RD, 1); /* Read */ -+ } -+ -+ if(bitmask & ACCESS_TO_DATA ) -+ gpio_set_value(SIMONE_LCD_RS, 1); /* Data */ -+ else -+ gpio_set_value(SIMONE_LCD_RS, 0); /* Cmds*/ -+ -+ if(test_bit(BACKLIGHT, &hd44780_flags)) -+ gpio_set_value(SIMONE_LCD_BCKLIGHT, 1); -+ else -+ gpio_set_value(SIMONE_LCD_BCKLIGHT, 0); -+} -+ -+ -+/* Low level read from the display */ -+static inline unsigned char __read_display(unsigned char bitmask) -+{ -+ unsigned char byte; -+ -+ set_lines (bitmask); -+ -+ ndelay(T_AS); /* Address set-up time */ -+ gpio_set_value(SIMONE_LCD_EN, 1); /* Enable */ -+ ndelay(T_EH);/* Enable high time */ -+ -+ byte = (gpio_get_value(SIMONE_LCD_DATA0) << 4); -+ byte |= (gpio_get_value(SIMONE_LCD_DATA1) << 5); -+ byte |= (gpio_get_value(SIMONE_LCD_DATA2) << 6); -+ byte |= (gpio_get_value(SIMONE_LCD_DATA3) << 7); -+ -+ gpio_set_value(SIMONE_LCD_EN, 0); /* Disable */ -+ -+ ndelay(T_EL); /* Enable low time */ -+ -+ -+ return (byte); -+ -+} -+ -+/* Low level write to the display */ -+static inline void __write_display(unsigned char data, unsigned char bitmask) -+{ -+ set_lines(bitmask); -+ -+ if(data & 0x10) -+ gpio_set_value(SIMONE_LCD_DATA0, 1); -+ else -+ gpio_set_value(SIMONE_LCD_DATA0, 0); -+ -+ if(data & 0x20) -+ gpio_set_value(SIMONE_LCD_DATA1, 1); -+ else -+ gpio_set_value(SIMONE_LCD_DATA1, 0); -+ -+ if(data & 0x40) -+ gpio_set_value(SIMONE_LCD_DATA2, 1); -+ else -+ gpio_set_value(SIMONE_LCD_DATA2, 0); -+ -+ if(data & 0x80) -+ gpio_set_value(SIMONE_LCD_DATA3, 1); -+ else -+ gpio_set_value(SIMONE_LCD_DATA3, 0); -+ -+ ndelay(T_AS); /* Address set-up time */ -+ gpio_set_value(SIMONE_LCD_EN, 1); -+ ndelay(T_EH); /* Enable high time */ -+ -+ gpio_set_value(SIMONE_LCD_EN, 0); /* Disable */ -+ ndelay(T_EL); /* Enable low time */ -+} -+ -+ -+/* Read data from the display (4 bit bus, check busy flag) */ -+static void read_display (unsigned char *byte,unsigned char bitmask) -+{ -+ if(bitmask) check_bf(bitmask); -+ *byte = HIGH_NIBBLE_READ(__read_display(bitmask)); -+ if(bitmask) check_bf(bitmask); -+ *byte |= LOW_NIBBLE_READ(__read_display(bitmask)); -+} -+ -+ -+/* Output commands or data to the display (4 bit bus, check busy flag) */ -+static void write_display(unsigned char byte,unsigned char bitmask) -+{ -+ check_bf(bitmask); -+ __write_display(HIGH_NIBBLE_WRITE(byte),bitmask); -+ check_bf(bitmask); -+ __write_display(LOW_NIBBLE_WRITE(byte),bitmask); -+} -+ -+ -+/* Read Address Counter AC from the display */ -+static unsigned char read_ac(unsigned char bitmask) -+{ -+ unsigned char byte; -+ -+ read_display(&byte, bitmask); -+ -+ return (byte); -+} -+ -+ -+/* Do busy-flag check */ -+static void check_bf(unsigned char bitmask) -+{ -+ unsigned int timeout = 20; -+ static unsigned char do_check_bf = 5; -+ gpio_set_value(SIMONE_LCD_EN, 0); /* Disable */ -+ -+ gpio_direction_input (SIMONE_LCD_DATA0); -+ gpio_direction_input (SIMONE_LCD_DATA1); -+ gpio_direction_input (SIMONE_LCD_DATA2); -+ gpio_direction_input (SIMONE_LCD_DATA3); -+ -+ gpio_set_value(SIMONE_LCD_RD, 1); /* Read */ -+ gpio_set_value(SIMONE_LCD_RS, 0); /* Instru */ -+ -+ ndelay(T_AS); /* Address set-up time */ -+ gpio_set_value(SIMONE_LCD_EN, 1); /* Enable */ -+ ndelay(T_EH);/* Enable high time */ -+ -+ do{ -+ udelay(T_BF); -+ } while (gpio_get_value(SIMONE_LCD_DATA3) && --timeout); -+ -+ if (! timeout) { -+ if (! --do_check_bf) { -+ printk(KERN_NOTICE "hd44780 error: is the LCD connected?\n"); -+ } -+ } -+ -+ gpio_set_value(SIMONE_LCD_EN, 0); /* Disable */ -+ -+ ndelay(T_EL); /* Enable low time */ -+} -+ -+/* Send commands to the display */ -+static void write_command(unsigned char command) -+{ -+ write_display(command, ACCESS_TO_WRITE); -+ -+ if (command <= 0x03) -+ mdelay(2); -+} -+ -+static inline void set_cursor(unsigned int offset) -+{ -+ unsigned int disp_number = offset/disp_size; -+ unsigned int local_offset = offset%disp_size; -+ -+ if (disp_offset[disp_number] != local_offset || test_bit(CGRAM_STATE+disp_number, &hd44780_flags)) { -+ unsigned int disp_row = local_offset/par.cntr_cols; -+ unsigned int disp_column = local_offset%par.cntr_cols; -+ -+ write_command(DDRAM_IO | ((disp_row%2)*0x40) | (((disp_row >= 2)*par.cntr_cols)+disp_column)); -+ clear_bit(CGRAM_STATE+disp_number, &hd44780_flags); -+ disp_offset[disp_number] = local_offset; -+ } -+} -+ -+/* HD44780 DDRAM addresses are consecutive only when -+ * the cursor moves on the same row of the display. -+ * Every time the row of the cursor changes we invalidate -+ * the cursor position to force hardware cursor repositioning. -+ */ -+static inline void mov_cursor(unsigned int disp_number) -+{ -+ if (test_bit(INC_ADDR, &hd44780_flags)) { -+ iterator_inc(disp_offset[disp_number], disp_size); -+ if (disp_offset[disp_number]%par.cntr_cols == 0) -+ disp_offset[disp_number] = disp_size; -+ } else { -+ iterator_dec(disp_offset[disp_number], disp_size); -+ if (disp_offset[disp_number]%par.cntr_cols == par.cntr_cols-1) -+ disp_offset[disp_number] = disp_size; -+ } -+} -+ -+static struct lcd_driver hd44780 = { -+ .read_char = hd44780_read_char, -+ .read_cgram_char = hd44780_read_cgram_char, -+ .write_char = hd44780_write_char, -+ .write_cgram_char = hd44780_write_cgram_char, -+ .address_mode = hd44780_address_mode, -+ .clear_display = hd44780_clear_display, -+ .validate_driver = hd44780_validate_driver, -+ .init_display = hd44780_init_display, -+ .cleanup_display = hd44780_cleanup_display, -+ .init_port = hd44780_init_port, -+ .cleanup_port = hd44780_cleanup_port, -+ .handle_custom_char = hd44780_handle_custom_char, -+ .handle_custom_ioctl = hd44780_handle_custom_ioctl, -+ -+ .charmap = charmap, -+}; -+ -+static void hd44780_read_char(unsigned int offset, unsigned short *data) -+{ -+ unsigned int disp_number = offset/disp_size; -+ unsigned char tmp; -+ -+ set_cursor(offset); -+ read_display(&tmp, ACCESS_TO_DATA); -+ *data = tmp; -+ mov_cursor(disp_number); -+} -+ -+static void hd44780_read_cgram_char(unsigned char index, unsigned char *pixels) -+{ -+ unsigned int i; -+ -+ write_command(CGRAM_IO | (index << 3)); -+ set_bit(CGRAM_STATE+0, &hd44780_flags); -+ -+ for (i = 0; i < 8; ++i) { -+ read_display(pixels+i, ACCESS_TO_DATA ); -+ pixels[i] &= 0x1f; -+ } -+} -+ -+static void hd44780_write_char(unsigned int offset, unsigned short data) -+{ -+ unsigned int disp_number = offset/disp_size; -+ -+ set_cursor(offset); -+ write_display(data & 0xff, ACCESS_TO_WRITE | ACCESS_TO_DATA ); -+ mov_cursor(disp_number); -+} -+ -+static void hd44780_write_cgram_char(unsigned char index, unsigned char *pixels) -+{ -+ unsigned int i; -+ -+ /* Move address pointer to index in CGRAM */ -+ write_command(CGRAM_IO | (index << 3)); -+ -+ set_bit(CGRAM_STATE+0, &hd44780_flags); -+ -+ for (i = 0; i < 8; ++i) { -+ pixels[i] &= 0x1f; -+ write_display(pixels[i], ACCESS_TO_WRITE | ACCESS_TO_DATA ); -+ } -+} -+ -+/* Increment/decrement address mode after a data read/write */ -+static void hd44780_address_mode(int mode) -+{ -+ if (mode > 0 && ! test_bit(INC_ADDR, &hd44780_flags)) { -+ write_command(CURS_INC | DISP_SHIFT_OFF); -+ set_bit(INC_ADDR, &hd44780_flags); -+ } else if (mode < 0 && test_bit(INC_ADDR, &hd44780_flags)) { -+ write_command(CURS_DEC | DISP_SHIFT_OFF); -+ clear_bit(INC_ADDR, &hd44780_flags); -+ } -+} -+ -+static void hd44780_clear_display(void) -+{ -+ write_command(CLR_DISP); -+ if (! test_bit(INC_ADDR, &hd44780_flags)) -+ write_command(CURS_DEC | DISP_SHIFT_OFF); -+ memset(disp_offset, 0, sizeof(disp_offset)); -+} -+ -+static int hd44780_validate_driver(void) -+{ -+ if (par.cntr_rows != 1 && par.cntr_rows != 2 && par.cntr_rows != 4) -+ par.cntr_rows = DFLT_CNTR_ROWS; -+ -+ if (par.cntr_rows != 1) -+ par.flags &= ~HD44780_5X10_FONT; -+ -+ -+ if (! par.cntr_cols || par.cntr_cols > MAX_CNTR_COLS/par.cntr_rows) -+ par.cntr_cols = MAX_CNTR_COLS/par.cntr_rows; -+ -+ disp_size = par.cntr_rows*par.cntr_cols; -+ -+ /* These parameters depend on the hardware and cannot be changed */ -+ par.cgram_chars = 8; -+ par.cgram_bytes = 8; -+ par.cgram_char0 = 0; -+ -+ return (0); -+} -+ -+/* Send init commands to the display */ -+static void write_init_command(void) -+{ -+ unsigned char command = 0x30; -+ -+ __write_display(HIGH_NIBBLE_WRITE(command), ACCESS_TO_WRITE); -+ mdelay(20); /* Wait more than 4.1 ms */ -+ __write_display(HIGH_NIBBLE_WRITE(command), ACCESS_TO_WRITE); -+ udelay(200); /* Wait more than 100 us */ -+ __write_display(HIGH_NIBBLE_WRITE(command), ACCESS_TO_WRITE); -+ udelay(200); /* Wait more than 100 us */ -+ command = BUS_4_BITS; -+ command |= ((par.cntr_rows == 1) ? DISP_1_LINE : DISP_2_LINES); -+ command |= (test_bit(_5X10_FONT, &hd44780_flags) ? FONT_5X10 : FONT_5X8); -+ write_command(command); -+ /* set_bit(BACKLIGHT, &hd44780_flags); */ -+} -+ -+static int hd44780_init_display(void) -+{ -+ if (par.flags & HD44780_CHECK_BF) -+ set_bit(_CHECK_BF, &hd44780_flags); -+ else -+ clear_bit(_CHECK_BF, &hd44780_flags); -+ -+ if (par.flags & HD44780_4BITS_BUS) -+ set_bit(_4BITS_BUS, &hd44780_flags); -+ else -+ clear_bit(_4BITS_BUS, &hd44780_flags); -+ -+ if (par.flags & HD44780_5X10_FONT) -+ set_bit(_5X10_FONT, &hd44780_flags); -+ else -+ clear_bit(_5X10_FONT, &hd44780_flags); -+ -+ write_init_command(); -+ -+ hd44780_clear_display(); -+ hd44780_address_mode(1); -+ write_command(DISP_ON | CURS_OFF | BLINK_OFF); -+ set_bit(DISPLAY_ON, &hd44780_flags); -+ clear_bit(SHOW_CURSOR, &hd44780_flags); -+ clear_bit(CURSOR_BLINK, &hd44780_flags); -+ -+ /* Set the CGRAM to default values */ -+ hd44780_write_cgram_char(0, cg0); -+ hd44780_write_cgram_char(1, cg1); -+ hd44780_write_cgram_char(2, cg2); -+ hd44780_write_cgram_char(3, cg3); -+ hd44780_write_cgram_char(4, cg4); -+ hd44780_write_cgram_char(5, cg5); -+ hd44780_write_cgram_char(6, cg6); -+ hd44780_write_cgram_char(7, cg7); -+ init_charmap(); -+ -+ return (0); -+} -+ -+static int hd44780_cleanup_display(void) -+{ -+ hd44780_clear_display(); -+ -+ return (0); -+} -+ -+static int hd44780_init_port(void) -+{ -+ gpio_direction_output (SIMONE_LCD_BCKLIGHT, 0); -+ gpio_direction_output (SIMONE_LCD_RD , 0); -+ gpio_direction_output (SIMONE_LCD_RS , 0); -+ gpio_direction_output (SIMONE_LCD_EN , 0); -+ gpio_set_value(SIMONE_LCD_EN, 0); /* Disable */ -+ -+ return (0); -+} -+ -+static int hd44780_cleanup_port(void) -+{ -+ -+ gpio_direction_input (SIMONE_LCD_BCKLIGHT); -+ gpio_direction_input (SIMONE_LCD_RD); -+ gpio_direction_input (SIMONE_LCD_RS); -+ gpio_direction_input (SIMONE_LCD_EN); -+ gpio_direction_input (SIMONE_LCD_DATA0); -+ gpio_direction_input (SIMONE_LCD_DATA1); -+ gpio_direction_input (SIMONE_LCD_DATA2); -+ gpio_direction_input (SIMONE_LCD_DATA3); -+ return (0); -+} -+ -+static void display_attr(unsigned char input) -+{ -+ unsigned char command; -+ -+ switch (ESC_STATE) { -+ case 'a': /* Turn on/off the display cursor */ -+ if (input == '1') -+ set_bit(SHOW_CURSOR, &hd44780_flags); -+ else if (input == '0') -+ clear_bit(SHOW_CURSOR, &hd44780_flags); -+ break; -+ case 'b': /* Turn on/off the display cursor blinking */ -+ if (input == '1') -+ set_bit(CURSOR_BLINK, &hd44780_flags); -+ else if (input == '0') -+ clear_bit(CURSOR_BLINK, &hd44780_flags); -+ break; -+ case 'h': /* Turn on/off the display */ -+ if (input == '1') -+ set_bit(DISPLAY_ON, &hd44780_flags); -+ else if (input == '0') -+ clear_bit(DISPLAY_ON, &hd44780_flags); -+ break; -+ } -+ -+ command = (test_bit(DISPLAY_ON, &hd44780_flags) ? DISP_ON : DISP_OFF); -+ command |= (test_bit(SHOW_CURSOR, &hd44780_flags) ? CURS_ON : CURS_OFF); -+ command |= (test_bit(CURSOR_BLINK, &hd44780_flags) ? BLINK_ON : BLINK_OFF); -+ -+ if (ESC_STATE == 'h') -+ write_command(command); -+} -+ -+static int hd44780_handle_custom_char(unsigned int _input) -+{ -+ unsigned char input = _input & 0xff; -+ -+ if (_input & (~0xff)) { -+ switch (ESC_STATE) { -+ case 'a': /* Turn on/off the display cursor */ -+ case 'b': /* Turn on/off the display cursor blinking */ -+ case 'h': /* Turn on/off the the display */ -+ display_attr(input); -+ return (0); -+ case 'l': /* Turn on/off the backlight */ -+ if (input == '1') -+ set_bit(BACKLIGHT, &hd44780_flags); -+ else if (input == '0') -+ clear_bit(BACKLIGHT, &hd44780_flags); -+ read_ac(ACCESS_TO_READ); -+ return (0); -+ } -+ } -+ -+ switch (input) { -+ case 'a': /* Turn on/off the display cursor */ -+ case 'b': /* Turn on/off the display cursor blinking */ -+ case 'h': /* Turn on/off the display */ -+ case 'l': /* Turn on/off the backlight */ -+ SET_ESC_STATE(input); -+ return (1); -+ case 'd': /* Shift display cursor Right */ -+ write_command(SHIFT_CURS | SHIFT_RIGHT); -+ return (0); -+ case 'e': /* Shift display cursor Left */ -+ write_command(SHIFT_CURS | SHIFT_LEFT); -+ return (0); -+ case 'f': /* Shift display Right */ -+ write_command(SHIFT_DISP | SHIFT_RIGHT); -+ return (0); -+ case 'g': /* Shift display Left */ -+ write_command(SHIFT_DISP | SHIFT_LEFT); -+ return (0); -+ } -+ -+ return (-1); -+} -+ -+static int hd44780_handle_custom_ioctl(unsigned int num, unsigned long arg, unsigned int user_space) -+{ -+ unsigned char *buffer = (unsigned char *)arg; -+ -+ if (num != HD44780_READ_AC) -+ return (-ENOIOCTLCMD); -+ -+ if (user_space) -+ put_user(read_ac(ACCESS_TO_READ), buffer); -+ else -+ buffer[0] = read_ac(ACCESS_TO_READ); -+ -+ return (0); -+} -+ -+#ifdef USE_PROC -+static int hd44780_proc_status(char *buffer, char **start, off_t offset, int size, int *eof, void *data) -+{ -+ char *temp = buffer; -+ -+ /* Print display configuration */ -+ temp += sprintf(temp, -+ "Interface:\t%u bits\n" -+ "Display rows:\t%d\n" -+ "Display cols:\t%d\n" -+ "Screen rows:\t%d\n" -+ "Screen cols:\t%d\n" -+ "Read:\t\t%sabled\n" -+ "Busy flag chk:\t%sabled\n" -+ "Assigned minor:\t%u\n", -+ (test_bit(_4BITS_BUS, &hd44780_flags) ? 4 : 8), -+ par.cntr_rows, par.cntr_cols, -+ par.vs_rows, par.vs_cols, -+ (hd44780.read_char ? "En" : "Dis"), -+ (test_bit(_CHECK_BF, &hd44780_flags) ? "En" : "Dis"), -+ par.minor); -+ -+ return (temp-buffer); -+} -+ -+static int hd44780_proc_cgram(char *buffer, char **start, off_t offset, int size, int *eof, void *data) -+{ -+ char *temp = buffer; -+ unsigned int i; -+ -+ temp += sprintf(temp, "static void init_charmap(void)\n{\n" -+ "\t/*\n" -+ "\t * charmap[char mapped to cg0] = 0;\n" -+ "\t * charmap[char mapped to cg1] = 1;\n" -+ "\t * charmap[char mapped to cg2] = 2;\n" -+ "\t * charmap[char mapped to cg3] = 3;\n" -+ "\t * charmap[char mapped to cg4] = 4;\n" -+ "\t * charmap[char mapped to cg5] = 5;\n" -+ "\t * charmap[char mapped to cg6] = 6;\n" -+ "\t * charmap[char mapped to cg7] = 7;\n" -+ "\t */\n" -+ "}\n\n"); -+ -+ for (i = 0; i < 8; ++i) { -+ unsigned char cgram_buffer[8]; -+ unsigned int j; -+ -+ temp += sprintf(temp, "static unsigned char cg%u[] = { ", i); -+ hd44780_read_cgram_char(i, cgram_buffer); -+ for (j = 0; j < 8; ++j) -+ temp += sprintf(temp, "0x%.2x%s", cgram_buffer[j], (j == 7 ? " };\n" : ", ")); -+ } -+ -+ return (temp-buffer); -+} -+ -+static void create_proc_entries(void) -+{ -+ int count = 0; -+ -+ SET_PROC_LEVEL(count); -+ if (create_proc_read_entry("status", 0, hd44780.driver_proc_root, hd44780_proc_status, NULL) == NULL) { -+ printk(KERN_ERR "hd44780: cannot create /proc/lcd/%s/status\n", par.name); -+ return; -+ } -+ SET_PROC_LEVEL(++count); -+ if (hd44780.read_cgram_char) { -+ if (create_proc_read_entry("cgram.h", 0, hd44780.driver_proc_root, hd44780_proc_cgram, NULL) == NULL) { -+ printk(KERN_ERR "hd44780: cannot create /proc/lcd/%s/cgram.h\n", par.name); -+ return; -+ } -+ SET_PROC_LEVEL(++count); -+ } -+} -+ -+static void remove_proc_entries(void) -+{ -+ switch (PROC_LEVEL) { -+ case 2: -+ remove_proc_entry("cgram.h", hd44780.driver_proc_root); -+ case 1: -+ remove_proc_entry("status", hd44780.driver_proc_root); -+ } -+ SET_PROC_LEVEL(0); -+} -+#endif -+ -+/* Initialization */ -+static int __init hd44780_init_module(void) -+{ -+ int ret; -+ -+#ifdef MODULE -+#ifdef NOT_DEF -+ if ((ret = request_module("lcd-linux"))) { -+ if (ret != -ENOSYS) { -+ printk(KERN_ERR "hd44780: failure while loading module lcd-linux\n"); -+ return (ret); -+ } -+ printk(KERN_ERR "hd44780: your kernel does not have kmod or kerneld support;\n"); -+ printk(KERN_ERR "hd44780: remember to load the lcd-linux module before\n"); -+ printk(KERN_ERR "hd44780: loading the hd44780 module\n"); -+ } -+#endif -+ if (flags != DFLT_FLAGS) par.flags = flags; -+ if (tabstop != DFLT_TABSTOP) par.tabstop = tabstop; -+ if (cntr_rows != DFLT_CNTR_ROWS) par.cntr_rows = cntr_rows; -+ if (cntr_cols != DFLT_CNTR_COLS) par.cntr_cols = cntr_cols; -+ if (vs_rows != DFLT_VS_ROWS) par.vs_rows = vs_rows; -+ if (vs_cols != DFLT_VS_COLS) par.vs_cols = vs_cols; -+ if (minor != HD44780_MINOR) par.minor = minor; -+#endif -+ -+ lcd_driver_setup(&hd44780); -+ if ((ret = lcd_register_driver(&hd44780, &par))) -+ return (ret); -+ -+#ifdef USE_PROC -+ if (hd44780.driver_proc_root) -+ create_proc_entries(); -+#endif -+ -+ printk(KERN_INFO "HD44780 driver (LCD-Linux" HD44780_VERSION ")\n"); -+ printk(KERN_INFO "Nuccio Raciti <raciti.nuccio@gmail.com>\n"); -+ -+ -+ return (0); -+} -+ -+/* Cleanup */ -+ -+static void __exit hd44780_cleanup_module(void) -+{ -+#ifdef USE_PROC -+ if (hd44780.driver_proc_root) -+ remove_proc_entries(); -+#endif -+ -+ lcd_unregister_driver(&hd44780, &par); -+} -+ -+module_init(hd44780_init_module) -+module_exit(hd44780_cleanup_module) -Index: linux-2.6.30.9/drivers/lcd-linux/lcd-linux.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.30.9/drivers/lcd-linux/lcd-linux.c 2009-11-24 02:01:42.000000000 +0100 -@@ -0,0 +1,2892 @@ -+/* lcd-linux.c -+ * -+ * -+ * -+ * Software layer to drive LCD displays under Linux. -+ * -+ * Copyright (C) 2005 - 2007 Mattia Jona-Lasinio (mjona@users.sourceforge.net) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ */ -+ -+#include <linux/version.h> -+ -+#ifndef KERNEL_VERSION -+#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) -+#endif -+ -+#ifndef LINUX_VERSION_CODE -+#error - LINUX_VERSION_CODE undefined in 'linux/version.h' -+#endif -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -+#include <linux/autoconf.h> -+#else -+#include <linux/config.h> -+#endif -+#ifdef CONFIG_PROC_FS -+#define USE_PROC -+#else -+#undef USE_PROC -+#endif -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) -+#include <linux/semaphore.h> -+#else -+#include <asm/semaphore.h> -+#endif -+#include <linux/bitops.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/sched.h> -+ -+#include <linux/fs.h> -+ -+#include <asm/uaccess.h> -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -+#include <linux/device.h> -+#endif -+#include <linux/init.h> -+#include <linux/list.h> -+#include <linux/slab.h> -+#include <linux/selection.h> -+#include <linux/vmalloc.h> -+ -+#ifdef USE_PROC -+#include <linux/proc_fs.h> -+#endif -+ -+#define LCD_LINUX_MAIN -+#include <linux/lcd-linux.h> -+ -+/*** struct_flags ***/ -+#define NEED_WRAP 0 /* Next char will trigger a newline */ -+#define DECIM 1 /* Insert mode */ -+#define DECAWM 2 /* Autowrap */ -+#define DECSCNM 3 /* Inverted screen */ -+#define CRLF 4 /* Follow lf, vt, ff, with a cr */ -+#define INC_CURS_POS 5 /* Increment cursor position after data read/write */ -+#define QUES 6 /* CSI Esc sequence contains a question mark */ -+#define USER_SPACE 7 /* If set, the buffer pointed by arg in do_lcd_ioctl() is -+ * assumed to be in user space otherwise it is in kernel space */ -+#define NULL_CHARMAP 8 /* The driver doesn't provide a charmap so the -+ * lcd-linux layer provides one*/ -+#define CAN_DO_COLOR 9 /* The display is color capable */ -+#define WITH_ATTR 10 /* If set, the void * buffer in do_lcd_read/write() contains -+ * attributes and therefore is an unsigned short * otherwise it -+ * is an unsigned char * -+ */ -+ -+/*** attributes ***/ -+#define I_MASK 0x03 /* Intensity (0 = low, 1 = normal, 2 = bright) */ -+#define ULINE 0x04 /* Underlined text */ -+#define REVERSE 0x08 /* Reversed video text */ -+#define BLINK 0x80 /* Blinking text */ -+ -+/*** Color attributes ***/ -+#define FG_MASK 0x0f /* Foreground color */ -+#define BG_MASK 0xf0 /* Background color */ -+ -+/* input states */ -+#define NORMAL 0x00001000 /* Normal mode */ -+#define RAW 0x00002000 /* Raw mode (console emulation disabled) */ -+#define SYN 0x00003000 /* Synchronous Idle mode */ -+#define ESC 0x00004000 /* Escape mode */ -+#define CSI 0x00005000 /* CSI escape mode */ -+#define ESC_G0 0x00006000 /* G0 character set */ -+#define ESC_G1 0x00007000 /* G1 character set */ -+#define ESC_HASH 0x00008000 /* ESC # escape sequence */ -+#define ESC_PERCENT 0x00009000 /* ESC % escape sequence */ -+#define ARG 0x0000a000 /* Waiting for arguments for the lcd-linux layer */ -+#define ARG_DRIVER 0x0000b000 /* Waiting for arguments for the display driver */ -+#define INPUT_MASK 0x0000f000 -+#define ESC_MASK 0x00ff0000 -+#define INIT_MASK 0x0f000000 -+#define PROC_MASK 0xf0000000 -+ -+#define SET_STATE(p, state, mask) ((p)->struct_flags = ((p)->struct_flags & ~(mask)) | ((state) & (mask))) -+#define SET_INPUT_STATE(p, state) SET_STATE(p, state, INPUT_MASK) -+#define SET_ESC_STATE(p, state) SET_STATE(p, (state) << 16, ESC_MASK) -+#define SET_INIT_LEVEL(p, level) SET_STATE(p, (level) << 24, INIT_MASK) -+#define SET_PROC_LEVEL(p, level) SET_STATE(p, (level) << 28, PROC_MASK) -+#define INPUT_STATE(p) ((p)->struct_flags & INPUT_MASK) -+#define ESC_STATE(p) (((p)->struct_flags & ESC_MASK) >> 16) -+#define INIT_LEVEL(p) (((p)->struct_flags & INIT_MASK) >> 24) -+#define PROC_LEVEL(p) (((p)->struct_flags & PROC_MASK) >> 28) -+ -+#define NPAR 16 /* Max number of parameters in CSI escape sequence */ -+#define FLIP_BUF_SIZE (1 << 6) /* Flip buffer size (64 bytes) */ -+ -+struct lcd_struct { -+ struct list_head lcd_list; /* Doubly linked list */ -+ struct semaphore lcd_sem; /* Locks this structure */ -+ struct lcd_driver *driver; /* The driver associated to this struct */ -+ struct lcd_parameters *par; /* The parameters associated to this struct */ -+ unsigned long struct_flags; /* Flags for internal use only */ -+ unsigned int refcount; /* Number of references to this struct */ -+ -+ unsigned short *display; /* The display buffer */ -+ -+ unsigned short *fb; /* The virtual screen framebuffer */ -+ unsigned int fb_size; /* Size of the framebuffer */ -+ unsigned int frame_base; /* Offset of row 0, column 0 of a frame in fb */ -+ unsigned int frame_size; /* Size of the frame */ -+ -+ unsigned int row; /* Current row in virtual screen */ -+ unsigned int col; /* Current column in virtual screen */ -+ unsigned int s_offset; /* Saved cursor position in virtual screen */ -+ -+ unsigned int top; /* Top scroll row in virtual screen */ -+ unsigned int bot; /* Bottom scroll row in virtual screen */ -+ -+ int esc_args; /* Number of arguments for a normal escape sequence */ -+ unsigned int csi_args[NPAR]; /* CSI parameters */ -+ unsigned int index; /* Index in csi_args and counter for cgram characters generation */ -+ unsigned char cgram_index; /* Index of the cgram character to be created */ -+ unsigned char *cgram_buffer; /* Buffer for cgram operations in this driver */ -+ -+ unsigned short erase_char; /* Character to be used when erasing */ -+ unsigned char attr; /* Current attributes */ -+ unsigned char color; /* Color for normal intensity mode */ -+ unsigned char s_color; /* Saved color for normal intensity mode */ -+ unsigned char defcolor; /* Default color for normal intensity mode */ -+ unsigned char ulcolor; /* Color for underline mode */ -+ unsigned char halfcolor; /* Color for low intensity mode */ -+ unsigned char attributes; /* Packed attributes */ -+ unsigned char s_attributes; /* Saved packed attributes */ -+ -+ unsigned char *s_charmap; /* Saved character map for this driver */ -+ unsigned char *flip_buf; /* High speed flip buffer */ -+}; -+ -+/** Function prototypes **/ -+ -+/* Init/Cleanup the driver */ -+static int init_driver(struct lcd_struct *); -+static int cleanup_driver(struct lcd_struct *); -+ -+/* Read from/Write to the driver */ -+static void read_data(struct lcd_struct *, unsigned short *); -+static void read_cgram(struct lcd_struct *, unsigned char, unsigned char *); -+static void write_data(struct lcd_struct *, unsigned short); -+static void write_cgram(struct lcd_struct *, unsigned char, unsigned char *); -+ -+/* Input handlers */ -+static void cr(struct lcd_struct *); -+static void lf(struct lcd_struct *); -+static void control_char(struct lcd_struct *, unsigned char); -+static void handle_csi(struct lcd_struct *, unsigned char); -+static int handle_custom_esc(struct lcd_struct *, unsigned int); -+static int handle_esc(struct lcd_struct *, unsigned char); -+static void handle_input(struct lcd_struct *, unsigned short); -+ -+/* Low level file operations */ -+static ssize_t do_lcd_read(struct lcd_struct *, void *, size_t); -+static ssize_t do_lcd_write(struct lcd_struct *, const void *, size_t); -+static int do_lcd_open(struct lcd_struct *); -+static int do_lcd_release(struct lcd_struct *); -+static int do_lcd_ioctl(struct lcd_struct *, unsigned int, unsigned long); -+ -+/* Proc functions */ -+#ifdef USE_PROC -+static void create_driver_proc_entries(struct lcd_struct *); -+static void remove_driver_proc_entries(struct lcd_struct *); -+#endif -+ -+/* globals */ -+static unsigned int major = LCD_MAJOR; /* Major number for LCD-Linux device */ -+static unsigned short minors = LCD_MINORS; /* Minor numbers allocated for LCD-Linux */ -+static LIST_HEAD(lcd_drivers); /* Registered lcd drivers */ -+static struct semaphore drivers_sem; /* Locks the lcd_drivers list */ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) -+static struct class *lcd_linux_class; -+#endif -+#ifdef USE_PROC -+static struct proc_dir_entry *lcd_proc_root; -+#endif -+/* End of globals */ -+ -+#ifdef MODULE -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -+#include <linux/device.h> -+MODULE_ALIAS_CHARDEV_MAJOR(LCD_MAJOR); -+#endif -+MODULE_DESCRIPTION("Software layer to drive LCD displays under Linux."); -+MODULE_AUTHOR("Mattia Jona-Lasinio <mjona@users.sourceforge.net>"); -+#ifdef MODULE_LICENSE -+MODULE_LICENSE("GPL"); -+#endif -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -+module_param(minors, ushort, 0444); -+#else -+MODULE_PARM(minors, "h"); -+#endif -+MODULE_PARM_DESC(minors, "Minor numbers allocated for LCD-Linux (default: " string(LCD_MINORS) ")"); -+#else -+ -+/* -+ * Parse boot command line -+ * -+ * lcd=minors -+ */ -+static int __init lcd_linux_boot_init(char *cmdline) -+{ -+ unsigned short args; -+ -+ if ((args = simple_strtoul(cmdline, NULL, 0))) -+ minors = args; -+ -+ return (1); -+} -+ -+__setup("lcd=", lcd_linux_boot_init); -+#endif /* MODULE */ -+ -+/* Macros for iterator handling */ -+static inline unsigned int iterator_inc_(unsigned int iterator, const unsigned int module) -+{ -+ return ((++iterator)%module); -+} -+ -+static inline unsigned int iterator_dec_(unsigned int iterator, const unsigned int module) -+{ -+ return (iterator ? --iterator : module-1); -+} -+ -+#define iterator_inc(iterator, module) (iterator = iterator_inc_(iterator, module)) -+#define iterator_dec(iterator, module) (iterator = iterator_dec_(iterator, module)) -+ -+/* Uncomment the following two lines -+ * for non-atomic set_bit and clear_bit -+#define set_bit __set_bit -+#define clear_bit __clear_bit -+*/ -+ -+/************************************ -+ * Low level routines and utilities * -+ ************************************/ -+/* -+ * Set whether the address counter should be incremented -+ * or decremented after a Read/Write -+ */ -+static void address_mode(struct lcd_struct *p, int mode) -+{ -+ struct lcd_driver *driver = p->driver; -+ -+ if (mode > 0 && ! test_bit(INC_CURS_POS, &p->struct_flags)) { -+ if (driver->address_mode) -+ driver->address_mode(mode); -+ set_bit(INC_CURS_POS, &p->struct_flags); -+ } else if (mode < 0 && test_bit(INC_CURS_POS, &p->struct_flags)) { -+ if (driver->address_mode) -+ driver->address_mode(mode); -+ clear_bit(INC_CURS_POS, &p->struct_flags); -+ } -+} -+ -+/* WARNING!! This function returns an int because if iterator is not -+ * within the visible area of the frame it returns -1 -+ */ -+static inline int vs_to_frame_(struct lcd_struct *p, unsigned int iterator) -+{ -+ unsigned int vs_cols = p->par->vs_cols; -+ unsigned int row = iterator/vs_cols; -+ unsigned int col = iterator%vs_cols; -+ unsigned int frame_base_row = p->frame_base/vs_cols; -+ unsigned int frame_base_col = p->frame_base%vs_cols; -+ unsigned int frame_rows = p->par->cntr_rows*p->par->num_cntr; -+ unsigned int frame_cols = p->par->cntr_cols; -+ -+ if (row < frame_base_row || row >= frame_base_row+frame_rows) -+ return (-1); -+ if (col < frame_base_col || col >= frame_base_col+frame_cols) -+ return (-1); -+ -+ return ((row-frame_base_row)*frame_cols+(col-frame_base_col)); -+} -+ -+/* Given 'iterator' in vs, returns the offset in vs corresponding to the nearest -+ * visible offset in vs, or returns 'iterator' if it is already visible. -+ */ -+static unsigned int round_vs_(struct lcd_struct *p, unsigned int iterator) -+{ -+ unsigned int vs_cols = p->par->vs_cols; -+ unsigned int row = iterator/vs_cols; -+ unsigned int col = iterator%vs_cols; -+ unsigned int frame_base_row = p->frame_base/vs_cols; -+ unsigned int frame_base_col = p->frame_base%vs_cols; -+ unsigned int frame_rows = p->par->cntr_rows*p->par->num_cntr; -+ unsigned int frame_cols = p->par->cntr_cols; -+ -+ if (row < frame_base_row) -+ row = frame_base_row; -+ else if (row >= frame_base_row+frame_rows) -+ row = frame_base_row+(frame_rows-1); -+ -+ if (col < frame_base_col) -+ col = frame_base_col; -+ else if (col >= frame_base_col+frame_cols) -+ col = frame_base_col+(frame_cols-1); -+ -+ return ((row*vs_cols)+col); -+} -+ -+#define round_vs(p, iterator) (iterator = round_vs_(p, iterator)) -+ -+/* -+ * Sync the frame area starting at offset s, ending at offset e with fb content. -+ */ -+static void redraw_screen(struct lcd_struct *p, unsigned int s, unsigned int e) -+{ -+ unsigned int len; -+ unsigned int row = p->row, col = p->col; -+ unsigned int inc_set = test_bit(INC_CURS_POS, &p->struct_flags); -+ unsigned int frame_cols = p->par->cntr_cols; -+ unsigned int vs_cols = p->par->vs_cols; -+ unsigned long flags; -+ -+ if (s >= p->fb_size || e >= p->fb_size || e < s || e < p->frame_base) -+ return; -+ -+ round_vs(p, s); -+ round_vs(p, e); -+ -+ len = 1+e-s; -+ -+ if (! inc_set) -+ s = e; -+ -+ p->row = s/vs_cols; -+ p->col = s%vs_cols; -+ -+ flags = p->struct_flags; -+ clear_bit(NEED_WRAP, &p->struct_flags); -+ clear_bit(DECIM, &p->struct_flags); -+ set_bit(DECAWM, &p->struct_flags); -+ SET_INPUT_STATE(p, RAW); -+ if (inc_set) -+ while (len--) -+ if (vs_to_frame_(p, (p->row*vs_cols)+p->col) < 0) { -+ s += vs_cols-frame_cols; -+ len -= vs_cols-frame_cols-1; -+ p->row = s/vs_cols; -+ p->col = s%vs_cols; -+ } else { -+ write_data(p, p->fb[s++]); -+ if (test_bit(NEED_WRAP, &p->struct_flags)) { -+ cr(p); -+ lf(p); -+ } -+ } -+ else -+ while (len--) -+ if (vs_to_frame_(p, (p->row*vs_cols)+p->col) < 0) { -+ s -= vs_cols-frame_cols; -+ len -= vs_cols-frame_cols-1; -+ p->row = s/vs_cols; -+ p->col = s%vs_cols; -+ } else { -+ write_data(p, p->fb[s--]); -+ if (test_bit(NEED_WRAP, &p->struct_flags)) { -+ cr(p); -+ lf(p); -+ } -+ } -+ p->struct_flags = flags; -+ -+ p->row = row; p->col = col; -+} -+ -+static int make_cursor_visible(struct lcd_struct *p) -+{ -+ unsigned int vs_rows = p->par->vs_rows; -+ unsigned int vs_cols = p->par->vs_cols; -+ unsigned int frame_base, frame_base_row, frame_base_col; -+ unsigned int frame_rows = p->par->cntr_rows*p->par->num_cntr; -+ unsigned int frame_cols = p->par->cntr_cols; -+ unsigned int tmp = frame_cols/2; -+ -+ if (test_bit(INC_CURS_POS, &p->struct_flags)) { -+ /* cursor always on the lowest row of the display */ -+ frame_base_row = 0; -+ frame_base_col = 0; -+ if (p->row >= frame_rows) -+ frame_base_row = p->row-(frame_rows-1); -+ if (p->col >= frame_cols) { -+ frame_base_col = p->col-(frame_cols-1); -+ if (tmp) { -+ tmp = (tmp-(frame_base_col%tmp))%tmp; -+ if (frame_base_col+tmp <= vs_cols-frame_cols) -+ frame_base_col += tmp; -+ } -+ } -+ } else { -+ /* cursor always on the uppermost row of the display */ -+ frame_base_row = vs_rows-frame_rows; -+ frame_base_col = vs_cols-frame_cols; -+ if (p->row < vs_rows-frame_rows) -+ frame_base_row = p->row; -+ if (p->col < vs_cols-frame_cols) { -+ frame_base_col = p->col; -+ if (tmp) { -+ tmp = frame_base_col%tmp; -+ if (frame_base_col >= tmp) -+ frame_base_col -= tmp; -+ } -+ } -+ } -+ -+ frame_base = p->frame_base; -+ p->frame_base = (frame_base_row*vs_cols)+frame_base_col; -+ -+ return (frame_base != p->frame_base); -+} -+ -+/* -+ * Move the visible screen area at user's wish -+ */ -+static void browse_screen(struct lcd_struct *p, unsigned char dir) -+{ -+ unsigned int vs_rows = p->par->vs_rows; -+ unsigned int vs_cols = p->par->vs_cols; -+ unsigned int frame_base_row = p->frame_base/vs_cols; -+ unsigned int frame_base_col = p->frame_base%vs_cols; -+ unsigned int frame_rows = p->par->cntr_rows*p->par->num_cntr; -+ unsigned int frame_cols = p->par->cntr_cols; -+ -+ switch (dir) { -+ case '1': /* Up */ -+ if (! frame_base_row) -+ return; -+ --frame_base_row; -+ break; -+ case '2': /* Down */ -+ if (frame_base_row >= vs_rows-frame_rows) -+ return; -+ ++frame_base_row; -+ break; -+ case '3': /* Left */ -+ if (! frame_base_col) -+ return; -+ --frame_base_col; -+ break; -+ case '4': /* Right */ -+ if (frame_base_col >= vs_cols-frame_cols) -+ return; -+ ++frame_base_col; -+ break; -+ default: -+ return; -+ } -+ -+ p->frame_base = (frame_base_row*vs_cols)+frame_base_col; -+ redraw_screen(p, 0, p->fb_size-1); -+} -+ -+static inline void __memset_short(unsigned short *buf, unsigned short c, unsigned int len) -+{ -+ while (len--) -+ *buf++ = c; -+} -+ -+/* -+ * A memset implementation writing to LCD instead of memory locations. -+ */ -+static void lcd_memset(struct lcd_struct *p, unsigned int d, unsigned short c, unsigned int len) -+{ -+ unsigned int inc_set = test_bit(INC_CURS_POS, &p->struct_flags); -+ -+ if (! len || d >= p->fb_size) -+ return; -+ -+ if (inc_set && d+len > p->fb_size) -+ len = p->fb_size-d; -+ else if (! inc_set && len > d+1) -+ len = d+1; -+ -+ if (! inc_set) -+ d -= len-1; -+ __memset_short(p->fb+d, c, len); -+ -+ if (make_cursor_visible(p)) -+ redraw_screen(p, 0, p->fb_size-1); -+ else -+ redraw_screen(p, d, d+(len-1)); -+} -+ -+static inline void __memcpy_short(unsigned short *d, unsigned short *s, unsigned int len, int dir) -+{ -+ if (dir > 0) -+ while (len--) -+ *d++ = *s++; -+ else -+ while (len--) -+ *d-- = *s--; -+} -+ -+/* -+ * A memmove implementation writing to LCD instead of memory locations. -+ * Copy is done in a non destructive way. Display regions may overlap. -+ */ -+static void lcd_memmove(struct lcd_struct *p, unsigned int d, unsigned int s, unsigned int len) -+{ -+ if (! len || d == s || d >= p->fb_size || s >= p->fb_size) -+ return; -+ -+ if (d < s) { -+ if (test_bit(INC_CURS_POS, &p->struct_flags)) { -+ if (s+len > p->fb_size) -+ len = p->fb_size-s; -+ } else { -+ if (len > d+1) -+ len = d+1; -+ d -= len-1; -+ s -= len-1; -+ } -+ __memcpy_short(p->fb+d, p->fb+s, len, 1); -+ if (make_cursor_visible(p)) -+ redraw_screen(p, 0, p->fb_size-1); -+ else -+ redraw_screen(p, d, d+(len-1)); -+ } else { -+ if (test_bit(INC_CURS_POS, &p->struct_flags)) { -+ if (d+len > p->fb_size) -+ len = p->fb_size-d; -+ d += len-1; -+ s += len-1; -+ } else { -+ if (len > s+1) -+ len = s+1; -+ } -+ __memcpy_short(p->fb+d, p->fb+s, len, -1); -+ if (make_cursor_visible(p)) -+ redraw_screen(p, 0, p->fb_size-1); -+ else -+ redraw_screen(p, d-(len-1), d); -+ } -+} -+ -+static void scrup(struct lcd_struct *p, unsigned int t, unsigned int b, unsigned int nr) -+{ -+ unsigned int vs_rows = p->par->vs_rows; -+ unsigned int vs_cols = p->par->vs_cols; -+ unsigned int d, s; -+ -+ if (t+nr >= b) -+ nr = b-t-1; -+ if (b > vs_rows || t >= b || nr < 1) -+ return; -+ d = t*vs_cols; -+ s = (t+nr)*vs_cols; -+ if (test_bit(INC_CURS_POS, &p->struct_flags)) { -+ lcd_memmove(p, d, s, (b-t-nr)*vs_cols); -+ lcd_memset(p, d+(b-t-nr)*vs_cols, p->erase_char, nr*vs_cols); -+ } else { -+ lcd_memmove(p, d+(b-t-nr)*vs_cols-1, s+(b-t-nr)*vs_cols-1, (b-t-nr)*vs_cols); -+ lcd_memset(p, d+(b-t)*vs_cols-1, p->erase_char, nr*vs_cols); -+ } -+} -+ -+static void scrdown(struct lcd_struct *p, unsigned int t, unsigned int b, unsigned int nr) -+{ -+ unsigned int vs_rows = p->par->vs_rows; -+ unsigned int vs_cols = p->par->vs_cols; -+ unsigned int d, s; -+ -+ if (t+nr >= b) -+ nr = b-t-1; -+ if (b > vs_rows || t >= b || nr < 1) -+ return; -+ s = t*vs_cols; -+ d = (t+nr)*vs_cols; -+ if (test_bit(INC_CURS_POS, &p->struct_flags)) { -+ lcd_memmove(p, d, s, (b-t-nr)*vs_cols); -+ lcd_memset(p, s, p->erase_char, nr*vs_cols); -+ } else { -+ lcd_memmove(p, d+(b-t-nr)*vs_cols-1, s+(b-t-nr)*vs_cols-1, (b-t-nr)*vs_cols); -+ lcd_memset(p, s+nr*vs_cols-1, p->erase_char, nr*vs_cols); -+ } -+} -+ -+static void lcd_insert_char(struct lcd_struct *p, unsigned int nr) -+{ -+ unsigned int vs_cols = p->par->vs_cols; -+ unsigned int pos = (p->row*vs_cols)+p->col; -+ -+ clear_bit(NEED_WRAP, &p->struct_flags); -+ if (test_bit(INC_CURS_POS, &p->struct_flags)) -+ lcd_memmove(p, pos+nr, pos, vs_cols-p->col-nr); -+ else -+ lcd_memmove(p, pos-nr, pos, p->col-(nr-1)); -+ lcd_memset(p, pos, p->erase_char, nr); -+} -+ -+static void lcd_delete_char(struct lcd_struct *p, unsigned int nr) -+{ -+ unsigned int vs_cols = p->par->vs_cols; -+ unsigned int pos = (p->row*vs_cols)+p->col; -+ -+ clear_bit(NEED_WRAP, &p->struct_flags); -+ if (test_bit(INC_CURS_POS, &p->struct_flags)) { -+ lcd_memmove(p, pos, pos+nr, vs_cols-(p->col+nr)); -+ lcd_memset(p, (p->row+1)*vs_cols-nr, p->erase_char, nr); -+ } else { -+ lcd_memmove(p, pos, pos-nr, p->col-(nr-1)); -+ lcd_memset(p, (p->row*vs_cols)+(nr-1), p->erase_char, nr); -+ } -+} -+ -+ -+ -+ -+ -+/****************************************************************************** -+ ************************* VT 102 Emulation ************************* -+ ******************************************************************************/ -+ -+/********************** -+ * Control characters * -+ **********************/ -+static void bs(struct lcd_struct *p) -+{ -+ clear_bit(NEED_WRAP, &p->struct_flags); -+ if (test_bit(INC_CURS_POS, &p->struct_flags)) { -+ if (p->col) -+ --p->col; -+ } else { -+ if (p->col+1 < p->par->vs_cols) -+ ++p->col; -+ } -+} -+ -+static void cr(struct lcd_struct *p) -+{ -+ clear_bit(NEED_WRAP, &p->struct_flags); -+ p->col = (test_bit(INC_CURS_POS, &p->struct_flags) ? 0 : p->par->vs_cols-1); -+} -+ -+static void lf(struct lcd_struct *p) -+{ -+ clear_bit(NEED_WRAP, &p->struct_flags); -+ if (test_bit(INC_CURS_POS, &p->struct_flags)) { -+ if (p->row+1 == p->bot && INPUT_STATE(p) != RAW) { -+ make_cursor_visible(p); -+ scrup(p, p->top, p->bot, 1); -+ } else if (p->row+1 < p->par->vs_rows) -+ ++p->row; -+ } else { -+ if (p->row == p->top && INPUT_STATE(p) != RAW) { -+ make_cursor_visible(p); -+ scrdown(p, p->top, p->bot, 1); -+ } else if (p->row) -+ --p->row; -+ } -+} -+ -+static void ri(struct lcd_struct *p) -+{ -+ clear_bit(NEED_WRAP, &p->struct_flags); -+ if (test_bit(INC_CURS_POS, &p->struct_flags)) { -+ if (p->row == p->top) { -+ make_cursor_visible(p); -+ scrdown(p, p->top, p->bot, 1); -+ } else if (p->row) -+ --p->row; -+ } else { -+ if (p->row+1 == p->bot) { -+ make_cursor_visible(p); -+ scrup(p, p->top, p->bot, 1); -+ } else if (p->row+1 < p->par->vs_rows) -+ ++p->row; -+ } -+} -+ -+static void ff(struct lcd_struct *p) -+{ -+ unsigned int vs_rows = p->par->vs_rows; -+ unsigned int vs_cols = p->par->vs_cols; -+ -+ clear_bit(NEED_WRAP, &p->struct_flags); -+ if (p->driver->clear_display) { -+ p->driver->clear_display(); -+ __memset_short(p->fb, p->erase_char, p->fb_size); -+ __memset_short(p->display, p->erase_char, p->frame_size); -+ p->frame_base = 0; -+ } else if (test_bit(INC_CURS_POS, &p->struct_flags)) -+ lcd_memset(p, 0, p->erase_char, p->fb_size); -+ else -+ lcd_memset(p, p->fb_size-1, p->erase_char, p->fb_size); -+ -+ if (test_bit(INC_CURS_POS, &p->struct_flags)) -+ p->row = p->col = 0; -+ else { -+ p->row = vs_rows-1; -+ p->col = vs_cols-1; -+ } -+} -+ -+static void tab(struct lcd_struct *p) -+{ -+ struct lcd_parameters *par = p->par; -+ unsigned int i, vs_cols = par->vs_cols; -+ -+ clear_bit(NEED_WRAP, &p->struct_flags); -+ -+ if (! par->tabstop) -+ return; -+ -+ if (test_bit(INC_CURS_POS, &p->struct_flags)) { -+ i = par->tabstop-(p->col%par->tabstop); -+ if (p->col+i < vs_cols) -+ p->col += i; -+ } else { -+ i = p->col%par->tabstop; -+ i = (i == 0 ? par->tabstop : i); -+ if (p->col >= i) -+ p->col -= i; -+ } -+} -+ -+/* -+ * Control character handler. -+ */ -+static void control_char(struct lcd_struct *p, unsigned char val) -+{ -+ switch (val) { -+ case 0x08: /* BS: Back Space (^H) */ -+ case 0x7f: /* DEL: Delete */ -+ bs(p); -+ return; -+ -+ case 0x09: /* HT: Horizontal Tab (^I) */ -+ tab(p); -+ return; -+ -+ case 0x0c: /* FF: Form Feed (^L) */ -+ ff(p); -+ return; -+ -+ case 0x0a: /* LF: Line Feed (^J) */ -+ case 0x0b: /* VT: Vertical Tab (^K) */ -+ lf(p); -+ if (! test_bit(CRLF, &p->struct_flags)) -+ return; -+ -+ case 0x0d: /* CR: Carriage Return (^M) */ -+ cr(p); -+ return; -+ -+ case 0x16: /* SYN: Synchronous Idle (^V) */ -+ SET_INPUT_STATE(p, SYN); -+ return; -+ -+ case 0x1b: /* ESC: Start of escape sequence */ -+ SET_INPUT_STATE(p, ESC); -+ return; -+ -+ case 0x9b: /* CSI: Start of CSI escape sequence */ -+ memset(p->csi_args, 0, sizeof(p->csi_args)); -+ p->index = 0; -+ SET_INPUT_STATE(p, CSI); -+ return; -+ } -+} -+ -+static void gotoxy(struct lcd_struct *p, int new_col, int new_row) -+{ -+ unsigned int vs_rows = p->par->vs_rows; -+ unsigned int vs_cols = p->par->vs_cols; -+ -+ clear_bit(NEED_WRAP, &p->struct_flags); -+ if (new_row < 0) -+ p->row = 0; -+ else if (new_row >= vs_rows) -+ p->row = vs_rows-1; -+ else -+ p->row = new_row; -+ -+ if (new_col < 0) -+ p->col = 0; -+ else if (new_col >= vs_cols) -+ p->col = vs_cols-1; -+ else -+ p->col = new_col; -+ -+ if (make_cursor_visible(p)) -+ redraw_screen(p, 0, p->fb_size-1); -+} -+ -+ -+/****************************** -+ * ECMA-48 CSI ESC- sequences * -+ ******************************/ -+static void csi_at(struct lcd_struct *p, unsigned int nr) -+{ -+ unsigned int vs_cols = p->par->vs_cols; -+ -+ if (p->col+nr > vs_cols) -+ nr = vs_cols-p->col; -+ else if (! nr) -+ ++nr; -+ lcd_insert_char(p, nr); -+} -+ -+static void csi_J(struct lcd_struct *p, unsigned int action) -+{ -+ unsigned int vs_cols = p->par->vs_cols; -+ unsigned int pos = (p->row*vs_cols)+p->col; -+ -+ clear_bit(NEED_WRAP, &p->struct_flags); -+ switch (action) { -+ case 0: /* From cursor to end of display */ -+ lcd_memset(p, pos, p->erase_char, p->fb_size-pos); -+ return; -+ -+ case 1: /* From start of display to cursor */ -+ lcd_memset(p, 0, p->erase_char, pos+1); -+ return; -+ -+ case 2: /* Whole display */ -+ lcd_memset(p, 0, p->erase_char, p->fb_size); -+ return; -+ } -+} -+ -+static void csi_K(struct lcd_struct *p, unsigned int action) -+{ -+ unsigned int vs_cols = p->par->vs_cols; -+ unsigned int row_start = p->row*vs_cols; -+ -+ clear_bit(NEED_WRAP, &p->struct_flags); -+ switch (action) { -+ case 0: /* From cursor to end of line */ -+ lcd_memset(p, row_start+p->col, p->erase_char, vs_cols-p->col); -+ return; -+ -+ case 1: /* From start of line to cursor */ -+ lcd_memset(p, row_start, p->erase_char, p->col+1); -+ return; -+ -+ case 2: /* Whole line */ -+ lcd_memset(p, row_start, p->erase_char, vs_cols); -+ return; -+ } -+} -+ -+static void csi_L(struct lcd_struct *p, unsigned int nr) -+{ -+ unsigned int vs_rows = p->par->vs_rows; -+ unsigned int vs_cols = p->par->vs_cols; -+ -+ clear_bit(NEED_WRAP, &p->struct_flags); -+ if (p->row+nr > vs_rows) -+ nr = vs_rows-p->row; -+ else if (! nr) -+ ++nr;; -+ lcd_memmove(p, (p->row+nr)*vs_cols, p->row*vs_cols, (vs_rows-p->row-nr)*vs_cols); -+ lcd_memset(p, p->row*vs_cols, p->erase_char, nr*vs_cols); -+} -+ -+static void csi_M(struct lcd_struct *p, unsigned int nr) -+{ -+ unsigned int vs_rows = p->par->vs_rows; -+ unsigned int vs_cols = p->par->vs_cols; -+ -+ clear_bit(NEED_WRAP, &p->struct_flags); -+ if (p->row+nr > vs_rows) -+ nr = vs_rows-p->row; -+ else if (! nr) -+ ++nr;; -+ lcd_memmove(p, p->row*vs_cols, (p->row+nr)*vs_cols, (vs_rows-p->row-nr)*vs_cols); -+ lcd_memset(p, (vs_rows-nr)*vs_cols, p->erase_char, nr*vs_cols); -+} -+ -+static void csi_P(struct lcd_struct *p, unsigned int nr) -+{ -+ unsigned int vs_cols = p->par->vs_cols; -+ -+ if (p->col+nr > vs_cols) -+ nr = vs_cols-p->col; -+ else if (! nr) -+ ++nr; -+ lcd_delete_char(p, nr); -+} -+ -+static void csi_X(struct lcd_struct *p, unsigned int nr) -+{ -+ unsigned int vs_cols = p->par->vs_cols; -+ -+ clear_bit(NEED_WRAP, &p->struct_flags); -+ if (p->col+nr > vs_cols) -+ nr = vs_cols-p->col; -+ else if (! nr) -+ ++nr; -+ lcd_memset(p, (p->row*vs_cols)+p->col, p->erase_char, nr); -+} -+ -+static void csi_su(struct lcd_struct *p, unsigned char input) -+{ -+ unsigned int vs_cols = p->par->vs_cols; -+ -+ clear_bit(NEED_WRAP, &p->struct_flags); -+ if (input == 'u') { -+ p->row = p->s_offset/vs_cols; -+ p->col = p->s_offset%vs_cols; -+ p->color = p->s_color; -+ p->attributes = p->s_attributes; -+ return; -+ } -+ p->s_offset = (p->row*vs_cols)+p->col; -+ p->s_color = p->color; -+ p->s_attributes = p->attributes; -+} -+ -+static unsigned char build_attr(struct lcd_struct *p, unsigned char color, unsigned char intensity, -+ unsigned char blink, unsigned char underline, unsigned char reverse) -+{ -+ unsigned char attr; -+ -+ if (test_bit(CAN_DO_COLOR, &p->struct_flags)) { -+ attr = color; -+ if (underline) -+ attr = (attr & BG_MASK) | p->ulcolor; -+ else if (intensity == 0) -+ attr = (attr & BG_MASK) | p->halfcolor; -+ if (reverse) -+ attr = (attr & 0x88) | ((attr & 0x70) >> 4) | ((attr & 0x07) << 4); -+ if (blink) -+ attr ^= 0x80; -+ if (intensity == 2) -+ attr ^= 0x08; -+ } else { -+ attr = intensity; -+ attr |= (underline ? ULINE : 0x00); -+ attr |= (reverse ? REVERSE : 0x00); -+ attr |= (blink ? BLINK : 0x00); -+ } -+ -+ return (attr); -+} -+ -+static void update_attr(struct lcd_struct *p) -+{ -+ unsigned char intensity = p->attributes & 0x03; -+ unsigned char underline = (p->attributes >> 2) & 0x01; -+ unsigned char reverse = (p->attributes >> 3) & 0x01; -+ unsigned char blink = (p->attributes >> 7) & 0x01; -+ unsigned char decscnm = (p->struct_flags >> DECSCNM) & 0x01; -+ -+ p->attr = build_attr(p, p->color, intensity, blink, underline, reverse^decscnm); -+ p->erase_char = (build_attr(p, p->color, 1, blink, 0, decscnm) << 8) | ' '; -+} -+ -+static void default_attr(struct lcd_struct *p) -+{ -+ p->attributes = 0x01; -+ p->color = p->defcolor; -+} -+ -+static void lcd_invert_screen(struct lcd_struct *p, unsigned int offset, unsigned int len) -+{ -+ if (test_bit(CAN_DO_COLOR, &p->struct_flags)) -+ while (len--) { -+ p->fb[offset] = (p->fb[offset] & 0x88ff) | ((p->fb[offset] & 0x7000) >> 4) | ((p->fb[offset] & 0x0700) << 4); -+ ++offset; -+ } -+ else -+ while (len--) { -+ p->fb[offset] ^= 0x0800; -+ ++offset; -+ } -+} -+ -+static void csi_m(struct lcd_struct *p, unsigned int n) -+{ -+ int i, arg; -+ -+ for (i = 0; i <= n; ++i) -+ switch ((arg = p->csi_args[i])) -+ { -+ case 0: -+ default_attr(p); -+ break; -+ -+ case 1: -+ p->attributes = (p->attributes & ~I_MASK) | 2; -+ break; -+ -+ case 2: -+ p->attributes = (p->attributes & ~I_MASK) | 0; -+ break; -+ -+ case 4: -+ p->attributes |= ULINE; -+ break; -+ -+ case 5: -+ p->attributes |= BLINK; -+ break; -+ -+ case 7: -+ p->attributes |= REVERSE; -+ break; -+ -+ case 21: case 22: -+ p->attributes = (p->attributes & ~I_MASK) | 1; -+ break; -+ -+ case 24: -+ p->attributes &= ~ULINE; -+ break; -+ -+ case 25: -+ p->attributes &= ~BLINK; -+ break; -+ -+ case 27: -+ p->attributes &= ~REVERSE; -+ break; -+ -+ case 38: -+ p->attributes |= ULINE; -+ p->color = (p->color & BG_MASK) | (p->defcolor & FG_MASK); -+ break; -+ -+ case 39: -+ p->attributes &= ~ULINE; -+ p->color = (p->color & BG_MASK) | (p->defcolor & FG_MASK); -+ break; -+ -+ case 49: -+ p->color = (p->defcolor & BG_MASK) | (p->color & FG_MASK); -+ break; -+ -+ default: -+ if (arg >= 30 && arg <= 37) -+ p->color = (p->color & BG_MASK) | color_table[arg-30]; -+ else if (arg >= 40 && arg <= 47) -+ p->color = (p->color & FG_MASK) | (color_table[arg-40] << 4); -+ break; -+ } -+ -+ update_attr(p); -+} -+ -+static void csi_h(struct lcd_struct *p, unsigned char n) -+{ -+ switch (n) { -+ case 4: /* Set insert mode */ -+ set_bit(DECIM, &p->struct_flags); -+ return; -+ -+ case 5: /* Inverted screen mode */ -+ if (test_bit(QUES, &p->struct_flags) && ! test_bit(DECSCNM, &p->struct_flags)) { -+ set_bit(DECSCNM, &p->struct_flags); -+ lcd_invert_screen(p, 0, p->fb_size); -+ update_attr(p); -+ redraw_screen(p, 0, p->fb_size-1); -+ } -+ return; -+ -+ case 7: /* Set autowrap */ -+ if (test_bit(QUES, &p->struct_flags)) -+ set_bit(DECAWM, &p->struct_flags); -+ return; -+ -+ case 20: /* Set cr lf */ -+ set_bit(CRLF, &p->struct_flags); -+ return; -+ } -+} -+ -+static void csi_l(struct lcd_struct *p, unsigned char n) -+{ -+ switch (n) { -+ case 4: /* Reset insert mode */ -+ clear_bit(DECIM, &p->struct_flags); -+ return; -+ -+ case 5: /* Normal screen mode */ -+ if (test_bit(QUES, &p->struct_flags) && test_bit(DECSCNM, &p->struct_flags)) { -+ clear_bit(DECSCNM, &p->struct_flags); -+ lcd_invert_screen(p, 0, p->fb_size); -+ update_attr(p); -+ redraw_screen(p, 0, p->fb_size-1); -+ } -+ return; -+ -+ case 7: /* Reset autowrap */ -+ if (test_bit(QUES, &p->struct_flags)) -+ clear_bit(DECAWM, &p->struct_flags); -+ return; -+ -+ case 20: /* Reset cr lf */ -+ clear_bit(CRLF, &p->struct_flags); -+ return; -+ } -+} -+ -+static void csi_linux(struct lcd_struct *p) -+{ -+ switch (p->csi_args[0]) { -+ case 1: -+ if (test_bit(CAN_DO_COLOR, &p->struct_flags) && p->csi_args[1] < 16) { -+ p->ulcolor = color_table[p->csi_args[1]]; -+ if (p->attributes & ULINE) -+ update_attr(p); -+ } -+ return; -+ -+ case 2: -+ if (test_bit(CAN_DO_COLOR, &p->struct_flags) && p->csi_args[1] < 16) { -+ p->halfcolor = color_table[p->csi_args[1]]; -+ if ((p->attributes & I_MASK) == 0) -+ update_attr(p); -+ } -+ return; -+ -+ case 8: -+ p->defcolor = p->color; -+ default_attr(p); -+ update_attr(p); -+ return; -+ } -+} -+ -+static void csi_r(struct lcd_struct *p, unsigned int top, unsigned int bot) -+{ -+ /* Minimum allowed region is 2 lines */ -+ if (top < bot) { -+ p->top = top-1; -+ p->bot = bot; -+ gotoxy(p, 0, 0); -+ } -+} -+ -+/* -+ * ECMA-48 CSI ESC- sequence handler. -+ */ -+static void handle_csi(struct lcd_struct *p, unsigned char input) -+{ -+ if (p->index >= NPAR) { -+ SET_INPUT_STATE(p, NORMAL); -+ printk(KERN_NOTICE "LCD: too many parameters in CSI escape sequence\n"); -+ } else if (input == '?') { -+ set_bit(QUES, &p->struct_flags); -+ } else if (input == ';') { -+ ++p->index; -+ } else if (input >= '0' && input <= '9') { -+ p->csi_args[p->index] = (p->csi_args[p->index]*10)+(input-'0'); -+ } else { -+ SET_INPUT_STATE(p, NORMAL); -+ if (! test_bit(INC_CURS_POS, &p->struct_flags)) -+ return; -+ switch (input) { -+ case 'h': /* DECSET sequences and mode switches */ -+ csi_h(p, p->csi_args[0]); -+ clear_bit(QUES, &p->struct_flags); -+ return; -+ -+ case 'l': /* DECRST sequences and mode switches */ -+ csi_l(p, p->csi_args[0]); -+ clear_bit(QUES, &p->struct_flags); -+ return; -+ } -+ clear_bit(QUES, &p->struct_flags); -+ switch (input) { -+ case '@': /* Insert # Blank character */ -+ csi_at(p, p->csi_args[0]); -+ return; -+ -+ case 'G': case '`': /* Cursor to indicated column in current row */ -+ if (p->csi_args[0]) -+ --p->csi_args[0]; -+ gotoxy(p, p->csi_args[0], p->row); -+ return; -+ -+ case 'A': /* Cursor # rows Up */ -+ if (! p->csi_args[0]) -+ ++p->csi_args[0]; -+ gotoxy(p, p->col, p->row-p->csi_args[0]); -+ return; -+ -+ case 'B': case 'e': /* Cursor # rows Down */ -+ if (! p->csi_args[0]) -+ ++p->csi_args[0]; -+ gotoxy(p, p->col, p->row+p->csi_args[0]); -+ return; -+ -+ case 'C': case 'a': /* Cursor # columns Right */ -+ if (! p->csi_args[0]) -+ ++p->csi_args[0]; -+ gotoxy(p, p->col+p->csi_args[0], p->row); -+ return; -+ -+ case 'D': /* Cursor # columns Left */ -+ if (! p->csi_args[0]) -+ ++p->csi_args[0]; -+ gotoxy(p, p->col-p->csi_args[0], p->row); -+ return; -+ -+ case 'E': /* Cursor # rows Down, column 1 */ -+ if (! p->csi_args[0]) -+ ++p->csi_args[0]; -+ gotoxy(p, 0, p->row+p->csi_args[0]); -+ return; -+ -+ case 'F': /* Cursor # rows Up, column 1 */ -+ if (! p->csi_args[0]) -+ ++p->csi_args[0]; -+ gotoxy(p, 0, p->row-p->csi_args[0]); -+ return; -+ -+ case 'd': /* Cursor to indicated row in current column */ -+ if (p->csi_args[0]) -+ --p->csi_args[0]; -+ gotoxy(p, p->col, p->csi_args[0]); -+ return; -+ -+ case 'H': case 'f': /* Cursor to indicated row, column (origin 1, 1) */ -+ if (p->csi_args[0]) -+ --p->csi_args[0]; -+ if (p->csi_args[1]) -+ --p->csi_args[1]; -+ gotoxy(p, p->csi_args[1], p->csi_args[0]); -+ return; -+ -+ case 'J': /* Erase display */ -+ csi_J(p, p->csi_args[0]); -+ return; -+ -+ case 'K': /* Erase line */ -+ csi_K(p, p->csi_args[0]); -+ return; -+ -+ case 'L': /* Insert # blank lines */ -+ csi_L(p, p->csi_args[0]); -+ return; -+ -+ case 'M': /* Delete # blank lines */ -+ csi_M(p, p->csi_args[0]); -+ return; -+ -+ case 'P': /* Delete # characters on the current line */ -+ csi_P(p, p->csi_args[0]); -+ return; -+ -+ case 'X': /* Erase # characters on the current line */ -+ csi_X(p, p->csi_args[0]); -+ return; -+ -+ case 'm': /* Set video attributes */ -+ csi_m(p, p->index); -+ return; -+ -+ case 's': /* Save cursor position */ -+ case 'u': /* Restore cursor position */ -+ csi_su(p, input); -+ return; -+ -+ case ']': /* Linux private ESC [ ] sequence */ -+ csi_linux(p); -+ return; -+ -+ case 'r': /* Set the scrolling region */ -+ if (! p->csi_args[0]) -+ ++p->csi_args[0]; -+ if (! p->csi_args[1] || p->csi_args[1] > p->par->vs_rows) -+ p->csi_args[1] = p->par->vs_rows; -+ csi_r(p, p->csi_args[0], p->csi_args[1]); -+ return; -+ -+ /* Ignored escape sequences */ -+ case 'c': -+ case 'g': -+ case 'n': -+ case 'q': -+ return; -+ -+ default: -+ printk(KERN_NOTICE "LCD: unrecognized CSI escape sequence: ESC [ %u\n", input); -+ return; -+ } -+ } -+} -+ -+/* -+ * Custom ESC- sequence handler. -+ */ -+static int handle_custom_esc(struct lcd_struct *p, unsigned int _input) -+{ -+ unsigned char input = _input & 0xff; -+ struct lcd_parameters *par = p->par; -+ -+ if (_input & (~0xff)) { -+ switch (ESC_STATE(p)) { -+ case 's': -+ if (p->index++) { -+ unsigned char *buf = p->cgram_buffer+(p->cgram_index-par->cgram_char0)*par->cgram_bytes; -+ -+ buf[p->index-2] = input; -+ if (p->index == par->cgram_bytes+1) -+ write_cgram(p, p->cgram_index, buf); -+ } else { -+ if (! p->driver->write_cgram_char) { -+ printk(KERN_ERR "LCD: %s: missing function to write to CGRAM\n", p->par->name); -+ return (-1); -+ } -+ if (input >= par->cgram_char0 && input < par->cgram_char0+par->cgram_chars) -+ p->cgram_index = input; -+ else { -+ printk(KERN_NOTICE "LCD: bad CGRAM index\n"); -+ return (-1); -+ } -+ } -+ return (0); -+ -+ case 'G': -+ if (input >= par->cgram_char0 && input < par->cgram_char0+par->cgram_chars) -+ write_data(p, (p->attr << 8) | p->driver->charmap[input]); -+ else { -+ SET_INPUT_STATE(p, NORMAL); -+ handle_input(p, (p->attr << 8) | input); -+ } -+ return (0); -+ -+ case 'r': -+ if (input == '1') -+ address_mode(p, -1); -+ else if (input == '0') -+ address_mode(p, 1); -+ return (0); -+ -+ case 'A': -+ scrup(p, p->top, p->bot, input); -+ return (0); -+ -+ case 'B': -+ scrdown(p, p->top, p->bot, input); -+ return (0); -+ -+ case 'C': -+ browse_screen(p, input); -+ return (0); -+ } -+ } -+ -+ /* These are the custom ESC- sequences */ -+ switch (input) { -+ case 's': /* CGRAM select */ -+ if (p->cgram_buffer) { -+ SET_ESC_STATE(p, input); -+ p->index = 0; -+ return (par->cgram_bytes+1); -+ } else { -+ printk(KERN_NOTICE "LCD: driver %s does not support CGRAM chars\n", par->name); -+ return (0); -+ } -+ -+ case 'A': /* Scroll up */ -+ case 'B': /* Scroll down */ -+ case 'C': /* Browse screen */ -+ case 'G': /* Enter cgram mode */ -+ case 'r': /* Decrement counter after data read/write */ -+ SET_ESC_STATE(p, input); -+ return (1); -+ } -+ -+ return (-1); -+} -+ -+/* -+ * ESC- but not CSI sequence handler. -+ */ -+static int handle_esc(struct lcd_struct *p, unsigned char input) -+{ -+ int ret; -+ -+ SET_INPUT_STATE(p, NORMAL); -+ switch (input) { -+ case 'c': /* Reset */ -+ set_bit(DECAWM, &p->struct_flags); -+ set_bit(INC_CURS_POS, &p->struct_flags); -+ ff(p); -+ return (0); -+ -+ case 'D': /* Line Feed */ -+ lf(p); -+ return (0); -+ -+ case 'E': /* New Line */ -+ cr(p); -+ lf(p); -+ return (0); -+ -+ case 'M': /* Reverse Line Feed */ -+ ri(p); -+ return (0); -+ -+ case '7': -+ case '8': -+ csi_su(p, (input == '7' ? 's' : 'u')); -+ return (0); -+ -+ /* CSI: Start of CSI escape sequence */ -+ case '[': -+ memset(p->csi_args, 0, sizeof(p->csi_args)); -+ p->index = 0; -+ SET_INPUT_STATE(p, CSI); -+ return (0); -+ -+ /* Ignored escape sequences */ -+ case '(': -+ SET_INPUT_STATE(p, ESC_G0); -+ return (1); -+ -+ case ')': -+ SET_INPUT_STATE(p, ESC_G1); -+ return (1); -+ -+ case '#': -+ SET_INPUT_STATE(p, ESC_HASH); -+ return (1); -+ -+ case '%': -+ SET_INPUT_STATE(p, ESC_PERCENT); -+ return (1); -+ -+ case 'H': -+ case 'Z': -+ case '>': -+ case '=': -+ case ']': -+ return (0); -+ } -+ -+ /* These are the custom ESC- sequences */ -+ if ((ret = handle_custom_esc(p, input)) > 0) { -+ SET_INPUT_STATE(p, ARG); -+ return (ret); -+ } -+ -+ if (ret < 0 && p->driver->handle_custom_char) -+ if ((ret = p->driver->handle_custom_char(input)) > 0) { -+ SET_INPUT_STATE(p, ARG_DRIVER); -+ return (ret); -+ } -+ -+ if (ret < 0) -+ printk(KERN_NOTICE "LCD: unrecognized escape sequence: ESC %u\n", input); -+ -+ return (0); -+} -+ -+/* -+ * Main input handler. -+ */ -+static void handle_input(struct lcd_struct *p, unsigned short _input) -+{ -+ unsigned char input = _input & 0xff; -+ struct lcd_driver *driver = p->driver; -+ -+ switch (INPUT_STATE(p)) { -+ case NORMAL: -+ if (input < 0x20 || input == 0x9b) -+ control_char(p, input); -+ else -+ write_data(p, (_input & 0xff00) | driver->charmap[input]); -+ return; -+ -+ case RAW: -+ write_data(p, (_input & 0xff00) | driver->charmap[input]); -+ return; -+ -+ case SYN: -+ write_data(p, _input); -+ SET_INPUT_STATE(p, NORMAL); -+ return; -+ -+ case ESC: -+ p->esc_args = handle_esc(p, input); -+ return; -+ -+ case ESC_G0: -+ case ESC_G1: -+ case ESC_HASH: -+ case ESC_PERCENT: -+ if (! --p->esc_args) -+ SET_INPUT_STATE(p, NORMAL); -+ return; -+ -+ case CSI: -+ handle_csi(p, input); -+ return; -+ -+ case ARG: -+ if (handle_custom_esc(p, 0x100 | input) || ! --p->esc_args) -+ SET_INPUT_STATE(p, NORMAL); -+ return; -+ -+ case ARG_DRIVER: -+ if (driver->handle_custom_char(0x100 | input) || ! --p->esc_args) -+ SET_INPUT_STATE(p, NORMAL); -+ return; -+ } -+} -+ -+ -+ -+ -+ -+/*************************************** -+ * Read from/Write to display routines * -+ ***************************************/ -+ -+/* -+ * Write character data to the display. -+ */ -+static void write_data(struct lcd_struct *p, unsigned short data) -+{ -+ unsigned int vs_cols = p->par->vs_cols; -+ unsigned int pos; -+ int frame_pos; -+ -+ if (test_bit(NEED_WRAP, &p->struct_flags)) { -+ cr(p); -+ lf(p); -+ } -+ -+ if (test_bit(DECIM, &p->struct_flags)) -+ lcd_insert_char(p, 1); -+ -+ pos = (p->row*vs_cols)+p->col; -+ if ((frame_pos = vs_to_frame_(p, pos)) < 0) { -+ make_cursor_visible(p); -+ redraw_screen(p, 0, p->fb_size-1); -+ frame_pos = vs_to_frame_(p, pos); -+ } -+ -+ if (p->display[frame_pos] != data) { -+ p->driver->write_char(frame_pos, data); -+ p->display[frame_pos] = data; -+ } -+ -+ p->fb[pos] = data; -+ -+ if (test_bit(INC_CURS_POS, &p->struct_flags)) { -+ if (p->col+1 < vs_cols) -+ iterator_inc(p->col, vs_cols); -+ else if (test_bit(DECAWM, &p->struct_flags)) -+ set_bit(NEED_WRAP, &p->struct_flags); -+ } else { -+ if (p->col) -+ iterator_dec(p->col, vs_cols); -+ else if (test_bit(DECAWM, &p->struct_flags)) -+ set_bit(NEED_WRAP, &p->struct_flags); -+ } -+} -+ -+/* -+ * Write an entire CGRAM character to the display. -+ */ -+static void write_cgram(struct lcd_struct *p, unsigned char index, unsigned char *pixels) -+{ -+ unsigned int inc_set = test_bit(INC_CURS_POS, &p->struct_flags); -+ -+ if (! inc_set) -+ address_mode(p, 1); -+ -+ p->driver->write_cgram_char(index, pixels); -+ -+ if (! inc_set) -+ address_mode(p, -1); -+} -+ -+/* -+ * Read character data from the display. -+ */ -+static void read_data(struct lcd_struct *p, unsigned short *data) -+{ -+ unsigned int vs_rows = p->par->vs_rows; -+ unsigned int vs_cols = p->par->vs_cols; -+ unsigned int pos = (p->row*vs_cols)+p->col; -+ int frame_pos; -+ -+ if ((frame_pos = vs_to_frame_(p, pos)) < 0) { -+ make_cursor_visible(p); -+ redraw_screen(p, 0, p->fb_size-1); -+ frame_pos = vs_to_frame_(p, pos); -+ } -+ -+ p->driver->read_char(frame_pos, data); -+ -+ if (test_bit(INC_CURS_POS, &p->struct_flags)) { -+ iterator_inc(p->col, vs_cols); -+ if (! p->col) { -+ if (p->row+1 < vs_rows) -+ ++p->row; -+ } -+ } else { -+ iterator_dec(p->col, vs_cols); -+ if (p->col+1 == vs_cols) { -+ if (p->row) -+ --p->row; -+ } -+ } -+} -+ -+/* -+ * Read an entire CGRAM character from the display. -+ */ -+static void read_cgram(struct lcd_struct *p, unsigned char index, unsigned char *pixels) -+{ -+ unsigned int inc_set = test_bit(INC_CURS_POS, &p->struct_flags); -+ -+ if (! inc_set) -+ address_mode(p, 1); -+ -+ p->driver->read_cgram_char(index, pixels); -+ -+ if (! inc_set) -+ address_mode(p, -1); -+} -+ -+ -+ -+ -+ -+/**************************** -+ * Proc filesystem routines * -+ ****************************/ -+#ifdef USE_PROC -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) -+/* create_proc_read_entry is missing in 2.2.x kernels */ -+static struct proc_dir_entry *create_proc_read_entry(const char *name, mode_t mode, -+ struct proc_dir_entry *parent, read_proc_t *read_proc, void *data) -+{ -+ struct proc_dir_entry *res = create_proc_entry(name, mode, parent); -+ -+ if (res) { -+ res->read_proc = read_proc; -+ res->data = data; -+ } -+ -+ return (res); -+} -+#endif -+ -+static int proc_fb_read(char *buffer, char **start, off_t offset, int size, int *eof, void *data) -+{ -+ char *temp = buffer; -+ struct lcd_struct *p = (struct lcd_struct *)data; -+ unsigned int vs_cols; -+ static unsigned int nr, need_wrap; -+ static off_t _offset; -+ -+ down(&p->lcd_sem); -+ if (! offset) -+ _offset = 0; -+ if ((*eof = (_offset >= p->fb_size))) { -+ up(&p->lcd_sem); -+ return (0); -+ } -+ vs_cols = p->par->vs_cols; -+ if (size && need_wrap) { -+ need_wrap = 0; -+ temp += sprintf(temp, "\n"); -+ --size; -+ } -+ if (! nr) -+ nr = vs_cols; -+ *start = (char *)0; -+ while (size && nr) { -+ unsigned char c = (p->fb[_offset] & 0xff); -+ -+ temp += sprintf(temp, "%c", (c < 0x20 ? '·' : c)); -+ --size; -+ --nr; -+ ++*start; -+ ++_offset; -+ } -+ if (! nr) { -+ if (size) { -+ temp += sprintf(temp, "\n"); -+ --size; -+ } else -+ need_wrap = 1; -+ } -+ up(&p->lcd_sem); -+ -+ return (temp-buffer); -+} -+ -+static int proc_display_read(char *buffer, char **start, off_t offset, int size, int *eof, void *data) -+{ -+ char *temp = buffer; -+ struct lcd_struct *p = (struct lcd_struct *)data; -+ unsigned int i, frame_cols; -+ int frame_pos; -+ -+ down(&p->lcd_sem); -+ frame_cols = p->par->cntr_cols; -+ frame_pos = vs_to_frame_(p, (p->row*p->par->vs_cols)+p->col); -+ temp += sprintf(temp, " "); -+ for (i = 2; i <= frame_cols; i += 2) -+ temp += sprintf(temp, " %d", i%10); -+ temp += sprintf(temp, "\n"); -+ -+ temp += sprintf(temp, " +"); -+ for (i = 0; i < frame_cols; ++i) -+ temp += sprintf(temp, "-"); -+ temp += sprintf(temp, "+\n"); -+ -+ for (i = 0; i < p->frame_size; ++i) { -+ unsigned char c = (p->display[i] & 0xff); -+ -+ if (! (i%frame_cols)) -+ temp += sprintf(temp, "%2d |", 1+i/frame_cols); -+ if (frame_pos--) -+ temp += sprintf(temp, "%c", (c < 0x20 ? '·' : c)); -+ else -+ temp += sprintf(temp, "_"); -+ if (! ((i+1)%frame_cols)) -+ temp += sprintf(temp, "|\n"); -+ } -+ -+ temp += sprintf(temp, " +"); -+ for (i = 0; i < frame_cols; ++i) -+ temp += sprintf(temp, "-"); -+ temp += sprintf(temp, "+\n"); -+ up(&p->lcd_sem); -+ -+ return (temp-buffer); -+} -+ -+static int proc_charmap_read(char *buffer, char **start, off_t offset, int size, int *eof, void *data) -+{ -+ char *temp = buffer; -+ struct lcd_struct *p = (struct lcd_struct *)data; -+ unsigned char *charmap; -+ unsigned int i; -+ -+ down(&p->lcd_sem); -+ charmap = p->driver->charmap; -+ temp += sprintf(temp, "static unsigned char charmap[] = {"); -+ for (i = 0; i < 255; ++i) { -+ if (! (i & 7)) { -+ temp += sprintf(temp, "\n"); -+ if (! (i & 31)) -+ temp += sprintf(temp, "\n/* %d - %d */\n", i, i+31); -+ } -+ temp += sprintf(temp, "0x%.2x, ", *charmap++); -+ } -+ temp += sprintf(temp, "0x%.2x\n\n};\n", *charmap); -+ up(&p->lcd_sem); -+ -+ return (temp-buffer); -+} -+ -+static int proc_registered_drivers(char *buffer, char **start, off_t offset, int size, int *eof, void *data) -+{ -+ char *temp = buffer; -+ struct list_head *entry; -+ -+ down(&drivers_sem); -+ temp += sprintf(temp, "Registered drivers:\n"); -+ list_for_each(entry, &lcd_drivers) { -+ struct lcd_struct *p = list_entry(entry, struct lcd_struct, lcd_list); -+ -+ down(&p->lcd_sem); -+ temp += sprintf(temp, "%3d %s\n", p->par->minor, p->par->name); -+ up(&p->lcd_sem); -+ } -+ up(&drivers_sem); -+ -+ return (temp-buffer); -+} -+ -+static void create_driver_proc_entries(struct lcd_struct *p) -+{ -+ struct proc_dir_entry *driver_proc_root = p->driver->driver_proc_root; -+ int proc_level = 0; -+ -+ SET_PROC_LEVEL(p, proc_level); -+ if (create_proc_read_entry("framebuffer", 0, driver_proc_root, proc_fb_read, p) == NULL) { -+ printk(KERN_ERR "LCD: cannot create /proc/lcd/%s/framebuffer\n", p->par->name); -+ return; -+ } -+ SET_PROC_LEVEL(p, ++proc_level); -+ if (create_proc_read_entry("display", 0, driver_proc_root, proc_display_read, p) == NULL) { -+ printk(KERN_ERR "LCD: cannot create /proc/lcd/%s/display\n", p->par->name); -+ return; -+ } -+ SET_PROC_LEVEL(p, ++proc_level); -+ if (create_proc_read_entry("charmap.h", 0, driver_proc_root, proc_charmap_read, p) == NULL) { -+ printk(KERN_ERR "LCD: cannot create /proc/lcd/%s/charmap.h\n", p->par->name); -+ return; -+ } -+ SET_PROC_LEVEL(p, ++proc_level); -+} -+ -+static void remove_driver_proc_entries(struct lcd_struct *p) -+{ -+ struct proc_dir_entry *driver_proc_root = p->driver->driver_proc_root; -+ -+ switch (PROC_LEVEL(p)) { -+ case 3: -+ remove_proc_entry("charmap.h", driver_proc_root); -+ case 2: -+ remove_proc_entry("display", driver_proc_root); -+ case 1: -+ remove_proc_entry("framebuffer", driver_proc_root); -+ } -+ SET_PROC_LEVEL(p, 0); -+} -+#endif -+ -+ -+ -+ -+ -+/***************************** -+ * Low level file operations * -+ *****************************/ -+static ssize_t do_lcd_read(struct lcd_struct *p, void *buffer, size_t length) -+{ -+ unsigned int i; -+ unsigned short tmp; -+ -+ if (! p->refcount) -+ return (-ENXIO); -+ -+ if (! p->driver->read_char) { -+ printk(KERN_NOTICE "LCD: driver %s doesn't support reading\n", p->par->name); -+ return (-ENOSYS); -+ } -+ -+ if (test_bit(WITH_ATTR, &p->struct_flags)) -+ for (i = 0; i < length; ++i) { -+ read_data(p, &tmp); -+ ((unsigned short *)buffer)[i] = tmp; -+ } -+ else -+ for (i = 0; i < length; ++i) { -+ read_data(p, &tmp); -+ ((unsigned char *)buffer)[i] = tmp & 0xff; -+ } -+ -+ return (length); -+} -+ -+static ssize_t do_lcd_write(struct lcd_struct *p, const void *buffer, size_t length) -+{ -+ unsigned int i; -+ -+ if (! p->refcount) -+ return (-ENXIO); -+ -+ if (test_bit(WITH_ATTR, &p->struct_flags)) -+ for (i = 0; i < length; ++i) -+ handle_input(p, ((const unsigned short *)buffer)[i]); -+ else -+ for (i = 0; i < length; ++i) -+ handle_input(p, (p->attr << 8) | ((const unsigned char *)buffer)[i]); -+ -+ return (length); -+} -+ -+static int do_lcd_open(struct lcd_struct *p) -+{ -+ if (! p->refcount) { -+ if (p->driver->driver_module) { -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -+ if (! try_module_get(p->driver->driver_module)) -+ return (-EBUSY); -+#else -+ if (__MOD_IN_USE(p->driver->driver_module)) -+ return (-EBUSY); -+ -+ __MOD_INC_USE_COUNT(p->driver->driver_module); -+#endif -+ } -+ } -+ -+ ++p->refcount; -+ -+ return (0); -+} -+ -+static int do_lcd_release(struct lcd_struct *p) -+{ -+ if (! p->refcount) -+ return (0); -+ -+ if (p->refcount == 1) { -+ if (p->driver->driver_module) -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -+ module_put(p->driver->driver_module); -+#else -+ __MOD_DEC_USE_COUNT(p->driver->driver_module); -+#endif -+ } -+ -+ --p->refcount; -+ -+ return (0); -+} -+ -+static int cgram_ioctl(struct lcd_struct *p, unsigned int cmd, unsigned char *argp) -+{ -+ struct lcd_parameters *par = p->par; -+ unsigned int length = par->cgram_bytes; -+ unsigned char index = argp[0]; -+ unsigned char *buffer = argp+1; -+ unsigned char *cgram_buffer = p->cgram_buffer+(index-par->cgram_char0)*length; -+ -+ if (index < par->cgram_char0 || index >= par->cgram_char0+par->cgram_chars) -+ return (-EINVAL); -+ -+ if (cmd == LCDL_SET_CGRAM_CHAR) { -+ if (! p->driver->write_cgram_char) { -+ printk(KERN_ERR "LCD: %s: missing function to write to CGRAM\n", p->par->name); -+ return (-ENOSYS); -+ } -+ if (test_bit(USER_SPACE, &p->struct_flags)) { -+ if (copy_from_user(cgram_buffer, buffer, length)) -+ return (-EFAULT); -+ } else -+ memcpy(cgram_buffer, buffer, length); -+ write_cgram(p, index, cgram_buffer); -+ } else { -+ if (! p->driver->read_cgram_char) { -+ printk(KERN_ERR "LCD: %s: missing function to read from CGRAM or unable to read\n", p->par->name); -+ return (-ENOSYS); -+ } -+ read_cgram(p, index, cgram_buffer); -+ if (test_bit(USER_SPACE, &p->struct_flags)) { -+ if (copy_to_user(buffer, cgram_buffer, length)) -+ return (-EFAULT); -+ } else -+ memcpy(buffer, cgram_buffer, length); -+ } -+ -+ return (0); -+} -+ -+static int do_lcd_ioctl(struct lcd_struct *p, unsigned int cmd, unsigned long arg) -+{ -+ int i; -+ struct lcd_driver *driver = p->driver; -+ struct lcd_parameters *par = p->par; -+ unsigned char *argp = (unsigned char *)arg; -+ -+ if (! p->refcount) -+ return (-ENXIO); -+ -+ switch (cmd) { -+ case LCDL_SET_PARAM: -+ if ((i = cleanup_driver(p))) -+ return (i); -+ i = par->minor; -+ if (test_bit(USER_SPACE, &p->struct_flags)) { -+ if (copy_from_user(par, argp, sizeof(struct lcd_parameters))) -+ return (-EFAULT); -+ } else -+ memcpy(par, argp, sizeof(struct lcd_parameters)); -+ par->minor = i; -+ return (init_driver(p)); -+ -+ case LCDL_GET_PARAM: -+ if (test_bit(USER_SPACE, &p->struct_flags)) { -+ if (copy_to_user(argp, par, sizeof(struct lcd_parameters))) -+ return (-EFAULT); -+ } else -+ memcpy(argp, par, sizeof(struct lcd_parameters)); -+ return (0); -+ -+ case LCDL_RESET_CHARMAP: -+ for (i = 0; i < 256; ++i) -+ driver->charmap[i] = i; -+ return (0); -+ -+ case LCDL_CHARSUBST: -+ if (test_bit(USER_SPACE, &p->struct_flags)) { -+ get_user(i, argp); -+ get_user(driver->charmap[i], argp+1); -+ } else { -+ i = argp[0]; -+ driver->charmap[i] = argp[1]; -+ } -+ return (0); -+ -+ case LCDL_SAVE_CHARMAP: -+ memcpy(p->s_charmap, driver->charmap, 256); -+ return (0); -+ -+ case LCDL_RESTORE_CHARMAP: -+ memcpy(driver->charmap, p->s_charmap, 256); -+ return (0); -+ -+ case LCDL_SWAP_CHARMAP: -+ { -+ unsigned char *tmp; -+ -+ tmp = driver->charmap; -+ driver->charmap = p->s_charmap; -+ p->s_charmap = tmp; -+ } -+ return (0); -+ -+ case LCDL_RAW_MODE: -+ if (arg) { -+ clear_bit(NEED_WRAP, &p->struct_flags); -+ clear_bit(DECIM, &p->struct_flags); -+ clear_bit(DECAWM, &p->struct_flags); -+ SET_INPUT_STATE(p, RAW); -+ } else { -+ set_bit(DECAWM, &p->struct_flags); -+ SET_INPUT_STATE(p, NORMAL); -+ } -+ return (0); -+ -+ case LCDL_CLEAR_DISP: -+ ff(p); -+ return (0); -+ -+ case LCDL_SET_CGRAM_CHAR: -+ case LCDL_GET_CGRAM_CHAR: -+ if (p->cgram_buffer) -+ return (cgram_ioctl(p, cmd, argp)); -+ else -+ printk(KERN_NOTICE "LCD: driver %s does not support CGRAM chars\n", par->name); -+ return (0); -+ -+ case LCDL_SET_CHARMAP: -+ if (test_bit(USER_SPACE, &p->struct_flags)) { -+ if (copy_from_user(driver->charmap, argp, 256)) -+ return (-EFAULT); -+ } else -+ memcpy(driver->charmap, argp, 256); -+ return (0); -+ -+ case LCDL_GET_CHARMAP: -+ if (test_bit(USER_SPACE, &p->struct_flags)) { -+ if (copy_to_user(argp, driver->charmap, 256)) -+ return (-EFAULT); -+ } else -+ memcpy(argp, driver->charmap, 256); -+ return (0); -+ -+ case LCDL_MEMSET: -+ case LCDL_MEMMOVE: -+ { -+ int buf[3]; -+ -+ if (test_bit(USER_SPACE, &p->struct_flags)) { -+ if (copy_from_user(buf, argp, sizeof(buf))) -+ return (-EFAULT); -+ } else -+ memcpy(buf, argp, sizeof(buf)); -+ -+ if (cmd == LCDL_MEMSET) -+ lcd_memset(p, buf[0], buf[1], buf[2]); -+ else -+ lcd_memmove(p, buf[0], buf[1], buf[2]); -+ -+ return (0); -+ } -+ -+ default: -+ if (driver->handle_custom_ioctl) -+ return (driver->handle_custom_ioctl(cmd, arg, test_bit(USER_SPACE, &p->struct_flags))); -+ } -+ -+ return (-ENOIOCTLCMD); -+} -+ -+ -+ -+ -+ -+/************************************************** -+ * Kernel register/unregister lcd driver routines * -+ **************************************************/ -+/* -+ * Find a driver in lcd_drivers linked list -+ */ -+static struct lcd_struct *find_lcd_struct(unsigned short minor) -+{ -+ struct list_head *entry; -+ -+ list_for_each(entry, &lcd_drivers) { -+ struct lcd_struct *p = list_entry(entry, struct lcd_struct, lcd_list); -+ -+ if (p->par->minor == minor) -+ return (p); -+ } -+ -+ return (NULL); -+} -+ -+static void list_add_sorted(struct list_head *new) -+{ -+ struct list_head *entry; -+ unsigned short new_minor = (list_entry(new, struct lcd_struct, lcd_list))->par->minor; -+ -+ list_for_each(entry, &lcd_drivers) { -+ struct lcd_struct *p = list_entry(entry, struct lcd_struct, lcd_list); -+ -+ if (p->par->minor > new_minor) -+ break; -+ } -+ list_add_tail(new, entry); -+} -+ -+/* Exported function */ -+int lcd_register_driver(struct lcd_driver *driver, struct lcd_parameters *par) -+{ -+ int ret; -+ struct lcd_struct *p; -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) -+ struct device *lcd_device; -+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) -+ struct class_device *lcd_class_device; -+#endif -+ -+ if (! driver || ! par || par->minor >= minors) -+ return (-EINVAL); -+ if (! driver->write_char || ! driver->init_port || ! driver->cleanup_port) { -+ printk(KERN_ERR "LCD: missing functions\n"); -+ return (-EINVAL); -+ } -+ -+ down(&drivers_sem); -+ -+ if (find_lcd_struct(par->minor)) { -+ up(&drivers_sem); -+ return (-EBUSY); -+ } -+ -+ if ((p = (struct lcd_struct *)kmalloc(sizeof(struct lcd_struct), GFP_KERNEL)) == NULL) { -+ printk(KERN_ERR "LCD: memory allocation failed (kmalloc)\n"); -+ up(&drivers_sem); -+ return (-ENOMEM); -+ } -+ memset(p, 0, sizeof(struct lcd_struct)); -+ -+ p->driver = driver; -+ p->par = par; -+ p->refcount = 0; -+ SET_INIT_LEVEL(p, 0); -+ SET_INPUT_STATE(p, NORMAL); -+ set_bit(DECAWM, &p->struct_flags); -+ set_bit(INC_CURS_POS, &p->struct_flags); -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) -+ lcd_device = device_create(lcd_linux_class, NULL, MKDEV(major, par->minor), "%s", par->name); -+ if (IS_ERR(lcd_device)) { -+ kfree(p); -+ up(&drivers_sem); -+ return (PTR_ERR(lcd_device)); -+ } -+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 15) -+ lcd_class_device = class_device_create(lcd_linux_class, NULL, MKDEV(major, par->minor), NULL, "%s", par->name); -+ if (IS_ERR(lcd_class_device)) { -+ kfree(p); -+ up(&drivers_sem); -+ return (PTR_ERR(lcd_class_device)); -+ } -+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) -+ lcd_class_device = class_device_create(lcd_linux_class, MKDEV(major, par->minor), NULL, "%s", par->name); -+ if (IS_ERR(lcd_class_device)) { -+ kfree(p); -+ up(&drivers_sem); -+ return (PTR_ERR(lcd_class_device)); -+ } -+#endif -+ -+#ifdef USE_PROC -+ if (lcd_proc_root && (driver->driver_proc_root = proc_mkdir(par->name, lcd_proc_root)) == NULL) -+ printk(KERN_ERR "LCD: cannot create /proc/lcd/%s/\n", par->name); -+#endif -+ -+ if ((ret = init_driver(p))) { -+#ifdef USE_PROC -+ if (driver->driver_proc_root) -+ remove_proc_entry(p->par->name, lcd_proc_root); -+#endif -+ kfree(p); -+ up(&drivers_sem); -+ return (ret); -+ } -+ -+ init_MUTEX(&p->lcd_sem); -+ -+ list_add_sorted(&p->lcd_list); -+ -+ up(&drivers_sem); -+ -+#ifdef MODULE -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -+ try_module_get(THIS_MODULE); -+#else -+ MOD_INC_USE_COUNT; -+#endif -+#endif -+ -+ return (0); -+} -+EXPORT_SYMBOL(lcd_register_driver); -+ -+/* Exported function */ -+int lcd_unregister_driver(struct lcd_driver *driver, struct lcd_parameters *par) -+{ -+ int ret; -+ struct lcd_struct *p; -+ -+ if (! driver || ! par || par->minor >= minors) -+ return (-EINVAL); -+ -+ down(&drivers_sem); -+ -+ if ((p = find_lcd_struct(par->minor)) == NULL || p->driver != driver) { -+ printk(KERN_ERR "LCD: driver not found; lcd_unregister_driver failed\n"); -+ up(&drivers_sem); -+ return (-ENODEV); -+ } -+ -+ down(&p->lcd_sem); -+ -+ if (p->refcount) { -+ printk(KERN_ERR "LCD: driver busy; lcd_unregister_driver failed\n"); -+ up(&p->lcd_sem); -+ up(&drivers_sem); -+ return (-EBUSY); -+ } -+ -+ if ((ret = cleanup_driver(p))) { -+ up(&p->lcd_sem); -+ up(&drivers_sem); -+ return (ret); -+ } -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) -+ device_destroy(lcd_linux_class, MKDEV(major, par->minor)); -+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) -+ class_device_destroy(lcd_linux_class, MKDEV(major, par->minor)); -+#endif -+ -+#ifdef USE_PROC -+ if (p->driver->driver_proc_root) -+ remove_proc_entry(p->par->name, lcd_proc_root); -+#endif -+ -+ list_del(&p->lcd_list); -+ kfree(p); -+ -+ up(&drivers_sem); -+ -+#ifdef MODULE -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -+ module_put(THIS_MODULE); -+#else -+ MOD_DEC_USE_COUNT; -+#endif -+#endif -+ -+ return (0); -+} -+EXPORT_SYMBOL(lcd_unregister_driver); -+ -+ -+ -+ -+ -+/************************ -+ * Kernel I/O interface * -+ ************************/ -+/* Exported function */ -+int lcd_open(unsigned short minor, struct lcd_struct **pp) -+{ -+ int ret; -+ struct lcd_struct *p; -+ -+ down(&drivers_sem); -+ -+ if (minor >= minors || (*pp = p = find_lcd_struct(minor)) == NULL) { -+ printk(KERN_ERR "LCD: lcd_open failed. Device not found.\n"); -+ up(&drivers_sem); -+ return (-ENODEV); -+ } -+ -+ down(&p->lcd_sem); -+ up(&drivers_sem); -+ -+ ret = do_lcd_open(p); -+ -+ up(&p->lcd_sem); -+ -+ return (ret); -+} -+EXPORT_SYMBOL(lcd_open); -+ -+/* Exported function */ -+int lcd_close(struct lcd_struct **pp) -+{ -+ int ret; -+ struct lcd_struct *p; -+ -+ if (! pp || ! (p = *pp)) { -+ printk(KERN_ERR "LCD: NULL pointer in lcd_close\n"); -+ return (-ENODEV); -+ } -+ -+ down(&p->lcd_sem); -+ -+ if (! (ret = do_lcd_release(p))) -+ *pp = NULL; -+ -+ up(&p->lcd_sem); -+ -+ return (ret); -+} -+EXPORT_SYMBOL(lcd_close); -+ -+static inline loff_t offset_to_row_col(struct lcd_struct *p, loff_t offset) -+{ -+ unsigned long _offset = offset; -+ unsigned int vs_cols = p->par->vs_cols; -+ -+ gotoxy(p, _offset%vs_cols, _offset/vs_cols); -+ -+ return ((p->row*vs_cols)+p->col); -+} -+ -+/* Exported function */ -+ssize_t lcd_read(struct lcd_struct *p, void *bufp, size_t length, loff_t offset, unsigned int with_attr) -+{ -+ ssize_t ret = 0; -+ -+ if (! p) { -+ printk(KERN_ERR "LCD: NULL pointer in lcd_read\n"); -+ return (-ENODEV); -+ } -+ if (! bufp) -+ return (-EFAULT); -+ if (offset < 0 || offset >= p->fb_size) -+ return (-EINVAL); -+ -+ if (length+offset > p->fb_size) -+ length = p->fb_size-offset; -+ -+ if (with_attr) -+ set_bit(WITH_ATTR, &p->struct_flags); -+ -+ offset_to_row_col(p, offset); -+ ret = do_lcd_read(p, bufp, length); -+ -+ if (with_attr) -+ clear_bit(WITH_ATTR, &p->struct_flags); -+ -+ return (ret); -+} -+EXPORT_SYMBOL(lcd_read); -+ -+/* Exported function */ -+ssize_t lcd_write(struct lcd_struct *p, const void *bufp, size_t length, loff_t offset, unsigned int with_attr) -+{ -+ ssize_t ret; -+ -+ if (! p) { -+ printk(KERN_ERR "LCD: NULL pointer in lcd_write\n"); -+ return (-ENODEV); -+ } -+ if (! bufp) -+ return (-EFAULT); -+ if (offset < 0 || offset >= p->fb_size) -+ return (-EINVAL); -+ -+ if (with_attr) -+ set_bit(WITH_ATTR, &p->struct_flags); -+ -+ offset_to_row_col(p, offset); -+ ret = do_lcd_write(p, bufp, length); -+ -+ if (with_attr) -+ clear_bit(WITH_ATTR, &p->struct_flags); -+ -+ return (ret); -+} -+EXPORT_SYMBOL(lcd_write); -+ -+/* Exported function */ -+int lcd_ioctl(struct lcd_struct *p, unsigned int cmd, ...) -+{ -+ int ret; -+ unsigned long arg; -+ va_list ap; -+ -+ if (! p) { -+ printk(KERN_ERR "LCD: NULL pointer in lcd_ioctl\n"); -+ return (-ENODEV); -+ } -+ -+ down(&p->lcd_sem); -+ va_start(ap, cmd); -+ arg = va_arg(ap, unsigned long); -+ ret = do_lcd_ioctl(p, cmd, arg); -+ va_end(ap); -+ up(&p->lcd_sem); -+ -+ return (ret); -+} -+EXPORT_SYMBOL(lcd_ioctl); -+ -+ -+ -+ -+ -+/******************* -+ * File operations * -+ *******************/ -+static loff_t lcd_fops_llseek(struct file *filp, loff_t offset, int orig) -+{ -+ struct lcd_struct *p; -+ -+ if (! (p = filp->private_data)) -+ return (-ENODEV); -+ -+ down(&p->lcd_sem); -+ -+ switch (orig) { -+ case 0: -+ filp->f_pos = offset; -+ break; -+ -+ case 1: -+ filp->f_pos += offset; -+ break; -+ -+ default: -+ up(&p->lcd_sem); -+ return (-EINVAL); /* SEEK_END not supported */ -+ } -+ -+ filp->f_pos = offset_to_row_col(p, filp->f_pos); -+ -+ up(&p->lcd_sem); -+ -+ return (filp->f_pos); -+} -+ -+static ssize_t lcd_fops_read(struct file *filp, char *buffer, size_t length, loff_t *offp) -+{ -+ ssize_t ret = 0; -+ char *bufp = buffer; -+ struct lcd_struct *p; -+ -+ if (! bufp) -+ return (-EFAULT); -+ if (! (p = filp->private_data)) -+ return (-ENODEV); -+ -+ down(&p->lcd_sem); -+ -+ if (*offp < 0 || *offp >= p->fb_size) { -+ up(&p->lcd_sem); -+ return (-EINVAL); -+ } -+ -+ if (length+(*offp) > p->fb_size) -+ length = p->fb_size-(*offp); -+ -+ while (length) { -+ ret = (length > FLIP_BUF_SIZE ? FLIP_BUF_SIZE : length); -+ if ((ret = do_lcd_read(p, p->flip_buf, ret)) < 0) -+ break; -+ *offp = (p->row*p->par->vs_cols)+p->col; -+ if (copy_to_user(bufp, p->flip_buf, ret)) { -+ ret = -EFAULT; -+ break; -+ } -+ length -= ret; -+ bufp += ret; -+ ret = bufp-buffer; -+ if (length) -+ schedule(); -+ } -+ -+ up(&p->lcd_sem); -+ -+ return (ret); -+} -+ -+static ssize_t lcd_fops_write(struct file *filp, const char *buffer, size_t length, loff_t *offp) -+{ -+ ssize_t ret = 0; -+ const char *bufp = buffer; -+ struct lcd_struct *p; -+ -+ if (! bufp) -+ return (-EFAULT); -+ if (! (p = filp->private_data)) -+ return (-ENODEV); -+ -+ down(&p->lcd_sem); -+ -+ if (*offp < 0 || *offp >= p->fb_size) { -+ up(&p->lcd_sem); -+ return (-EINVAL); -+ } -+ -+ while (length) { -+ ret = (length > FLIP_BUF_SIZE ? FLIP_BUF_SIZE : length); -+ if (copy_from_user(p->flip_buf, bufp, ret)) { -+ ret = -EFAULT; -+ break; -+ } -+ if ((ret = do_lcd_write(p, p->flip_buf, ret)) < 0) -+ break; -+ *offp = (p->row*p->par->vs_cols)+p->col; -+ length -= ret; -+ bufp += ret; -+ ret = bufp-buffer; -+ if (length) -+ schedule(); -+ } -+ -+ up(&p->lcd_sem); -+ -+ return (ret); -+} -+ -+static int lcd_fops_open(struct inode *inop, struct file *filp) -+{ -+ unsigned short minor; -+ int ret; -+ struct lcd_struct *p; -+ -+ down(&drivers_sem); -+ -+ if ((minor = MINOR(inop->i_rdev)) >= minors || (filp->private_data = p = find_lcd_struct(minor)) == NULL) { -+ up(&drivers_sem); -+ return (-ENODEV); -+ } -+ -+ down(&p->lcd_sem); -+ up(&drivers_sem); -+ -+ ret = do_lcd_open(p); -+ -+ up(&p->lcd_sem); -+ -+ return (ret); -+} -+ -+static int lcd_fops_release(struct inode *inop, struct file *filp) -+{ -+ struct lcd_struct *p; -+ int ret; -+ -+ if (! (p = filp->private_data)) -+ return (-ENODEV); -+ -+ down(&p->lcd_sem); -+ -+ if (! (ret = do_lcd_release(p))) -+ filp->private_data = NULL; -+ -+ up(&p->lcd_sem); -+ -+ return (ret); -+} -+ -+static int lcd_fops_ioctl(struct inode *inop, struct file *filp, unsigned int cmd, unsigned long arg) -+{ -+ struct lcd_struct *p; -+ int ret; -+ -+ if (! (p = filp->private_data)) -+ return (-ENODEV); -+ -+ down(&p->lcd_sem); -+ -+ set_bit(USER_SPACE, &p->struct_flags); -+ ret = do_lcd_ioctl(p, cmd, arg); -+ clear_bit(USER_SPACE, &p->struct_flags); -+ -+ up(&p->lcd_sem); -+ -+ return (ret); -+} -+ -+static struct file_operations lcd_linux_fops = { -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) -+ .owner = THIS_MODULE, -+#endif -+ .llseek = lcd_fops_llseek, -+ .read = lcd_fops_read, -+ .write = lcd_fops_write, -+ .open = lcd_fops_open, -+ .release = lcd_fops_release, -+ .ioctl = lcd_fops_ioctl, -+}; -+ -+ -+ -+ -+ -+/******************************** -+ * Init/Cleanup driver routines * -+ ********************************/ -+static int do_init_driver(struct lcd_struct *p) -+{ -+ int ret, init_level; -+ struct lcd_driver *driver = p->driver; -+ struct lcd_parameters *par = p->par; -+ unsigned int frame_rows = par->cntr_rows*par->num_cntr; -+ unsigned int frame_cols = par->cntr_cols; -+ -+ switch ((init_level = INIT_LEVEL(p))) { -+ case 0: -+ if (frame_rows == 0 || frame_cols == 0 || ! par->name) { -+ printk(KERN_ERR "LCD: wrong lcd parameters\n"); -+ return (-EINVAL); -+ } -+ if (driver->validate_driver) { -+ if ((ret = driver->validate_driver()) < 0) { -+ printk(KERN_ERR "LCD: validate_driver failed\n"); -+ return (-EINVAL); -+ } else if (ret > 0) { -+ set_bit(CAN_DO_COLOR, &p->struct_flags); -+ p->defcolor = 0x07; -+ p->ulcolor = 0x0f; -+ p->halfcolor = 0x08; -+ } -+ } -+ default_attr(p); -+ update_attr(p); -+ p->frame_size = frame_rows*frame_cols; -+ if (par->vs_rows < frame_rows) -+ par->vs_rows = frame_rows; -+ if (par->vs_cols < frame_cols) -+ par->vs_cols = frame_cols; -+ p->fb_size = par->vs_rows*par->vs_cols; -+ -+ ret = sizeof(short)*p->fb_size; -+ ret += sizeof(short)*p->frame_size; -+ ret += FLIP_BUF_SIZE; -+ ret += (p->driver->charmap ? 256 : 512); -+ ret += par->cgram_chars*par->cgram_bytes; -+ if ((p->fb = (unsigned short *)vmalloc(ret)) == NULL) { -+ printk(KERN_ERR "LCD: memory allocation failed (vmalloc)\n"); -+ return (-ENOMEM); -+ } -+ __memset_short(p->fb, p->erase_char, p->fb_size+p->frame_size); -+ -+ p->display = p->fb+p->fb_size; -+ p->flip_buf = (unsigned char *)(p->display+p->frame_size); -+ -+ if (! p->driver->charmap) { -+ set_bit(NULL_CHARMAP, &p->struct_flags); -+ p->driver->charmap = p->flip_buf+FLIP_BUF_SIZE; -+ for (ret = 0; ret < 256; ++ret) -+ p->driver->charmap[ret] = ret; -+ p->s_charmap = p->driver->charmap+256; -+ } else -+ p->s_charmap = p->flip_buf+FLIP_BUF_SIZE; -+ memset(p->s_charmap, 0, 256); -+ -+ if (par->cgram_chars*par->cgram_bytes) { -+ p->cgram_buffer = p->s_charmap+256; -+ memset(p->cgram_buffer, 0, par->cgram_chars*par->cgram_bytes); -+ } else -+ p->cgram_buffer = NULL; -+ -+ p->frame_base = 0; -+ p->row = p->col = 0; -+ p->top = 0; -+ p->bot = par->vs_rows; -+ SET_INIT_LEVEL(p, ++init_level); -+ -+ case 1: -+ /* Initialize the communication port */ -+ if ((ret = driver->init_port())) { -+ printk(KERN_ERR "LCD: failure while initializing the communication port\n"); -+ return (ret); -+ } -+ SET_INIT_LEVEL(p, ++init_level); -+ -+ case 2: -+ /* Initialize LCD display */ -+ if (driver->init_display && (ret = driver->init_display())) { -+ printk(KERN_ERR "LCD: failure while initializing the display\n"); -+ return (ret); -+ } -+ -+#ifdef USE_PROC -+ /* Create entries in /proc/lcd/"driver" */ -+ if (driver->driver_proc_root) -+ create_driver_proc_entries(p); -+#endif -+ SET_INIT_LEVEL(p, ++init_level); -+ } -+ -+ return (0); -+} -+ -+static int do_cleanup_driver(struct lcd_struct *p) -+{ -+ int ret, init_level; -+ struct lcd_driver *driver = p->driver; -+ -+ switch ((init_level = INIT_LEVEL(p))) { -+ case 3: -+#ifdef USE_PROC -+ if (driver->driver_proc_root) -+ remove_driver_proc_entries(p); -+#endif -+ if (driver->cleanup_display && (ret = driver->cleanup_display())) { -+ printk(KERN_ERR "LCD: failure while cleaning the display\n"); -+ return (ret); -+ } -+ SET_INIT_LEVEL(p, --init_level); -+ -+ case 2: -+ if ((ret = driver->cleanup_port())) { -+ printk(KERN_ERR "LCD: failure while cleaning the communication port\n"); -+ return (ret); -+ } -+ SET_INIT_LEVEL(p, --init_level); -+ -+ case 1: -+ if (test_bit(NULL_CHARMAP, &p->struct_flags)) { -+ p->driver->charmap = NULL; -+ clear_bit(NULL_CHARMAP, &p->struct_flags); -+ } -+ vfree(p->fb); -+ p->fb = NULL; -+ SET_INIT_LEVEL(p, --init_level); -+ } -+ -+ return (0); -+} -+ -+static int init_driver(struct lcd_struct *p) -+{ -+ int ret; -+ -+ if ((ret = do_init_driver(p))) { -+ do_cleanup_driver(p); -+ printk(KERN_ERR "LCD: init_driver failed\n"); -+ } -+ -+ return (ret); -+} -+ -+static int cleanup_driver(struct lcd_struct *p) -+{ -+ int ret; -+ -+ if ((ret = do_cleanup_driver(p))) { -+ do_init_driver(p); -+ printk(KERN_ERR "LCD: cleanup_driver failed\n"); -+ } -+ -+ return (ret); -+} -+ -+ -+ -+ -+ -+/******************************** -+ * Init/Cleanup module routines * -+ ********************************/ -+static int __init lcd_linux_init_module(void) -+{ -+ int ret; -+ -+ if (! minors || minors > 256) -+ minors = LCD_MINORS; -+ -+ init_MUTEX(&drivers_sem); -+ -+ if ((ret = register_chrdev(major, LCD_LINUX_STRING, &lcd_linux_fops)) < 0) { -+ printk(KERN_ERR "LCD: register_chrdev failed\n"); -+ return (ret); -+ } -+ if (major == 0) -+ major = ret; -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) -+ if (IS_ERR((lcd_linux_class = class_create(THIS_MODULE, "lcd")))) { -+ ret = PTR_ERR(lcd_linux_class); -+ unregister_chrdev(major, LCD_LINUX_STRING); -+ return (ret); -+ } -+#endif -+ -+#ifdef USE_PROC -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) -+ if ((lcd_proc_root = proc_mkdir("lcd", NULL)) == NULL) -+#else -+ if ((lcd_proc_root = proc_mkdir("lcd", &proc_root)) == NULL) -+#endif -+ printk(KERN_ERR "LCD: cannot create /proc/lcd/\n"); -+ else if (create_proc_read_entry("drivers", 0, lcd_proc_root, proc_registered_drivers, NULL) == NULL) -+ printk(KERN_ERR "LCD: cannot create /proc/lcd/drivers\n"); -+#endif -+ -+ printk(KERN_INFO "LCD: --> LCD-Linux " LCD_LINUX_VERSION " <--\n"); -+ printk(KERN_INFO "LCD: --> Mattia Jona-Lasinio <mjona@users.sourceforge.net> <--\n" ); -+ -+ -+ return (0); -+} -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) -+static void __exit lcd_linux_cleanup_module(void) -+#else -+/* __exit is not defined in 2.2.x kernels */ -+static void lcd_linux_cleanup_module(void) -+#endif -+{ -+#ifdef USE_PROC -+ if (lcd_proc_root) { -+ remove_proc_entry("drivers", lcd_proc_root); -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) -+ remove_proc_entry("lcd", NULL); -+#else -+ remove_proc_entry("lcd", &proc_root); -+#endif -+ } -+#endif -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) -+ class_destroy(lcd_linux_class); -+#endif -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) -+ unregister_chrdev(major, LCD_LINUX_STRING); -+#else -+ if (unregister_chrdev(major, LCD_LINUX_STRING)) -+ printk(KERN_ERR "LCD: unregister_chrdev failed\n"); -+#endif -+} -+ -+module_init(lcd_linux_init_module) -+module_exit(lcd_linux_cleanup_module) -Index: linux-2.6.30.9/include/linux/hd44780.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.30.9/include/linux/hd44780.h 2009-11-24 02:01:42.000000000 +0100 -@@ -0,0 +1,46 @@ -+/* hd44780.h -+ * -+ * -+ * LCD-Linux: -+ * Driver for HD44780 compatible displays connected to the parallel port. -+ * -+ * HD44780 header file. -+ * -+ * Copyright (C) 2004 - 2007 Mattia Jona-Lasinio (mjona@users.sourceforge.net) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ */ -+ -+#ifndef HD44780_H -+#define HD44780_H -+ -+#include <linux/lcd-linux.h> -+ -+#define HD44780_VERSION LCD_LINUX_VERSION /* Version number */ -+#define HD44780_STRING "hd44780" -+ -+#define HD44780_MINOR 0 /* Minor number for the hd44780 driver */ -+ -+ -+/* flags */ -+#define HD44780_CHECK_BF 0x00000001 /* Do busy flag checking */ -+#define HD44780_4BITS_BUS 0x00000002 /* Set the bus length to 4 bits */ -+#define HD44780_5X10_FONT 0x00000004 /* Use 5x10 dots fonts */ -+ -+/* IOCTLs */ -+#define HD44780_READ_AC _IOR(LCD_MAJOR, 0x00, unsigned char *) -+ -+#endif /* HD44780 included */ -Index: linux-2.6.30.9/include/linux/lcd-linux.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.30.9/include/linux/lcd-linux.h 2009-11-24 02:01:42.000000000 +0100 -@@ -0,0 +1,151 @@ -+/* lcd-linux.h -+ * -+ * -+ * Software layer to drive LCD displays under Linux. -+ * -+ * External interface header file. -+ * -+ * Copyright (C) 2005 - 2007 Mattia Jona-Lasinio (mjona@users.sourceforge.net) -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ */ -+ -+#ifndef LCD_LINUX_H -+#define LCD_LINUX_H -+ -+#ifndef LCD_LINUX_MAIN -+#warning -+#warning LCD-Linux is still in development stage and -+#warning aims at speed and optimization. For these -+#warning reasons there is no guarantee of backward -+#warning compatibility between different LCD-Linux -+#warning versions. Be sure to use the lcd-linux.h -+#warning file of the same version as the module. -+#warning "http://lcd-linux.sourceforge.net/" -+#warning -+#endif -+ -+#define LCD_LINUX_VERSION "0.13.6" /* Version number */ -+#define LCD_LINUX_STRING "lcd" -+ -+#define LCD_MAJOR 120 /* Major number for this device -+ * Set this to 0 for dynamic allocation -+ */ -+#define LCD_MINORS 8 /* Minors allocated for LCD-Linux*/ -+ -+#include <linux/types.h> -+ -+#define str(s) #s -+#define string(s) str(s) -+ -+struct lcd_parameters { -+ const char *name; /* Driver's name */ -+ unsigned long flags; /* Flags (see documentation) */ -+ unsigned short minor; /* Minor number of the char device */ -+ unsigned short tabstop; /* Tab character length */ -+ unsigned short num_cntr; /* Controllers to drive */ -+ unsigned short cntr_rows; /* Rows per controller */ -+ unsigned short cntr_cols; /* Display columns */ -+ unsigned short vs_rows; /* Virtual screen rows */ -+ unsigned short vs_cols; /* Virtual screen columns */ -+ unsigned short cgram_chars; /* Number of user definable characters */ -+ unsigned short cgram_bytes; /* Number of bytes required to define a -+ * user definable character */ -+ unsigned char cgram_char0; /* Ascii of first user definable character */ -+}; -+ -+/* IOCTLs */ -+#include <asm/ioctl.h> -+#define LCDL_SET_PARAM _IOW(LCD_MAJOR, 0x80, struct lcd_parameters *) -+#define LCDL_GET_PARAM _IOR(LCD_MAJOR, 0x81, struct lcd_parameters *) -+#define LCDL_CHARSUBST _IOW(LCD_MAJOR, 0x82, unsigned char *) -+#define LCDL_RAW_MODE _IOW(LCD_MAJOR, 0x83, unsigned int) -+#define LCDL_RESET_CHARMAP _IO(LCD_MAJOR, 0x84) -+#define LCDL_SAVE_CHARMAP _IO(LCD_MAJOR, 0x85) -+#define LCDL_RESTORE_CHARMAP _IO(LCD_MAJOR, 0x86) -+#define LCDL_SWAP_CHARMAP _IO(LCD_MAJOR, 0x87) -+#define LCDL_CLEAR_DISP _IO(LCD_MAJOR, 0x88) -+#define LCDL_SET_CGRAM_CHAR _IOW(LCD_MAJOR, 0x89, unsigned char *) -+#define LCDL_GET_CGRAM_CHAR _IOR(LCD_MAJOR, 0x8a, unsigned char *) -+#define LCDL_SET_CHARMAP _IOW(LCD_MAJOR, 0x8b, unsigned char *) -+#define LCDL_GET_CHARMAP _IOR(LCD_MAJOR, 0x8c, unsigned char *) -+#define LCDL_MEMSET _IOW(LCD_MAJOR, 0x8d, unsigned int *) -+#define LCDL_MEMMOVE _IOW(LCD_MAJOR, 0x8e, unsigned int *) -+ -+ -+ -+#ifdef __KERNEL__ /* The rest is for kernel only */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+ -+ -+struct lcd_driver { -+ void (*read_char)(unsigned int offset, unsigned short *data); -+ void (*read_cgram_char)(unsigned char index, unsigned char *pixmap); -+ void (*write_char)(unsigned int offset, unsigned short data); -+ void (*write_cgram_char)(unsigned char index, unsigned char *pixmap); -+ void (*clear_display)(void); -+ void (*address_mode)(int mode); -+ int (*validate_driver)(void); -+ int (*init_display)(void); -+ int (*cleanup_display)(void); -+ int (*init_port)(void); -+ int (*cleanup_port)(void); -+ int (*handle_custom_char)(unsigned int data); -+ int (*handle_custom_ioctl)(unsigned int cmd, unsigned long arg, unsigned int arg_in_userspace); -+ -+ /* The character map to be used */ -+ unsigned char *charmap; -+ -+ /* The root where the driver can create its own proc files. -+ * Will be filled by the lcd-linux layer. -+ */ -+ struct proc_dir_entry *driver_proc_root; -+ -+ /* Set this field to 'driver_module_init' or call lcd_driver_setup -+ * just before registering the driver with lcd_register_driver. -+ */ -+ struct module *driver_module; -+}; -+ -+#ifdef MODULE -+#define driver_module_init THIS_MODULE -+#else -+#define driver_module_init NULL -+#endif -+ -+/* Always call lcd_driver_setup just before registering the driver -+ * with lcd_register_driver. -+ */ -+static inline void lcd_driver_setup(struct lcd_driver *p) -+{ -+ p->driver_module = driver_module_init; -+} -+ -+/* External interface */ -+struct lcd_struct; -+int lcd_register_driver(struct lcd_driver *drv, struct lcd_parameters *par); -+int lcd_unregister_driver(struct lcd_driver *drv, struct lcd_parameters *par); -+int lcd_open(unsigned short minor, struct lcd_struct **lcd); -+int lcd_close(struct lcd_struct **lcd); -+int lcd_ioctl(struct lcd_struct *lcd, unsigned int cmd, ...); -+ssize_t lcd_write(struct lcd_struct *lcd, const void *buffer, size_t length, loff_t offset, unsigned int); -+ssize_t lcd_read(struct lcd_struct *lcd, void *buffer, size_t length, loff_t offset, unsigned int); -+ -+#endif /* __KERNEL__ */ -+ -+#endif /* External interface included */ |