7480b28117c52da66dc2e1f48790619c13a5e811
[librecmc/librecmc.git] / target / linux / ep93xx / patches-2.6.30 / 002-lcd-linux-hd44780.patch
1 Index: linux-2.6.30.9/arch/arm/Kconfig
2 ===================================================================
3 --- linux-2.6.30.9.orig/arch/arm/Kconfig        2009-10-05 17:38:08.000000000 +0200
4 +++ linux-2.6.30.9/arch/arm/Kconfig     2009-11-24 02:01:42.000000000 +0100
5 @@ -1407,6 +1407,8 @@
6  
7  source "drivers/accessibility/Kconfig"
8  
9 +source "drivers/lcd-linux/Kconfig"
10 +
11  source "drivers/leds/Kconfig"
12  
13  source "drivers/rtc/Kconfig"
14 Index: linux-2.6.30.9/drivers/Makefile
15 ===================================================================
16 --- linux-2.6.30.9.orig/drivers/Makefile        2009-10-05 17:38:08.000000000 +0200
17 +++ linux-2.6.30.9/drivers/Makefile     2009-11-24 02:01:42.000000000 +0100
18 @@ -106,4 +106,5 @@
19  obj-$(CONFIG_SSB)              += ssb/
20  obj-$(CONFIG_VIRTIO)           += virtio/
21  obj-$(CONFIG_STAGING)          += staging/
22 +obj-$(CONFIG_LCD_LINUX)                += lcd-linux/
23  obj-y                          += platform/
24 Index: linux-2.6.30.9/drivers/lcd-linux/Config.in
25 ===================================================================
26 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
27 +++ linux-2.6.30.9/drivers/lcd-linux/Config.in  2009-11-24 02:01:42.000000000 +0100
28 @@ -0,0 +1,8 @@
29 +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
30 +   mainmenu_option next_comment
31 +   comment 'LCD support'
32 +
33 +   tristate 'LCD-Linux layer' CONFIG_LCD_LINUX
34 +   dep_tristate '  HD44780 controller' CONFIG_LCD_HD44780 $CONFIG_LCD_LINUX
35 +   endmenu
36 +fi
37 Index: linux-2.6.30.9/drivers/lcd-linux/Kconfig
38 ===================================================================
39 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
40 +++ linux-2.6.30.9/drivers/lcd-linux/Kconfig    2009-11-24 02:01:42.000000000 +0100
41 @@ -0,0 +1,33 @@
42 +menu "LCD-Linux support"
43 +       depends on EXPERIMENTAL
44 +
45 +config LCD_LINUX
46 +       tristate "LCD-Linux layer"
47 +       default m
48 +       help
49 +         LCD-Linux provides an easy way to drive LCD displays under
50 +         Linux by creating a character which can be read or written.
51 +         It features complete VT102 emulation and recognizes
52 +         many escape sequences. If you want to use it you must also
53 +         choose an appropriate driver, otherwise it will not be
54 +         very useful. For more information see
55 +         http://lcd-linux.sourceforge.net/
56 +
57 +         To compile LCD-Linux as a module, choose M here:
58 +         the module will be called lcd-linux.
59 +
60 +config LCD_HD44780
61 +       tristate "HD44780 controller"
62 +       depends on LCD_LINUX && MACH_SIM_ONE
63 +       default m
64 +       help
65 +         This is a LCD-Linux driver for LCD displays based on the
66 +         Hitachi HD44780 (and compatible) controllers connected
67 +         to the SimOne LCD port.
68 +
69 +         To compile this driver as a module, choose M here:
70 +         the module will be called hd44780.
71 +
72 +         If unsure, say N.
73 +
74 +endmenu
75 Index: linux-2.6.30.9/drivers/lcd-linux/Makefile
76 ===================================================================
77 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
78 +++ linux-2.6.30.9/drivers/lcd-linux/Makefile   2009-11-24 02:01:42.000000000 +0100
79 @@ -0,0 +1,8 @@
80 +#
81 +#
82 +# Standard Makefile to statically compile LCD-Linux into the kernel
83 +# Linux 2.6
84 +
85 +obj-$(CONFIG_LCD_LINUX)                += lcd-linux.o
86 +obj-$(CONFIG_LCD_HD44780)      += hd44780.o
87 +
88 Index: linux-2.6.30.9/drivers/lcd-linux/cgram/default.h
89 ===================================================================
90 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
91 +++ linux-2.6.30.9/drivers/lcd-linux/cgram/default.h    2009-11-24 02:01:42.000000000 +0100
92 @@ -0,0 +1,37 @@
93 +/* default.h
94 + *
95 + *
96 + *
97 + * Default user defined characters for lcdmod.
98 + *
99 + * Copyright (C) by Michael McLellan (mikey@cs.auckland.ac.nz)
100 + *
101 + *  This program is free software; you can redistribute it and/or modify
102 + *  it under the terms of the GNU General Public License as published by
103 + *  the Free Software Foundation; either version 2 of the License, or
104 + *  (at your option) any later version.
105 + *
106 + *  This program is distributed in the hope that it will be useful,
107 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
108 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
109 + *  GNU General Public License for more details.
110 + *
111 + *  You should have received a copy of the GNU General Public License
112 + *  along with this program; if not, write to the Free Software
113 + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
114 + *
115 + *
116 + */
117 +
118 +static void init_charmap(void)
119 +{
120 +}
121 +
122 +static unsigned char cg0[] = { 0x1f, 0x1f, 0x11, 0x0f, 0x11, 0x1e, 0x01, 0x1f };
123 +static unsigned char cg1[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f };
124 +static unsigned char cg2[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f };
125 +static unsigned char cg3[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f };
126 +static unsigned char cg4[] = { 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f };
127 +static unsigned char cg5[] = { 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f };
128 +static unsigned char cg6[] = { 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f };
129 +static unsigned char cg7[] = { 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f };
130 Index: linux-2.6.30.9/drivers/lcd-linux/charmap.h
131 ===================================================================
132 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
133 +++ linux-2.6.30.9/drivers/lcd-linux/charmap.h  2009-11-24 02:01:42.000000000 +0100
134 @@ -0,0 +1,79 @@
135 +/* charmap.h
136 + *
137 + *
138 + *
139 + * Character mapping for HD44780 devices by Mark Haemmerling <mail@markh.de>.
140 + *
141 + * Translates ISO 8859-1 to HD44780 charset.
142 + * HD44780 charset reference: http://markh.de/hd44780-charset.png
143 + *
144 + * Initial table taken from lcd.o Linux kernel driver by
145 + * Nils Faerber <nilsf@users.sourceforge.net>. Thanks!
146 + *
147 + * This file is released under the GNU General Public License. Refer to the
148 + * COPYING file distributed with this package.
149 + *
150 + * Following translations are being performed:
151 + * - maps umlaut accent characters to the corresponding umlaut characters
152 + * - maps other accent characters to the characters without accents
153 + * - maps beta (=ringel-S), micro and Yen
154 + *
155 + * Alternative mappings:
156 + * - #112 ("p") -> #240 (large "p"), orig. mapped -> #112
157 + * - #113 ("q") -> #241 (large "q"), orig. mapped -> #113
158 + *
159 + * HD44780 misses backslash
160 + *
161 + */
162 +
163 +static unsigned char charmap[] = {
164 +
165 +/* 0 - 31 */
166 +  0,   1,   2,   3,   4,   5,   6,   7,
167 +  8,   9,  10,  11,  12,  13,  14,  15,
168 + 16,  17,  18,  19,  20,  21,  22,  23,
169 + 24,  25,  26,  27,  28,  29,  30,  31,
170 +
171 +/* 32 - 63 */
172 + 32,  33,  34,  35,  36,  37,  38,  39,
173 + 40,  41,  42,  43,  44,  45,  46,  47,
174 + 48,  49,  50,  51,  52,  53,  54,  55,
175 + 56,  57,  58,  59,  60,  61,  62,  63,
176 +
177 +/* 64 - 95 */
178 + 64,  65,  66,  67,  68,  69,  70,  71,
179 + 72,  73,  74,  75,  76,  77,  78,  79,
180 + 80,  81,  82,  83,  84,  85,  86,  87,
181 + 88,  89,  90,  91,  47,  93,  94,  95,
182 +
183 +/* 96 - 127 */
184 + 96,  97,  98,  99, 100, 101, 102, 103,
185 +104, 105, 106, 107, 108, 109, 110, 111,
186 +112, 113, 114, 115, 116, 117, 118, 119,
187 +120, 121, 122, 123, 124, 125, 126, 127,
188 +
189 +/* 128 - 159 */
190 +128, 129, 130, 131, 132, 133, 134, 135,
191 +136, 137, 138, 139, 140, 141, 142, 143,
192 +144, 145, 146, 147, 148, 149, 150, 151,
193 +152, 153, 154, 155, 156, 157, 158, 159,
194 +
195 +/* 160 - 191 */
196 +160,  33, 236, 237, 164,  92, 124, 167,
197 + 34, 169, 170, 171, 172, 173, 174, 175,
198 +223, 177, 178, 179,  39, 249, 247, 165,
199 + 44, 185, 186, 187, 188, 189, 190,  63,
200 +
201 +/* 192 - 223 */
202 + 65,  65,  65,  65, 225,  65,  65,  67,
203 + 69,  69,  69,  69,  73,  73,  73,  73,
204 + 68,  78,  79,  79,  79,  79, 239, 120,
205 + 48,  85,  85,  85, 245,  89, 240, 226,
206 +
207 +/* 224 - 255 */
208 + 97,  97,  97,  97, 225,  97,  97,  99,
209 +101, 101, 101, 101, 105, 105, 105, 105,
210 +111, 110, 111, 111, 111, 111, 239, 253,
211 + 48, 117, 117, 117, 245, 121, 240, 255
212 +
213 +};
214 Index: linux-2.6.30.9/drivers/lcd-linux/commands.h
215 ===================================================================
216 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
217 +++ linux-2.6.30.9/drivers/lcd-linux/commands.h 2009-11-24 02:01:42.000000000 +0100
218 @@ -0,0 +1,77 @@
219 +/* commands.h
220 + *
221 + *
222 + *
223 + * LCD-Linux:
224 + * Driver for HD44780 compatible displays connected to the parallel port.
225 + *
226 + * HD44780 commands.
227 + *
228 + * Copyright (C) 2004 - 2007  Mattia Jona-Lasinio (mjona@users.sourceforge.net)
229 + *
230 + *  This program is free software; you can redistribute it and/or modify
231 + *  it under the terms of the GNU General Public License as published by
232 + *  the Free Software Foundation; either version 2 of the License, or
233 + *  (at your option) any later version.
234 + *
235 + *  This program is distributed in the hope that it will be useful,
236 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
237 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
238 + *  GNU General Public License for more details.
239 + *
240 + *  You should have received a copy of the GNU General Public License
241 + *  along with this program; if not, write to the Free Software
242 + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
243 + *
244 + */
245 +
246 +#ifndef HD44780_COMMANDS_H
247 +#define HD44780_COMMANDS_H
248 +
249 +/*** HD44780 Command Set ***/
250 +
251 +/* Clear Display*/
252 +#define CLR_DISP       0x01    /* Clear entire display; cursor at row 0, column 0 */
253 +
254 +/* Return Home */
255 +#define        RET_HOME        0x02    /* Cursor at row 0, column 0; display content doesn't change */
256 +
257 +/* Entry Mode Set */
258 +#define ENTRY_MODE_SET 0x04
259 +#define DISP_SHIFT_ON  (ENTRY_MODE_SET | 0x01)         /* Shift display, not cursor after data write */
260 +#define DISP_SHIFT_OFF (ENTRY_MODE_SET | 0x00)         /* Shift cursor, not display after data write */
261 +#define CURS_INC       (ENTRY_MODE_SET | 0x02)         /* Shift on the right after data read/write */
262 +#define CURS_DEC       (ENTRY_MODE_SET | 0x00)         /* Shift on the left after data read/write */
263 +
264 +/* Display on/off Control */
265 +#define DISP_ONOFF_CNTR        0x08
266 +#define BLINK_ON       (DISP_ONOFF_CNTR | 0x01)        /* Cursor blinking on */
267 +#define BLINK_OFF      (DISP_ONOFF_CNTR | 0x00)        /* Cursor blinking off */
268 +#define CURS_ON                (DISP_ONOFF_CNTR | 0x02)        /* Display Cursor */
269 +#define CURS_OFF       (DISP_ONOFF_CNTR | 0x00)        /* Hide Cursor */
270 +#define DISP_ON                (DISP_ONOFF_CNTR | 0x04)        /* Turn on display updating */
271 +#define DISP_OFF       (DISP_ONOFF_CNTR | 0x00)        /* Freeze display content */
272 +
273 +/* Cursor or Display Shift */
274 +#define CURS_DISP_SHIFT        0x10
275 +#define SHIFT_RIGHT    (CURS_DISP_SHIFT | 0x04)        /* Shift on the right */
276 +#define SHIFT_LEFT     (CURS_DISP_SHIFT | 0x00)        /* Shift on the left */
277 +#define SHIFT_DISP     (CURS_DISP_SHIFT | 0x08)        /* Shift display */
278 +#define SHIFT_CURS     (CURS_DISP_SHIFT | 0x00)        /* Shift cursor */
279 +
280 +/* Function Set */
281 +#define FUNC_SET       0x20
282 +#define FONT_5X10      (FUNC_SET | 0x04)       /* Select 5x10 dots font */
283 +#define FONT_5X8       (FUNC_SET | 0x00)       /* Select 5x8 dots font */
284 +#define DISP_2_LINES   (FUNC_SET | 0x08)       /* Select 2 lines display (only 5x8 font allowed) */
285 +#define DISP_1_LINE    (FUNC_SET | 0x00)       /* Select 1 line display */
286 +#define BUS_8_BITS     (FUNC_SET | 0x10)       /* Set 8 data bits */
287 +#define BUS_4_BITS     (FUNC_SET | 0x00)       /* Set 4 data bits */
288 +
289 +/* Set CGRAM Address */
290 +#define CGRAM_IO       0x40    /* Base CGRAM address */
291 +
292 +/* Set DDRAM Address */
293 +#define DDRAM_IO       0x80    /* Base DDRAM address */
294 +
295 +#endif /* commands included */
296 Index: linux-2.6.30.9/drivers/lcd-linux/config.h
297 ===================================================================
298 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
299 +++ linux-2.6.30.9/drivers/lcd-linux/config.h   2009-11-24 02:01:42.000000000 +0100
300 @@ -0,0 +1,73 @@
301 +/* config.h
302 + *
303 + *
304 + *
305 + * Configure file for LCD-Linux. Here you must specify your hardware setup and
306 + * timings constants. The default values will probably be right for you.
307 + *
308 + * Copyright (C) 2005 - 2007  Mattia Jona-Lasinio (mjona@users.sourceforge.net)
309 + *
310 + *  This program is free software; you can redistribute it and/or modify
311 + *  it under the terms of the GNU General Public License as published by
312 + *  the Free Software Foundation; either version 2 of the License, or
313 + *  (at your option) any later version.
314 + *
315 + *  This program is distributed in the hope that it will be useful,
316 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
317 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
318 + *  GNU General Public License for more details.
319 + *
320 + *  You should have received a copy of the GNU General Public License
321 + *  along with this program; if not, write to the Free Software
322 + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
323 + *
324 + *
325 + */
326 +
327 +/* Setup the default user defined characters in CGRAM */
328 +#include "cgram/default.h"
329 +
330 +/* Don't modify the default timing constants
331 + * unless you know what you are doing.
332 + */
333 +
334 +/* Execution times (in microseconds) */
335 +#define T_READ                 60      /* Read execution time (min 43 us) */
336 +#define T_WRITE                        60      /* Write execution time (min 43 us) */
337 +#define T_BF                   2       /* Busy flag polling time (min 1 us) */
338 +
339 +/* Timings in nanoseconds */
340 +#define T_AS                   200     /* Address set-up time (min 140 ns) */
341 +#define T_EH                   500     /* Enable high time (min 450 ns) */
342 +#define T_EL                   600     /* Enable low time (min 500 ns) */
343 +
344 +/* Various constants */
345 +#define DFLT_NUM_CNTR          1       /* Default number of controllers the display has */
346 +#define DFLT_CNTR_ROWS         2       /* Default number of rows per controller */
347 +#define DFLT_CNTR_COLS         16      /* Default number of columns the display has */
348 +#define DFLT_VS_ROWS           25      /* Default number of rows for the virtual screen */
349 +#define DFLT_VS_COLS           80      /* Default number of columns for the virtual screen */
350 +#define DFLT_TABSTOP           3       /* Default length of tabs */
351 +#define DFLT_FLAGS             (HD44780_CHECK_BF | HD44780_4BITS_BUS ) /* Default flags */
352 +
353 +#define MAX_CNTR_ROWS          4       /* The HD44780 supports up to 4 lines as a fake 2 lines mode */
354 +#define MAX_CNTR_COLS          80      /* The HD44780 supports up to 80 characters (1*80; 2*40; etc) */
355 +
356 +#define SETUP                  4
357 +#define HIGH_NIBBLE_WRITE(x)   (((x) >> (4-SETUP)) & (0x0f << SETUP))
358 +#define LOW_NIBBLE_WRITE(x)    (((x) << SETUP) & (0x0f << SETUP))
359 +#define HIGH_NIBBLE_READ(x)    (((x) & (0x0f << SETUP)) << (4-SETUP))
360 +#define LOW_NIBBLE_READ(x)     (((x) & (0x0f << SETUP)) >> SETUP)
361 +
362 +
363 +#define SIMONE_LCD_RS           EP93XX_GPIO_LINE_A(2) /* OUT */
364 +#define SIMONE_LCD_RD           EP93XX_GPIO_LINE_A(3) /* OUT */
365 +#define SIMONE_LCD_EN           EP93XX_GPIO_LINE_B(4) /* EGPIO12 OUT */
366 +#define SIMONE_LCD_BCKLIGHT     EP93XX_GPIO_LINE_B(5) /* EGPIO13 OUT */
367 +
368 +#define SIMONE_LCD_DATA0        EP93XX_GPIO_LINE_A(4)
369 +#define SIMONE_LCD_DATA1        EP93XX_GPIO_LINE_A(5)
370 +#define SIMONE_LCD_DATA2        EP93XX_GPIO_LINE_A(6)
371 +#define SIMONE_LCD_DATA3        EP93XX_GPIO_LINE_A(7)
372 +
373 +
374 Index: linux-2.6.30.9/drivers/lcd-linux/hd44780.c
375 ===================================================================
376 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
377 +++ linux-2.6.30.9/drivers/lcd-linux/hd44780.c  2009-11-24 02:05:29.000000000 +0100
378 @@ -0,0 +1,860 @@
379 +/* hd44780.c
380 + *
381 + *
382 + *
383 + * LCD-Linux:
384 + * Driver for HD44780 compatible displays connected to the parallel port.
385 + *
386 + * Copyright (C) 2005 - 2007  Mattia Jona-Lasinio (mjona@users.sourceforge.net)
387 + * Adapted to Sim.One Hardware by Nuccio Raciti (raciti.nuccio@gmail.com)
388 + *
389 + *  This program is free software; you can redistribute it and/or modify
390 + *  it under the terms of the GNU General Public License as published by
391 + *  the Free Software Foundation; either version 2 of the License, or
392 + *  (at your option) any later version.
393 + *
394 + *  This program is distributed in the hope that it will be useful,
395 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
396 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
397 + *  GNU General Public License for more details.
398 + *
399 + *  You should have received a copy of the GNU General Public License
400 + *  along with this program; if not, write to the Free Software
401 + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
402 + *
403 + */
404 +
405 +
406 +#include <linux/autoconf.h>
407 +
408 +
409 +#ifdef CONFIG_PROC_FS
410 +#define USE_PROC
411 +#else
412 +#undef USE_PROC
413 +#endif
414 +
415 +#include <linux/bitops.h>
416 +#include <linux/kernel.h>
417 +#include <linux/module.h>
418 +
419 +#include <linux/delay.h>
420 +#include <linux/fs.h>
421 +
422 +#include <asm/uaccess.h>
423 +#include <linux/init.h>
424 +
425 +#include <asm/io.h>
426 +#include <linux/ioport.h>
427 +#include <asm/gpio.h>
428 +
429 +#ifdef USE_PROC
430 +#include <linux/proc_fs.h>
431 +#endif
432 +
433 +#define LCD_LINUX_MAIN
434 +#include <linux/hd44780.h>
435 +
436 +#include "charmap.h"
437 +#include "commands.h"
438 +#include "config.h"
439 +
440 +/** Function prototypes **/
441 +static void read_display(unsigned char *byte, unsigned char bitmask);
442 +static void write_display(unsigned char byte, unsigned char bitmask);
443 +
444 +/* Initialization */
445 +static int hd44780_validate_driver(void);
446 +static int hd44780_init_port(void);
447 +static int hd44780_cleanup_port(void);
448 +static int hd44780_init_display(void);
449 +static int hd44780_cleanup_display(void);
450 +
451 +/* Write */
452 +static void hd44780_address_mode(int);
453 +static void hd44780_clear_display(void);
454 +static void hd44780_write_char(unsigned int, unsigned short);
455 +static void hd44780_write_cgram_char(unsigned char, unsigned char *);
456 +
457 +/* Read */
458 +static void check_bf(unsigned char);
459 +static void hd44780_read_char(unsigned int, unsigned short *);
460 +static void hd44780_read_cgram_char(unsigned char, unsigned char *);
461 +
462 +/* Input handling */
463 +static int hd44780_handle_custom_char(unsigned int);
464 +static int hd44780_handle_custom_ioctl(unsigned int,unsigned long , unsigned int);
465 +
466 +/* Proc operations */
467 +#ifdef USE_PROC
468 +static void create_proc_entries(void);
469 +static void remove_proc_entries(void);
470 +#endif
471 +
472 +/* hd44780 access */
473 +#define ACCESS_TO_READ    0
474 +#define ACCESS_TO_WRITE   1
475 +#define ACCESS_TO_DATA    2
476 +
477 +/* hd44780_flags */
478 +#define _CHECK_BF      0       /* Do busy-flag checking */
479 +#define _4BITS_BUS     1       /* The bus is 4 bits long */
480 +#define _5X10_FONT     2       /* Use 5x10 font */
481 +#define CURSOR_BLINK   3       /* Make the cursor blinking */
482 +#define SHOW_CURSOR    4       /* Make the cursor visible */
483 +#define DISPLAY_ON     5       /* Display status: on or off */
484 +#define INC_ADDR       6       /* Increment address after data read/write */
485 +#define BACKLIGHT      7       /* Display backlight: on or off */
486 +#define CGRAM_STATE    9       /* Controller status bitmask (bits 9->15): DDRAM or CGRAM access */
487 +#define ESC_MASK       0x00ff0000
488 +#define PROC_MASK      0x0f000000
489 +
490 +#define SET_STATE(state, mask) (hd44780_flags = (hd44780_flags & ~(mask)) | ((state) & (mask)))
491 +#define SET_ESC_STATE(state)   SET_STATE((state) << 16, ESC_MASK)
492 +#define SET_PROC_LEVEL(level)  SET_STATE((level) << 24, PROC_MASK)
493 +#define ESC_STATE              ((hd44780_flags & ESC_MASK) >> 16)
494 +#define PROC_LEVEL             ((hd44780_flags & PROC_MASK) >> 24)
495 +
496 +/* globals */
497 +static unsigned int disp_size;                 /* Display size (rows*columns) */
498 +static unsigned int disp_offset[1];    /* Physical cursor position on the display */
499 +static unsigned long hd44780_flags;            /* Driver flags for internal use only */
500 +
501 +static struct lcd_parameters par = {
502 +       .name           = HD44780_STRING,
503 +       .minor          = HD44780_MINOR,
504 +       .flags          = DFLT_FLAGS,
505 +       .tabstop        = DFLT_TABSTOP,
506 +       .num_cntr       = 1,
507 +       .cntr_rows      = DFLT_CNTR_ROWS,
508 +       .cntr_cols      = DFLT_CNTR_COLS,
509 +       .vs_rows        = DFLT_VS_ROWS,
510 +       .vs_cols        = DFLT_VS_COLS,
511 +       .cgram_chars    = 8,
512 +       .cgram_bytes    = 8,
513 +       .cgram_char0    = 0,
514 +};
515 +/* End of globals */
516 +
517 +#ifdef MODULE
518 +#include <linux/device.h>
519 +MODULE_ALIAS_CHARDEV(LCD_MAJOR, HD44780_MINOR);
520 +#include <linux/kmod.h>
521 +
522 +static unsigned short flags    = DFLT_FLAGS;
523 +static unsigned short tabstop  = DFLT_TABSTOP;
524 +static unsigned short cntr_rows        = DFLT_CNTR_ROWS;
525 +static unsigned short cntr_cols        = DFLT_CNTR_COLS;
526 +static unsigned short vs_rows  = DFLT_VS_ROWS;
527 +static unsigned short vs_cols  = DFLT_VS_COLS;
528 +static unsigned short minor    = HD44780_MINOR;
529 +
530 +MODULE_DESCRIPTION("LCD SimOne driver for HD44780 compatible controllers.");
531 +MODULE_AUTHOR("Nuccio Raciti (raciti.nuccio@gmail.com)");
532 +#ifdef MODULE_LICENSE
533 +MODULE_LICENSE("GPL");
534 +#endif
535 +module_param(flags,    ushort, 0444);
536 +module_param(cntr_rows,        ushort, 0444);
537 +module_param(cntr_cols,        ushort, 0444);
538 +module_param(vs_rows,  ushort, 0444);
539 +module_param(vs_cols,  ushort, 0444);
540 +module_param(tabstop,  ushort, 0444);
541 +module_param(minor,    ushort, 0444);
542 +
543 +MODULE_PARM_DESC(flags,                "Various flags (see Documentation)");
544 +MODULE_PARM_DESC(cntr_rows,    "Number of rows per controller on the LCD: 1, 2, 4 (default: " string(DFLT_CNTR_ROWS) ")");
545 +MODULE_PARM_DESC(cntr_cols,    "Number of columns on the LCD (default: " string(DFLT_CNTR_COLS) ", max: " string(MAX_CNTR_COLS) ")");
546 +MODULE_PARM_DESC(vs_rows,      "Number of rows of the virtual screen (default: " string(DFLT_VS_ROWS) ")");
547 +MODULE_PARM_DESC(vs_cols,      "Number of columns of the virtual screen (default: " string(DFLT_VS_COLS) ")");
548 +MODULE_PARM_DESC(tabstop,      "Tab character length (default: " string(DFLT_TABSTOP) ")");
549 +MODULE_PARM_DESC(minor,                "Assigned minor number (default: " string(HD44780_MINOR) ")");
550 +#else
551 +
552 +/*
553 + * Parse boot command line
554 + *
555 + * hd44780=cntr_rows,cntr_cols,vs_rows,vs_cols,flags,minor,tabstop
556 + */
557 +static int __init hd44780_boot_init(char *cmdline)
558 +{
559 +       char *str = cmdline;
560 +       int idx = 0;
561 +       unsigned short *args[] = {
562 +               &par.cntr_rows,
563 +               &par.cntr_cols,
564 +               &par.vs_rows,
565 +               &par.vs_cols,
566 +               &par.flags,
567 +               &par.num_cntr,
568 +               &par.minor,
569 +               &par.tabstop,
570 +       };
571 +
572 +       while (*cmdline && idx < (sizeof(args)/sizeof(unsigned short *))) {
573 +               switch (*str) {
574 +               case ',':
575 +                       *str++ = 0;
576 +               case 0:
577 +                       if (strlen(cmdline))
578 +                               *args[idx] = simple_strtoul(cmdline, NULL, 0);
579 +                       ++idx;
580 +                       cmdline = str;
581 +                       break;
582 +               default:
583 +                       ++str;
584 +                       break;
585 +               }
586 +       }
587 +
588 +       return (1);
589 +}
590 +
591 +__setup("hd44780=", hd44780_boot_init);
592 +#endif /* MODULE */
593 +
594 +/* Macros for iterator handling */
595 +static inline unsigned int iterator_inc_(unsigned int iterator, const unsigned int module)
596 +{
597 +    return ((++iterator)%module);
598 +}
599 +
600 +static inline unsigned int iterator_dec_(unsigned int iterator, const unsigned int module)
601 +{
602 +    return (iterator ? --iterator : module-1);
603 +}
604 +
605 +#define iterator_inc(iterator, module)         (iterator = iterator_inc_(iterator, module))
606 +#define iterator_dec(iterator, module)         (iterator = iterator_dec_(iterator, module))
607 +
608 +static inline void set_lines(unsigned char bitmask)
609 +{
610 +    gpio_set_value(SIMONE_LCD_EN, 0);  /* Disable */
611 +
612 +    if(bitmask & ACCESS_TO_WRITE ) {
613 +        gpio_direction_output (SIMONE_LCD_DATA0   , 0);
614 +        gpio_direction_output (SIMONE_LCD_DATA1   , 0);
615 +        gpio_direction_output (SIMONE_LCD_DATA2   , 0);
616 +        gpio_direction_output (SIMONE_LCD_DATA3   , 0);
617 +        gpio_set_value(SIMONE_LCD_RD, 0);  /* Write */
618 +    } else {
619 +
620 +        gpio_direction_input (SIMONE_LCD_DATA0);
621 +        gpio_direction_input (SIMONE_LCD_DATA1);
622 +        gpio_direction_input (SIMONE_LCD_DATA2);
623 +        gpio_direction_input (SIMONE_LCD_DATA3);
624 +        gpio_set_value(SIMONE_LCD_RD, 1);  /* Read */
625 +    }
626 +
627 +    if(bitmask & ACCESS_TO_DATA )
628 +        gpio_set_value(SIMONE_LCD_RS, 1);  /* Data */
629 +    else
630 +        gpio_set_value(SIMONE_LCD_RS, 0);  /* Cmds*/
631 +
632 +    if(test_bit(BACKLIGHT, &hd44780_flags))
633 +        gpio_set_value(SIMONE_LCD_BCKLIGHT, 1);
634 +    else
635 +        gpio_set_value(SIMONE_LCD_BCKLIGHT, 0);
636 +}
637 +
638 +
639 +/* Low level read from the display */
640 +static inline unsigned char __read_display(unsigned char bitmask)
641 +{
642 +    unsigned char byte;
643 +
644 +    set_lines (bitmask);
645 +
646 +    ndelay(T_AS); /* Address set-up time */
647 +    gpio_set_value(SIMONE_LCD_EN, 1); /* Enable */
648 +    ndelay(T_EH);/* Enable high time */
649 +
650 +    byte  = (gpio_get_value(SIMONE_LCD_DATA0) << 4);
651 +    byte |= (gpio_get_value(SIMONE_LCD_DATA1) << 5);
652 +    byte |= (gpio_get_value(SIMONE_LCD_DATA2) << 6);
653 +    byte |= (gpio_get_value(SIMONE_LCD_DATA3) << 7);
654 +
655 +    gpio_set_value(SIMONE_LCD_EN, 0); /* Disable */
656 +
657 +    ndelay(T_EL); /* Enable low time */
658 +
659 +
660 +   return (byte);
661 +
662 +}
663 +
664 +/* Low level write to the display */
665 +static inline void __write_display(unsigned char data, unsigned char bitmask)
666 +{
667 +    set_lines(bitmask);
668 +
669 +    if(data & 0x10)
670 +        gpio_set_value(SIMONE_LCD_DATA0, 1);
671 +    else
672 +        gpio_set_value(SIMONE_LCD_DATA0, 0);
673 +
674 +    if(data & 0x20)
675 +        gpio_set_value(SIMONE_LCD_DATA1, 1);
676 +    else
677 +        gpio_set_value(SIMONE_LCD_DATA1, 0);
678 +
679 +    if(data & 0x40)
680 +        gpio_set_value(SIMONE_LCD_DATA2, 1);
681 +    else
682 +        gpio_set_value(SIMONE_LCD_DATA2, 0);
683 +
684 +    if(data & 0x80)
685 +        gpio_set_value(SIMONE_LCD_DATA3, 1);
686 +    else
687 +        gpio_set_value(SIMONE_LCD_DATA3, 0);
688 +
689 +    ndelay(T_AS); /* Address set-up time */
690 +    gpio_set_value(SIMONE_LCD_EN, 1);
691 +    ndelay(T_EH); /* Enable high time */
692 +
693 +    gpio_set_value(SIMONE_LCD_EN, 0); /* Disable */
694 +    ndelay(T_EL);  /* Enable low time */
695 +}
696 +
697 +
698 +/* Read data from the display (4 bit bus, check busy flag) */
699 +static void read_display (unsigned char *byte,unsigned char bitmask)
700 +{
701 +    if(bitmask) check_bf(bitmask);
702 +    *byte = HIGH_NIBBLE_READ(__read_display(bitmask));
703 +    if(bitmask) check_bf(bitmask);
704 +    *byte |= LOW_NIBBLE_READ(__read_display(bitmask));
705 +}
706 +
707 +
708 +/* Output commands or data to the display (4 bit bus, check busy flag) */
709 +static void write_display(unsigned char byte,unsigned char bitmask)
710 +{
711 +    check_bf(bitmask);
712 +    __write_display(HIGH_NIBBLE_WRITE(byte),bitmask);
713 +     check_bf(bitmask);
714 +    __write_display(LOW_NIBBLE_WRITE(byte),bitmask);
715 +}
716 +
717 +
718 +/* Read Address Counter AC from the display */
719 +static unsigned char read_ac(unsigned char bitmask)
720 +{
721 +    unsigned char byte;
722 +
723 +    read_display(&byte, bitmask);
724 +
725 +    return (byte);
726 +}
727 +
728 +
729 +/* Do busy-flag check */
730 +static void  check_bf(unsigned char bitmask)
731 +{
732 +    unsigned int timeout = 20;
733 +    static unsigned char do_check_bf = 5;
734 +    gpio_set_value(SIMONE_LCD_EN, 0);  /* Disable */
735 +
736 +    gpio_direction_input (SIMONE_LCD_DATA0);
737 +    gpio_direction_input (SIMONE_LCD_DATA1);
738 +    gpio_direction_input (SIMONE_LCD_DATA2);
739 +    gpio_direction_input (SIMONE_LCD_DATA3);
740 +
741 +    gpio_set_value(SIMONE_LCD_RD, 1);  /* Read */
742 +    gpio_set_value(SIMONE_LCD_RS, 0);  /* Instru */
743 +
744 +    ndelay(T_AS); /* Address set-up time */
745 +    gpio_set_value(SIMONE_LCD_EN, 1); /* Enable */
746 +    ndelay(T_EH);/* Enable high time */
747 +
748 +    do{
749 +       udelay(T_BF);
750 +    } while (gpio_get_value(SIMONE_LCD_DATA3) && --timeout);
751 +
752 +    if (! timeout) {
753 +        if (! --do_check_bf) {
754 +            printk(KERN_NOTICE "hd44780 error: is the LCD connected?\n");
755 +       }
756 +    }
757 +
758 +    gpio_set_value(SIMONE_LCD_EN, 0); /* Disable */
759 +
760 +    ndelay(T_EL); /* Enable low time */
761 +}
762 +
763 +/* Send commands to the display */
764 +static void write_command(unsigned char command)
765 +{
766 +    write_display(command, ACCESS_TO_WRITE);
767 +
768 +    if (command <= 0x03)
769 +        mdelay(2);
770 +}
771 +
772 +static inline void set_cursor(unsigned int offset)
773 +{
774 +    unsigned int disp_number = offset/disp_size;
775 +    unsigned int local_offset = offset%disp_size;
776 +
777 +    if (disp_offset[disp_number] != local_offset || test_bit(CGRAM_STATE+disp_number, &hd44780_flags)) {
778 +        unsigned int disp_row = local_offset/par.cntr_cols;
779 +        unsigned int disp_column = local_offset%par.cntr_cols;
780 +
781 +        write_command(DDRAM_IO | ((disp_row%2)*0x40) | (((disp_row >= 2)*par.cntr_cols)+disp_column));
782 +        clear_bit(CGRAM_STATE+disp_number, &hd44780_flags);
783 +               disp_offset[disp_number] = local_offset;
784 +       }
785 +}
786 +
787 +/* HD44780 DDRAM addresses are consecutive only when
788 + * the cursor moves on the same row of the display.
789 + * Every time the row of the cursor changes we invalidate
790 + * the cursor position to force hardware cursor repositioning.
791 + */
792 +static inline void mov_cursor(unsigned int disp_number)
793 +{
794 +    if (test_bit(INC_ADDR, &hd44780_flags)) {
795 +        iterator_inc(disp_offset[disp_number], disp_size);
796 +        if (disp_offset[disp_number]%par.cntr_cols == 0)
797 +                       disp_offset[disp_number] = disp_size;
798 +       } else {
799 +               iterator_dec(disp_offset[disp_number], disp_size);
800 +               if (disp_offset[disp_number]%par.cntr_cols == par.cntr_cols-1)
801 +                       disp_offset[disp_number] = disp_size;
802 +    }
803 +}
804 +
805 +static struct lcd_driver hd44780 = {
806 +       .read_char              = hd44780_read_char,
807 +       .read_cgram_char        = hd44780_read_cgram_char,
808 +       .write_char             = hd44780_write_char,
809 +       .write_cgram_char       = hd44780_write_cgram_char,
810 +       .address_mode           = hd44780_address_mode,
811 +       .clear_display          = hd44780_clear_display,
812 +       .validate_driver        = hd44780_validate_driver,
813 +       .init_display           = hd44780_init_display,
814 +       .cleanup_display        = hd44780_cleanup_display,
815 +       .init_port              = hd44780_init_port,
816 +       .cleanup_port           = hd44780_cleanup_port,
817 +       .handle_custom_char     = hd44780_handle_custom_char,
818 +       .handle_custom_ioctl    = hd44780_handle_custom_ioctl,
819 +
820 +       .charmap                = charmap,
821 +};
822 +
823 +static void hd44780_read_char(unsigned int offset, unsigned short *data)
824 +{
825 +    unsigned int disp_number = offset/disp_size;
826 +    unsigned char tmp;
827 +
828 +    set_cursor(offset);
829 +    read_display(&tmp, ACCESS_TO_DATA);
830 +    *data = tmp;
831 +    mov_cursor(disp_number);
832 +}
833 +
834 +static void hd44780_read_cgram_char(unsigned char index, unsigned char *pixels)
835 +{
836 +    unsigned int i;
837 +
838 +    write_command(CGRAM_IO | (index << 3));
839 +    set_bit(CGRAM_STATE+0, &hd44780_flags);
840 +
841 +    for (i = 0; i < 8; ++i) {
842 +               read_display(pixels+i, ACCESS_TO_DATA );
843 +               pixels[i] &= 0x1f;
844 +    }
845 +}
846 +
847 +static void hd44780_write_char(unsigned int offset, unsigned short data)
848 +{
849 +    unsigned int disp_number = offset/disp_size;
850 +
851 +    set_cursor(offset);
852 +    write_display(data & 0xff, ACCESS_TO_WRITE | ACCESS_TO_DATA );
853 +    mov_cursor(disp_number);
854 +}
855 +
856 +static void hd44780_write_cgram_char(unsigned char index, unsigned char *pixels)
857 +{
858 +       unsigned int i;
859 +
860 +       /* Move address pointer to index in CGRAM */
861 +       write_command(CGRAM_IO | (index << 3));
862 +
863 +       set_bit(CGRAM_STATE+0, &hd44780_flags);
864 +
865 +       for (i = 0; i < 8; ++i) {
866 +               pixels[i] &= 0x1f;
867 +               write_display(pixels[i], ACCESS_TO_WRITE | ACCESS_TO_DATA );
868 +       }
869 +}
870 +
871 +/* Increment/decrement address mode after a data read/write */
872 +static void hd44780_address_mode(int mode)
873 +{
874 +       if (mode > 0 && ! test_bit(INC_ADDR, &hd44780_flags)) {
875 +               write_command(CURS_INC | DISP_SHIFT_OFF);
876 +               set_bit(INC_ADDR, &hd44780_flags);
877 +       } else if (mode < 0 && test_bit(INC_ADDR, &hd44780_flags)) {
878 +               write_command(CURS_DEC | DISP_SHIFT_OFF);
879 +               clear_bit(INC_ADDR, &hd44780_flags);
880 +       }
881 +}
882 +
883 +static void hd44780_clear_display(void)
884 +{
885 +       write_command(CLR_DISP);
886 +       if (! test_bit(INC_ADDR, &hd44780_flags))
887 +               write_command(CURS_DEC | DISP_SHIFT_OFF);
888 +       memset(disp_offset, 0, sizeof(disp_offset));
889 +}
890 +
891 +static int hd44780_validate_driver(void)
892 +{
893 +       if (par.cntr_rows != 1 && par.cntr_rows != 2 && par.cntr_rows != 4)
894 +               par.cntr_rows = DFLT_CNTR_ROWS;
895 +
896 +       if (par.cntr_rows != 1)
897 +               par.flags &= ~HD44780_5X10_FONT;
898 +
899 +
900 +       if (! par.cntr_cols || par.cntr_cols > MAX_CNTR_COLS/par.cntr_rows)
901 +               par.cntr_cols = MAX_CNTR_COLS/par.cntr_rows;
902 +
903 +       disp_size = par.cntr_rows*par.cntr_cols;
904 +
905 +       /* These parameters depend on the hardware and cannot be changed */
906 +       par.cgram_chars = 8;
907 +       par.cgram_bytes = 8;
908 +       par.cgram_char0 = 0;
909 +
910 +       return (0);
911 +}
912 +
913 +/* Send init commands to the display */
914 +static void write_init_command(void)
915 +{
916 +    unsigned char command = 0x30;
917 +
918 +    __write_display(HIGH_NIBBLE_WRITE(command), ACCESS_TO_WRITE);
919 +    mdelay(20);        /* Wait more than 4.1 ms */
920 +    __write_display(HIGH_NIBBLE_WRITE(command), ACCESS_TO_WRITE);
921 +    udelay(200);       /* Wait more than 100 us */
922 +    __write_display(HIGH_NIBBLE_WRITE(command), ACCESS_TO_WRITE);
923 +    udelay(200);       /* Wait more than 100 us */
924 +    command = BUS_4_BITS;
925 +    command |= ((par.cntr_rows == 1) ? DISP_1_LINE : DISP_2_LINES);
926 +    command |= (test_bit(_5X10_FONT, &hd44780_flags) ? FONT_5X10 : FONT_5X8);
927 +    write_command(command);
928 +    /* set_bit(BACKLIGHT, &hd44780_flags); */
929 +}
930 +
931 +static int hd44780_init_display(void)
932 +{
933 +       if (par.flags & HD44780_CHECK_BF)
934 +               set_bit(_CHECK_BF, &hd44780_flags);
935 +       else
936 +               clear_bit(_CHECK_BF, &hd44780_flags);
937 +
938 +       if (par.flags & HD44780_4BITS_BUS)
939 +               set_bit(_4BITS_BUS, &hd44780_flags);
940 +       else
941 +               clear_bit(_4BITS_BUS, &hd44780_flags);
942 +
943 +       if (par.flags & HD44780_5X10_FONT)
944 +               set_bit(_5X10_FONT, &hd44780_flags);
945 +       else
946 +               clear_bit(_5X10_FONT, &hd44780_flags);
947 +
948 +       write_init_command();
949 +
950 +       hd44780_clear_display();
951 +       hd44780_address_mode(1);
952 +       write_command(DISP_ON | CURS_OFF | BLINK_OFF);
953 +       set_bit(DISPLAY_ON, &hd44780_flags);
954 +       clear_bit(SHOW_CURSOR, &hd44780_flags);
955 +       clear_bit(CURSOR_BLINK, &hd44780_flags);
956 +
957 +       /* Set the CGRAM to default values */
958 +       hd44780_write_cgram_char(0, cg0);
959 +       hd44780_write_cgram_char(1, cg1);
960 +       hd44780_write_cgram_char(2, cg2);
961 +       hd44780_write_cgram_char(3, cg3);
962 +       hd44780_write_cgram_char(4, cg4);
963 +       hd44780_write_cgram_char(5, cg5);
964 +       hd44780_write_cgram_char(6, cg6);
965 +       hd44780_write_cgram_char(7, cg7);
966 +       init_charmap();
967 +
968 +       return (0);
969 +}
970 +
971 +static int hd44780_cleanup_display(void)
972 +{
973 +    hd44780_clear_display();
974 +
975 +    return (0);
976 +}
977 +
978 +static int hd44780_init_port(void)
979 +{
980 +    gpio_direction_output (SIMONE_LCD_BCKLIGHT, 0);
981 +    gpio_direction_output (SIMONE_LCD_RD      , 0);
982 +    gpio_direction_output (SIMONE_LCD_RS      , 0);
983 +    gpio_direction_output (SIMONE_LCD_EN      , 0);
984 +    gpio_set_value(SIMONE_LCD_EN, 0);           /* Disable */
985 +
986 +    return (0);
987 +}
988 +
989 +static int hd44780_cleanup_port(void)
990 +{
991 +
992 +    gpio_direction_input (SIMONE_LCD_BCKLIGHT);
993 +    gpio_direction_input (SIMONE_LCD_RD);
994 +    gpio_direction_input (SIMONE_LCD_RS);
995 +    gpio_direction_input (SIMONE_LCD_EN);
996 +    gpio_direction_input (SIMONE_LCD_DATA0);
997 +    gpio_direction_input (SIMONE_LCD_DATA1);
998 +    gpio_direction_input (SIMONE_LCD_DATA2);
999 +    gpio_direction_input (SIMONE_LCD_DATA3);
1000 +    return (0);
1001 +}
1002 +
1003 +static void display_attr(unsigned char input)
1004 +{
1005 +       unsigned char command;
1006 +
1007 +       switch (ESC_STATE) {
1008 +       case 'a':       /* Turn on/off the display cursor */
1009 +               if (input == '1')
1010 +                       set_bit(SHOW_CURSOR, &hd44780_flags);
1011 +               else if (input == '0')
1012 +                       clear_bit(SHOW_CURSOR, &hd44780_flags);
1013 +               break;
1014 +       case 'b':       /* Turn on/off the display cursor blinking */
1015 +               if (input == '1')
1016 +                       set_bit(CURSOR_BLINK, &hd44780_flags);
1017 +               else if (input == '0')
1018 +                       clear_bit(CURSOR_BLINK, &hd44780_flags);
1019 +               break;
1020 +       case 'h':       /* Turn on/off the display */
1021 +               if (input == '1')
1022 +                       set_bit(DISPLAY_ON, &hd44780_flags);
1023 +               else if (input == '0')
1024 +                       clear_bit(DISPLAY_ON, &hd44780_flags);
1025 +               break;
1026 +       }
1027 +
1028 +        command = (test_bit(DISPLAY_ON, &hd44780_flags) ? DISP_ON : DISP_OFF);
1029 +        command |= (test_bit(SHOW_CURSOR, &hd44780_flags) ? CURS_ON : CURS_OFF);
1030 +       command |= (test_bit(CURSOR_BLINK, &hd44780_flags) ? BLINK_ON : BLINK_OFF);
1031 +
1032 +       if (ESC_STATE == 'h')
1033 +               write_command(command);
1034 +}
1035 +
1036 +static int hd44780_handle_custom_char(unsigned int _input)
1037 +{
1038 +       unsigned char input = _input & 0xff;
1039 +
1040 +       if (_input & (~0xff)) {
1041 +               switch (ESC_STATE) {
1042 +               case 'a':       /* Turn on/off the display cursor */
1043 +               case 'b':       /* Turn on/off the display cursor blinking */
1044 +               case 'h':       /* Turn on/off the the display */
1045 +                       display_attr(input);
1046 +                       return (0);
1047 +               case 'l':       /* Turn on/off the backlight */
1048 +                       if (input == '1')
1049 +                               set_bit(BACKLIGHT, &hd44780_flags);
1050 +                       else if (input == '0')
1051 +                               clear_bit(BACKLIGHT, &hd44780_flags);
1052 +                       read_ac(ACCESS_TO_READ);
1053 +                       return (0);
1054 +               }
1055 +       }
1056 +
1057 +       switch (input) {
1058 +       case 'a':       /* Turn on/off the display cursor */
1059 +       case 'b':       /* Turn on/off the display cursor blinking */
1060 +       case 'h':       /* Turn on/off the display */
1061 +       case 'l':       /* Turn on/off the backlight */
1062 +               SET_ESC_STATE(input);
1063 +               return (1);
1064 +       case 'd':       /* Shift display cursor Right */
1065 +               write_command(SHIFT_CURS | SHIFT_RIGHT);
1066 +               return (0);
1067 +       case 'e':       /* Shift display cursor Left */
1068 +               write_command(SHIFT_CURS | SHIFT_LEFT);
1069 +               return (0);
1070 +       case 'f':       /* Shift display Right */
1071 +               write_command(SHIFT_DISP | SHIFT_RIGHT);
1072 +               return (0);
1073 +       case 'g':       /* Shift display Left */
1074 +               write_command(SHIFT_DISP | SHIFT_LEFT);
1075 +               return (0);
1076 +       }
1077 +
1078 +       return (-1);
1079 +}
1080 +
1081 +static int hd44780_handle_custom_ioctl(unsigned int num, unsigned long arg, unsigned int user_space)
1082 +{
1083 +       unsigned char *buffer = (unsigned char *)arg;
1084 +
1085 +       if (num != HD44780_READ_AC)
1086 +               return (-ENOIOCTLCMD);
1087 +
1088 +       if (user_space)
1089 +               put_user(read_ac(ACCESS_TO_READ), buffer);
1090 +       else
1091 +               buffer[0] = read_ac(ACCESS_TO_READ);
1092 +
1093 +       return (0);
1094 +}
1095 +
1096 +#ifdef USE_PROC
1097 +static int hd44780_proc_status(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
1098 +{
1099 +       char *temp = buffer;
1100 +
1101 +       /* Print display configuration */
1102 +       temp += sprintf(temp,
1103 +                       "Interface:\t%u bits\n"
1104 +                       "Display rows:\t%d\n"
1105 +                       "Display cols:\t%d\n"
1106 +                       "Screen rows:\t%d\n"
1107 +                       "Screen cols:\t%d\n"
1108 +                       "Read:\t\t%sabled\n"
1109 +                       "Busy flag chk:\t%sabled\n"
1110 +                       "Assigned minor:\t%u\n",
1111 +                       (test_bit(_4BITS_BUS, &hd44780_flags) ? 4 : 8),
1112 +                       par.cntr_rows, par.cntr_cols,
1113 +                       par.vs_rows, par.vs_cols,
1114 +                       (hd44780.read_char ? "En" : "Dis"),
1115 +                       (test_bit(_CHECK_BF, &hd44780_flags) ? "En" : "Dis"),
1116 +                       par.minor);
1117 +
1118 +       return (temp-buffer);
1119 +}
1120 +
1121 +static int hd44780_proc_cgram(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
1122 +{
1123 +       char *temp = buffer;
1124 +       unsigned int i;
1125 +
1126 +       temp += sprintf(temp,   "static void init_charmap(void)\n{\n"
1127 +                               "\t/*\n"
1128 +                               "\t * charmap[char mapped to cg0] = 0;\n"
1129 +                               "\t * charmap[char mapped to cg1] = 1;\n"
1130 +                               "\t * charmap[char mapped to cg2] = 2;\n"
1131 +                               "\t * charmap[char mapped to cg3] = 3;\n"
1132 +                               "\t * charmap[char mapped to cg4] = 4;\n"
1133 +                               "\t * charmap[char mapped to cg5] = 5;\n"
1134 +                               "\t * charmap[char mapped to cg6] = 6;\n"
1135 +                               "\t * charmap[char mapped to cg7] = 7;\n"
1136 +                               "\t */\n"
1137 +                               "}\n\n");
1138 +
1139 +       for (i = 0; i < 8; ++i) {
1140 +               unsigned char cgram_buffer[8];
1141 +               unsigned int j;
1142 +
1143 +               temp += sprintf(temp, "static unsigned char cg%u[] = { ", i);
1144 +               hd44780_read_cgram_char(i, cgram_buffer);
1145 +               for (j = 0; j < 8; ++j)
1146 +                       temp += sprintf(temp, "0x%.2x%s", cgram_buffer[j], (j == 7 ? " };\n" : ", "));
1147 +       }
1148 +
1149 +       return (temp-buffer);
1150 +}
1151 +
1152 +static void create_proc_entries(void)
1153 +{
1154 +       int count = 0;
1155 +
1156 +       SET_PROC_LEVEL(count);
1157 +       if (create_proc_read_entry("status", 0, hd44780.driver_proc_root, hd44780_proc_status, NULL) == NULL) {
1158 +               printk(KERN_ERR "hd44780: cannot create /proc/lcd/%s/status\n", par.name);
1159 +               return;
1160 +       }
1161 +       SET_PROC_LEVEL(++count);
1162 +       if (hd44780.read_cgram_char) {
1163 +               if (create_proc_read_entry("cgram.h", 0, hd44780.driver_proc_root, hd44780_proc_cgram, NULL) == NULL) {
1164 +                       printk(KERN_ERR "hd44780: cannot create /proc/lcd/%s/cgram.h\n", par.name);
1165 +                       return;
1166 +               }
1167 +               SET_PROC_LEVEL(++count);
1168 +       }
1169 +}
1170 +
1171 +static void remove_proc_entries(void)
1172 +{
1173 +       switch (PROC_LEVEL) {
1174 +       case 2:
1175 +               remove_proc_entry("cgram.h", hd44780.driver_proc_root);
1176 +       case 1:
1177 +               remove_proc_entry("status", hd44780.driver_proc_root);
1178 +       }
1179 +       SET_PROC_LEVEL(0);
1180 +}
1181 +#endif
1182 +
1183 +/* Initialization */
1184 +static int __init hd44780_init_module(void)
1185 +{
1186 +       int ret;
1187 +
1188 +#ifdef MODULE
1189 +#ifdef NOT_DEF
1190 +       if ((ret = request_module("lcd-linux"))) {
1191 +               if (ret != -ENOSYS) {
1192 +                       printk(KERN_ERR "hd44780: failure while loading module lcd-linux\n");
1193 +                       return (ret);
1194 +               }
1195 +               printk(KERN_ERR "hd44780: your kernel does not have kmod or kerneld support;\n");
1196 +               printk(KERN_ERR "hd44780: remember to load the lcd-linux module before\n");
1197 +               printk(KERN_ERR "hd44780: loading the hd44780 module\n");
1198 +       }
1199 +#endif
1200 +       if (flags       != DFLT_FLAGS)          par.flags       = flags;
1201 +       if (tabstop     != DFLT_TABSTOP)        par.tabstop     = tabstop;
1202 +       if (cntr_rows   != DFLT_CNTR_ROWS)      par.cntr_rows   = cntr_rows;
1203 +       if (cntr_cols   != DFLT_CNTR_COLS)      par.cntr_cols   = cntr_cols;
1204 +       if (vs_rows     != DFLT_VS_ROWS)        par.vs_rows     = vs_rows;
1205 +       if (vs_cols     != DFLT_VS_COLS)        par.vs_cols     = vs_cols;
1206 +       if (minor       != HD44780_MINOR)       par.minor       = minor;
1207 +#endif
1208 +
1209 +       lcd_driver_setup(&hd44780);
1210 +       if ((ret = lcd_register_driver(&hd44780, &par)))
1211 +               return (ret);
1212 +
1213 +#ifdef USE_PROC
1214 +       if (hd44780.driver_proc_root)
1215 +               create_proc_entries();
1216 +#endif
1217 +
1218 +       printk(KERN_INFO "HD44780 driver (LCD-Linux" HD44780_VERSION ")\n");
1219 +       printk(KERN_INFO "Nuccio Raciti <raciti.nuccio@gmail.com>\n");
1220 +
1221 +
1222 +       return (0);
1223 +}
1224 +
1225 +/* Cleanup */
1226 +
1227 +static void __exit hd44780_cleanup_module(void)
1228 +{
1229 +#ifdef USE_PROC
1230 +       if (hd44780.driver_proc_root)
1231 +               remove_proc_entries();
1232 +#endif
1233 +
1234 +       lcd_unregister_driver(&hd44780, &par);
1235 +}
1236 +
1237 +module_init(hd44780_init_module)
1238 +module_exit(hd44780_cleanup_module)
1239 Index: linux-2.6.30.9/drivers/lcd-linux/lcd-linux.c
1240 ===================================================================
1241 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
1242 +++ linux-2.6.30.9/drivers/lcd-linux/lcd-linux.c        2009-11-24 02:01:42.000000000 +0100
1243 @@ -0,0 +1,2892 @@
1244 +/* lcd-linux.c
1245 + *
1246 + *
1247 + *
1248 + * Software layer to drive LCD displays under Linux.
1249 + *
1250 + * Copyright (C) 2005 - 2007  Mattia Jona-Lasinio (mjona@users.sourceforge.net)
1251 + *
1252 + *  This program is free software; you can redistribute it and/or modify
1253 + *  it under the terms of the GNU General Public License as published by
1254 + *  the Free Software Foundation; either version 2 of the License, or
1255 + *  (at your option) any later version.
1256 + *
1257 + *  This program is distributed in the hope that it will be useful,
1258 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1259 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1260 + *  GNU General Public License for more details.
1261 + *
1262 + *  You should have received a copy of the GNU General Public License
1263 + *  along with this program; if not, write to the Free Software
1264 + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1265 + *
1266 + */
1267 +
1268 +#include <linux/version.h>
1269 +
1270 +#ifndef KERNEL_VERSION
1271 +#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
1272 +#endif
1273 +
1274 +#ifndef LINUX_VERSION_CODE
1275 +#error - LINUX_VERSION_CODE undefined in 'linux/version.h'
1276 +#endif
1277 +
1278 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
1279 +#include <linux/autoconf.h>
1280 +#else
1281 +#include <linux/config.h>
1282 +#endif
1283 +#ifdef CONFIG_PROC_FS
1284 +#define USE_PROC
1285 +#else
1286 +#undef USE_PROC
1287 +#endif
1288 +
1289 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
1290 +#include <linux/semaphore.h>
1291 +#else
1292 +#include <asm/semaphore.h>
1293 +#endif
1294 +#include <linux/bitops.h>
1295 +#include <linux/kernel.h>
1296 +#include <linux/module.h>
1297 +#include <linux/sched.h>
1298 +
1299 +#include <linux/fs.h>
1300 +
1301 +#include <asm/uaccess.h>
1302 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
1303 +#include <linux/device.h>
1304 +#endif
1305 +#include <linux/init.h>
1306 +#include <linux/list.h>
1307 +#include <linux/slab.h>
1308 +#include <linux/selection.h>
1309 +#include <linux/vmalloc.h>
1310 +
1311 +#ifdef USE_PROC
1312 +#include <linux/proc_fs.h>
1313 +#endif
1314 +
1315 +#define LCD_LINUX_MAIN
1316 +#include <linux/lcd-linux.h>
1317 +
1318 +/*** struct_flags ***/
1319 +#define NEED_WRAP      0               /* Next char will trigger a newline */
1320 +#define DECIM          1               /* Insert mode */
1321 +#define DECAWM         2               /* Autowrap */
1322 +#define DECSCNM                3               /* Inverted screen */
1323 +#define CRLF           4               /* Follow lf, vt, ff, with a cr */
1324 +#define INC_CURS_POS   5               /* Increment cursor position after data read/write */
1325 +#define QUES           6               /* CSI Esc sequence contains a question mark */
1326 +#define USER_SPACE     7               /* If set, the buffer pointed by arg in do_lcd_ioctl() is
1327 +                                        * assumed to be in user space otherwise it is in kernel space */
1328 +#define NULL_CHARMAP   8               /* The driver doesn't provide a charmap so the
1329 +                                        * lcd-linux layer provides one*/
1330 +#define CAN_DO_COLOR   9               /* The display is color capable */
1331 +#define WITH_ATTR      10              /* If set, the void * buffer in do_lcd_read/write() contains
1332 +                                        * attributes and therefore is an unsigned short * otherwise it
1333 +                                        * is an unsigned char *
1334 +                                        */
1335 +
1336 +/*** attributes ***/
1337 +#define I_MASK         0x03            /* Intensity (0 = low, 1 = normal, 2 = bright) */
1338 +#define ULINE          0x04            /* Underlined text */
1339 +#define        REVERSE         0x08            /* Reversed video text */
1340 +#define BLINK          0x80            /* Blinking text */
1341 +
1342 +/*** Color attributes ***/
1343 +#define FG_MASK                0x0f            /* Foreground color */
1344 +#define BG_MASK                0xf0            /* Background color */
1345 +
1346 +/* input states */
1347 +#define NORMAL         0x00001000      /* Normal mode */
1348 +#define RAW            0x00002000      /* Raw mode (console emulation disabled) */
1349 +#define SYN            0x00003000      /* Synchronous Idle mode */
1350 +#define ESC            0x00004000      /* Escape mode */
1351 +#define CSI            0x00005000      /* CSI escape mode */
1352 +#define ESC_G0         0x00006000      /* G0 character set */
1353 +#define ESC_G1         0x00007000      /* G1 character set */
1354 +#define ESC_HASH       0x00008000      /* ESC # escape sequence */
1355 +#define ESC_PERCENT    0x00009000      /* ESC % escape sequence */
1356 +#define ARG            0x0000a000      /* Waiting for arguments for the lcd-linux layer */
1357 +#define ARG_DRIVER     0x0000b000      /* Waiting for arguments for the display driver */
1358 +#define INPUT_MASK     0x0000f000
1359 +#define ESC_MASK       0x00ff0000
1360 +#define INIT_MASK      0x0f000000
1361 +#define PROC_MASK      0xf0000000
1362 +
1363 +#define SET_STATE(p, state, mask)      ((p)->struct_flags = ((p)->struct_flags & ~(mask)) | ((state) & (mask)))
1364 +#define SET_INPUT_STATE(p, state)      SET_STATE(p, state, INPUT_MASK)
1365 +#define SET_ESC_STATE(p, state)                SET_STATE(p, (state) << 16, ESC_MASK)
1366 +#define SET_INIT_LEVEL(p, level)       SET_STATE(p, (level) << 24, INIT_MASK)
1367 +#define SET_PROC_LEVEL(p, level)       SET_STATE(p, (level) << 28, PROC_MASK)
1368 +#define INPUT_STATE(p)                 ((p)->struct_flags & INPUT_MASK)
1369 +#define ESC_STATE(p)                   (((p)->struct_flags & ESC_MASK) >> 16)
1370 +#define INIT_LEVEL(p)                  (((p)->struct_flags & INIT_MASK) >> 24)
1371 +#define PROC_LEVEL(p)                  (((p)->struct_flags & PROC_MASK) >> 28)
1372 +
1373 +#define NPAR   16                      /* Max number of parameters in CSI escape sequence */
1374 +#define FLIP_BUF_SIZE  (1 << 6)        /* Flip buffer size (64 bytes) */
1375 +
1376 +struct lcd_struct {
1377 +       struct list_head        lcd_list;               /* Doubly linked list */
1378 +       struct semaphore        lcd_sem;                /* Locks this structure */
1379 +       struct lcd_driver       *driver;                /* The driver associated to this struct */
1380 +       struct lcd_parameters   *par;                   /* The parameters associated to this struct */
1381 +       unsigned long           struct_flags;           /* Flags for internal use only */
1382 +       unsigned int            refcount;               /* Number of references to this struct */
1383 +
1384 +       unsigned short          *display;               /* The display buffer */
1385 +
1386 +       unsigned short          *fb;                    /* The virtual screen framebuffer */
1387 +       unsigned int            fb_size;                /* Size of the framebuffer */
1388 +       unsigned int            frame_base;             /* Offset of row 0, column 0 of a frame in fb */
1389 +       unsigned int            frame_size;             /* Size of the frame */
1390 +
1391 +       unsigned int            row;                    /* Current row in virtual screen */
1392 +       unsigned int            col;                    /* Current column in virtual screen */
1393 +       unsigned int            s_offset;               /* Saved cursor position in virtual screen */
1394 +
1395 +       unsigned int            top;                    /* Top scroll row in virtual screen */
1396 +       unsigned int            bot;                    /* Bottom scroll row in virtual screen */
1397 +
1398 +       int                     esc_args;               /* Number of arguments for a normal escape sequence */
1399 +       unsigned int            csi_args[NPAR];         /* CSI parameters */
1400 +       unsigned int            index;                  /* Index in csi_args and counter for cgram characters generation */
1401 +       unsigned char           cgram_index;            /* Index of the cgram character to be created */
1402 +       unsigned char           *cgram_buffer;          /* Buffer for cgram operations in this driver */
1403 +
1404 +       unsigned short          erase_char;             /* Character to be used when erasing */
1405 +       unsigned char           attr;                   /* Current attributes */
1406 +       unsigned char           color;                  /* Color for normal intensity mode */
1407 +       unsigned char           s_color;                /* Saved color for normal intensity mode */
1408 +       unsigned char           defcolor;               /* Default color for normal intensity mode */
1409 +       unsigned char           ulcolor;                /* Color for underline mode */
1410 +       unsigned char           halfcolor;              /* Color for low intensity mode */
1411 +       unsigned char           attributes;             /* Packed attributes */
1412 +       unsigned char           s_attributes;           /* Saved packed attributes */
1413 +
1414 +       unsigned char           *s_charmap;             /* Saved character map for this driver */
1415 +       unsigned char           *flip_buf;              /* High speed flip buffer */
1416 +};
1417 +
1418 +/** Function prototypes **/
1419 +
1420 +/* Init/Cleanup the driver */
1421 +static int init_driver(struct lcd_struct *);
1422 +static int cleanup_driver(struct lcd_struct *);
1423 +
1424 +/* Read from/Write to the driver */
1425 +static void read_data(struct lcd_struct *, unsigned short *);
1426 +static void read_cgram(struct lcd_struct *, unsigned char, unsigned char *);
1427 +static void write_data(struct lcd_struct *, unsigned short);
1428 +static void write_cgram(struct lcd_struct *, unsigned char, unsigned char *);
1429 +
1430 +/* Input handlers */
1431 +static void cr(struct lcd_struct *);
1432 +static void lf(struct lcd_struct *);
1433 +static void control_char(struct lcd_struct *, unsigned char);
1434 +static void handle_csi(struct lcd_struct *, unsigned char);
1435 +static int handle_custom_esc(struct lcd_struct *, unsigned int);
1436 +static int handle_esc(struct lcd_struct *, unsigned char);
1437 +static void handle_input(struct lcd_struct *, unsigned short);
1438 +
1439 +/* Low level file operations */
1440 +static ssize_t do_lcd_read(struct lcd_struct *, void *, size_t);
1441 +static ssize_t do_lcd_write(struct lcd_struct *, const void *, size_t);
1442 +static int do_lcd_open(struct lcd_struct *);
1443 +static int do_lcd_release(struct lcd_struct *);
1444 +static int do_lcd_ioctl(struct lcd_struct *, unsigned int, unsigned long);
1445 +
1446 +/* Proc functions */
1447 +#ifdef USE_PROC
1448 +static void create_driver_proc_entries(struct lcd_struct *);
1449 +static void remove_driver_proc_entries(struct lcd_struct *);
1450 +#endif
1451 +
1452 +/* globals */
1453 +static unsigned int major      = LCD_MAJOR;            /* Major number for LCD-Linux device */
1454 +static unsigned short minors   = LCD_MINORS;           /* Minor numbers allocated for LCD-Linux */
1455 +static LIST_HEAD(lcd_drivers);                         /* Registered lcd drivers */
1456 +static struct semaphore drivers_sem;                   /* Locks the lcd_drivers list */
1457 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
1458 +static struct class *lcd_linux_class;
1459 +#endif
1460 +#ifdef USE_PROC
1461 +static struct proc_dir_entry *lcd_proc_root;
1462 +#endif
1463 +/* End of globals */
1464 +
1465 +#ifdef MODULE
1466 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
1467 +#include <linux/device.h>
1468 +MODULE_ALIAS_CHARDEV_MAJOR(LCD_MAJOR);
1469 +#endif
1470 +MODULE_DESCRIPTION("Software layer to drive LCD displays under Linux.");
1471 +MODULE_AUTHOR("Mattia Jona-Lasinio <mjona@users.sourceforge.net>");
1472 +#ifdef MODULE_LICENSE
1473 +MODULE_LICENSE("GPL");
1474 +#endif
1475 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
1476 +module_param(minors, ushort, 0444);
1477 +#else
1478 +MODULE_PARM(minors, "h");
1479 +#endif
1480 +MODULE_PARM_DESC(minors, "Minor numbers allocated for LCD-Linux (default: " string(LCD_MINORS) ")");
1481 +#else
1482 +
1483 +/*
1484 + * Parse boot command line
1485 + *
1486 + * lcd=minors
1487 + */
1488 +static int __init lcd_linux_boot_init(char *cmdline)
1489 +{
1490 +       unsigned short args;
1491 +
1492 +       if ((args = simple_strtoul(cmdline, NULL, 0)))
1493 +               minors = args;
1494 +
1495 +       return (1);
1496 +}
1497 +
1498 +__setup("lcd=", lcd_linux_boot_init);
1499 +#endif /* MODULE */
1500 +
1501 +/* Macros for iterator handling */
1502 +static inline unsigned int iterator_inc_(unsigned int iterator, const unsigned int module)
1503 +{
1504 +       return ((++iterator)%module);
1505 +}
1506 +
1507 +static inline unsigned int iterator_dec_(unsigned int iterator, const unsigned int module)
1508 +{
1509 +       return (iterator ? --iterator : module-1);
1510 +}
1511 +
1512 +#define iterator_inc(iterator, module)         (iterator = iterator_inc_(iterator, module))
1513 +#define iterator_dec(iterator, module)         (iterator = iterator_dec_(iterator, module))
1514 +
1515 +/* Uncomment the following two lines
1516 + * for non-atomic set_bit and clear_bit
1517 +#define set_bit                __set_bit
1518 +#define clear_bit      __clear_bit
1519 +*/
1520 +
1521 +/************************************
1522 + * Low level routines and utilities *
1523 + ************************************/
1524 +/*
1525 + * Set whether the address counter should be incremented
1526 + * or decremented after a Read/Write
1527 + */
1528 +static void address_mode(struct lcd_struct *p, int mode)
1529 +{
1530 +       struct lcd_driver *driver = p->driver;
1531 +
1532 +       if (mode > 0 && ! test_bit(INC_CURS_POS, &p->struct_flags)) {
1533 +               if (driver->address_mode)
1534 +                       driver->address_mode(mode);
1535 +               set_bit(INC_CURS_POS, &p->struct_flags);
1536 +       } else if (mode < 0 && test_bit(INC_CURS_POS, &p->struct_flags)) {
1537 +               if (driver->address_mode)
1538 +                       driver->address_mode(mode);
1539 +               clear_bit(INC_CURS_POS, &p->struct_flags);
1540 +       }
1541 +}
1542 +
1543 +/* WARNING!! This function returns an int because if iterator is not
1544 + * within the visible area of the frame it returns -1
1545 + */
1546 +static inline int vs_to_frame_(struct lcd_struct *p, unsigned int iterator)
1547 +{
1548 +       unsigned int vs_cols = p->par->vs_cols;
1549 +       unsigned int row = iterator/vs_cols;
1550 +       unsigned int col = iterator%vs_cols;
1551 +       unsigned int frame_base_row = p->frame_base/vs_cols;
1552 +       unsigned int frame_base_col = p->frame_base%vs_cols;
1553 +       unsigned int frame_rows = p->par->cntr_rows*p->par->num_cntr;
1554 +       unsigned int frame_cols = p->par->cntr_cols;
1555 +
1556 +       if (row < frame_base_row || row >= frame_base_row+frame_rows)
1557 +               return (-1);
1558 +       if (col < frame_base_col || col >= frame_base_col+frame_cols)
1559 +               return (-1);
1560 +
1561 +       return ((row-frame_base_row)*frame_cols+(col-frame_base_col));
1562 +}
1563 +
1564 +/* Given 'iterator' in vs, returns the offset in vs corresponding to the nearest
1565 + * visible offset in vs, or returns 'iterator' if it is already visible.
1566 + */
1567 +static unsigned int round_vs_(struct lcd_struct *p, unsigned int iterator)
1568 +{
1569 +       unsigned int vs_cols = p->par->vs_cols;
1570 +       unsigned int row = iterator/vs_cols;
1571 +       unsigned int col = iterator%vs_cols;
1572 +       unsigned int frame_base_row = p->frame_base/vs_cols;
1573 +       unsigned int frame_base_col = p->frame_base%vs_cols;
1574 +       unsigned int frame_rows = p->par->cntr_rows*p->par->num_cntr;
1575 +       unsigned int frame_cols = p->par->cntr_cols;
1576 +
1577 +       if (row < frame_base_row)
1578 +               row = frame_base_row;
1579 +       else if (row >= frame_base_row+frame_rows)
1580 +               row = frame_base_row+(frame_rows-1);
1581 +
1582 +       if (col < frame_base_col)
1583 +               col = frame_base_col;
1584 +       else if (col >= frame_base_col+frame_cols)
1585 +               col = frame_base_col+(frame_cols-1);
1586 +
1587 +       return ((row*vs_cols)+col);
1588 +}
1589 +
1590 +#define round_vs(p, iterator)                  (iterator = round_vs_(p, iterator))
1591 +
1592 +/*
1593 + * Sync the frame area starting at offset s, ending at offset e with fb content.
1594 + */
1595 +static void redraw_screen(struct lcd_struct *p, unsigned int s, unsigned int e)
1596 +{
1597 +       unsigned int len;
1598 +       unsigned int row = p->row, col = p->col;
1599 +       unsigned int inc_set = test_bit(INC_CURS_POS, &p->struct_flags);
1600 +       unsigned int frame_cols = p->par->cntr_cols;
1601 +       unsigned int vs_cols = p->par->vs_cols;
1602 +       unsigned long flags;
1603 +
1604 +       if (s >= p->fb_size || e >= p->fb_size || e < s || e < p->frame_base)
1605 +               return;
1606 +
1607 +       round_vs(p, s);
1608 +       round_vs(p, e);
1609 +
1610 +       len = 1+e-s;
1611 +
1612 +       if (! inc_set)
1613 +               s = e;
1614 +
1615 +       p->row = s/vs_cols;
1616 +       p->col = s%vs_cols;
1617 +
1618 +       flags = p->struct_flags;
1619 +       clear_bit(NEED_WRAP, &p->struct_flags);
1620 +       clear_bit(DECIM, &p->struct_flags);
1621 +       set_bit(DECAWM, &p->struct_flags);
1622 +       SET_INPUT_STATE(p, RAW);
1623 +       if (inc_set)
1624 +               while (len--)
1625 +                       if (vs_to_frame_(p, (p->row*vs_cols)+p->col) < 0) {
1626 +                               s += vs_cols-frame_cols;
1627 +                               len -= vs_cols-frame_cols-1;
1628 +                               p->row = s/vs_cols;
1629 +                               p->col = s%vs_cols;
1630 +                       } else {
1631 +                               write_data(p, p->fb[s++]);
1632 +                               if (test_bit(NEED_WRAP, &p->struct_flags)) {
1633 +                                       cr(p);
1634 +                                       lf(p);
1635 +                               }
1636 +                       }
1637 +       else
1638 +               while (len--)
1639 +                       if (vs_to_frame_(p, (p->row*vs_cols)+p->col) < 0) {
1640 +                               s -= vs_cols-frame_cols;
1641 +                               len -= vs_cols-frame_cols-1;
1642 +                               p->row = s/vs_cols;
1643 +                               p->col = s%vs_cols;
1644 +                       } else {
1645 +                               write_data(p, p->fb[s--]);
1646 +                               if (test_bit(NEED_WRAP, &p->struct_flags)) {
1647 +                                       cr(p);
1648 +                                       lf(p);
1649 +                               }
1650 +                       }
1651 +       p->struct_flags = flags;
1652 +
1653 +       p->row = row; p->col = col;
1654 +}
1655 +
1656 +static int make_cursor_visible(struct lcd_struct *p)
1657 +{
1658 +       unsigned int vs_rows = p->par->vs_rows;
1659 +       unsigned int vs_cols = p->par->vs_cols;
1660 +       unsigned int frame_base, frame_base_row, frame_base_col;
1661 +       unsigned int frame_rows = p->par->cntr_rows*p->par->num_cntr;
1662 +       unsigned int frame_cols = p->par->cntr_cols;
1663 +       unsigned int tmp = frame_cols/2;
1664 +
1665 +       if (test_bit(INC_CURS_POS, &p->struct_flags)) {
1666 +       /* cursor always on the lowest row of the display */
1667 +               frame_base_row = 0;
1668 +               frame_base_col = 0;
1669 +               if (p->row >= frame_rows)
1670 +                       frame_base_row = p->row-(frame_rows-1);
1671 +               if (p->col >= frame_cols) {
1672 +                       frame_base_col = p->col-(frame_cols-1);
1673 +                       if (tmp) {
1674 +                               tmp = (tmp-(frame_base_col%tmp))%tmp;
1675 +                               if (frame_base_col+tmp <= vs_cols-frame_cols)
1676 +                                       frame_base_col += tmp;
1677 +                       }
1678 +               }
1679 +       } else {
1680 +       /* cursor always on the uppermost row of the display */
1681 +               frame_base_row = vs_rows-frame_rows;
1682 +               frame_base_col = vs_cols-frame_cols;
1683 +               if (p->row < vs_rows-frame_rows)
1684 +                       frame_base_row = p->row;
1685 +               if (p->col < vs_cols-frame_cols) {
1686 +                       frame_base_col = p->col;
1687 +                       if (tmp) {
1688 +                               tmp = frame_base_col%tmp;
1689 +                               if (frame_base_col >= tmp)
1690 +                                       frame_base_col -= tmp;
1691 +                       }
1692 +               }
1693 +       }
1694 +
1695 +       frame_base = p->frame_base;
1696 +       p->frame_base = (frame_base_row*vs_cols)+frame_base_col;
1697 +
1698 +       return (frame_base != p->frame_base);
1699 +}
1700 +
1701 +/*
1702 + * Move the visible screen area at user's wish
1703 + */
1704 +static void browse_screen(struct lcd_struct *p, unsigned char dir)
1705 +{
1706 +       unsigned int vs_rows = p->par->vs_rows;
1707 +       unsigned int vs_cols = p->par->vs_cols;
1708 +       unsigned int frame_base_row = p->frame_base/vs_cols;
1709 +       unsigned int frame_base_col = p->frame_base%vs_cols;
1710 +       unsigned int frame_rows = p->par->cntr_rows*p->par->num_cntr;
1711 +       unsigned int frame_cols = p->par->cntr_cols;
1712 +
1713 +       switch (dir) {
1714 +       case '1':       /* Up */
1715 +               if (! frame_base_row)
1716 +                       return;
1717 +               --frame_base_row;
1718 +               break;
1719 +       case '2':       /* Down */
1720 +               if (frame_base_row >= vs_rows-frame_rows)
1721 +                       return;
1722 +               ++frame_base_row;
1723 +               break;
1724 +       case '3':       /* Left */
1725 +               if (! frame_base_col)
1726 +                       return;
1727 +               --frame_base_col;
1728 +               break;
1729 +       case '4':       /* Right */
1730 +               if (frame_base_col >= vs_cols-frame_cols)
1731 +                       return;
1732 +               ++frame_base_col;
1733 +               break;
1734 +       default:
1735 +               return;
1736 +       }
1737 +
1738 +       p->frame_base = (frame_base_row*vs_cols)+frame_base_col;
1739 +       redraw_screen(p, 0, p->fb_size-1);
1740 +}
1741 +
1742 +static inline void __memset_short(unsigned short *buf, unsigned short c, unsigned int len)
1743 +{
1744 +       while (len--)
1745 +               *buf++ = c;
1746 +}
1747 +
1748 +/*
1749 + * A memset implementation writing to LCD instead of memory locations.
1750 + */
1751 +static void lcd_memset(struct lcd_struct *p, unsigned int d, unsigned short c, unsigned int len)
1752 +{
1753 +       unsigned int inc_set = test_bit(INC_CURS_POS, &p->struct_flags);
1754 +
1755 +       if (! len || d >= p->fb_size)
1756 +               return;
1757 +
1758 +       if (inc_set && d+len > p->fb_size)
1759 +               len = p->fb_size-d;
1760 +       else if (! inc_set && len > d+1)
1761 +               len = d+1;
1762 +
1763 +       if (! inc_set)
1764 +               d -= len-1;
1765 +       __memset_short(p->fb+d, c, len);
1766 +
1767 +       if (make_cursor_visible(p))
1768 +               redraw_screen(p, 0, p->fb_size-1);
1769 +       else
1770 +               redraw_screen(p, d, d+(len-1));
1771 +}
1772 +
1773 +static inline void __memcpy_short(unsigned short *d, unsigned short *s, unsigned int len, int dir)
1774 +{
1775 +       if (dir > 0)
1776 +               while (len--)
1777 +                       *d++ = *s++;
1778 +       else
1779 +               while (len--)
1780 +                       *d-- = *s--;
1781 +}
1782 +
1783 +/*
1784 + * A memmove implementation writing to LCD instead of memory locations.
1785 + * Copy is done in a non destructive way. Display regions may overlap.
1786 + */
1787 +static void lcd_memmove(struct lcd_struct *p, unsigned int d, unsigned int s, unsigned int len)
1788 +{
1789 +       if (! len || d == s || d >= p->fb_size || s >= p->fb_size)
1790 +               return;
1791 +
1792 +       if (d < s) {
1793 +               if (test_bit(INC_CURS_POS, &p->struct_flags)) {
1794 +                       if (s+len > p->fb_size)
1795 +                               len = p->fb_size-s;
1796 +               } else {
1797 +                       if (len > d+1)
1798 +                               len = d+1;
1799 +                       d -= len-1;
1800 +                       s -= len-1;
1801 +               }
1802 +               __memcpy_short(p->fb+d, p->fb+s, len, 1);
1803 +               if (make_cursor_visible(p))
1804 +                       redraw_screen(p, 0, p->fb_size-1);
1805 +               else
1806 +                       redraw_screen(p, d, d+(len-1));
1807 +       } else {
1808 +               if (test_bit(INC_CURS_POS, &p->struct_flags)) {
1809 +                       if (d+len > p->fb_size)
1810 +                               len = p->fb_size-d;
1811 +                       d += len-1;
1812 +                       s += len-1;
1813 +               } else {
1814 +                       if (len > s+1)
1815 +                               len = s+1;
1816 +               }
1817 +               __memcpy_short(p->fb+d, p->fb+s, len, -1);
1818 +               if (make_cursor_visible(p))
1819 +                       redraw_screen(p, 0, p->fb_size-1);
1820 +               else
1821 +                       redraw_screen(p, d-(len-1), d);
1822 +       }
1823 +}
1824 +
1825 +static void scrup(struct lcd_struct *p, unsigned int t, unsigned int b, unsigned int nr)
1826 +{
1827 +       unsigned int vs_rows = p->par->vs_rows;
1828 +       unsigned int vs_cols = p->par->vs_cols;
1829 +       unsigned int d, s;
1830 +
1831 +       if (t+nr >= b)
1832 +               nr = b-t-1;
1833 +       if (b > vs_rows || t >= b || nr < 1)
1834 +               return;
1835 +       d = t*vs_cols;
1836 +       s = (t+nr)*vs_cols;
1837 +       if (test_bit(INC_CURS_POS, &p->struct_flags)) {
1838 +               lcd_memmove(p, d, s, (b-t-nr)*vs_cols);
1839 +               lcd_memset(p, d+(b-t-nr)*vs_cols, p->erase_char, nr*vs_cols);
1840 +       } else {
1841 +               lcd_memmove(p, d+(b-t-nr)*vs_cols-1, s+(b-t-nr)*vs_cols-1, (b-t-nr)*vs_cols);
1842 +               lcd_memset(p, d+(b-t)*vs_cols-1, p->erase_char, nr*vs_cols);
1843 +       }
1844 +}
1845 +
1846 +static void scrdown(struct lcd_struct *p, unsigned int t, unsigned int b, unsigned int nr)
1847 +{
1848 +       unsigned int vs_rows = p->par->vs_rows;
1849 +       unsigned int vs_cols = p->par->vs_cols;
1850 +       unsigned int d, s;
1851 +
1852 +       if (t+nr >= b)
1853 +               nr = b-t-1;
1854 +       if (b > vs_rows || t >= b || nr < 1)
1855 +               return;
1856 +       s = t*vs_cols;
1857 +       d = (t+nr)*vs_cols;
1858 +       if (test_bit(INC_CURS_POS, &p->struct_flags)) {
1859 +               lcd_memmove(p, d, s, (b-t-nr)*vs_cols);
1860 +               lcd_memset(p, s, p->erase_char, nr*vs_cols);
1861 +       } else {
1862 +               lcd_memmove(p, d+(b-t-nr)*vs_cols-1, s+(b-t-nr)*vs_cols-1, (b-t-nr)*vs_cols);
1863 +               lcd_memset(p, s+nr*vs_cols-1, p->erase_char, nr*vs_cols);
1864 +       }
1865 +}
1866 +
1867 +static void lcd_insert_char(struct lcd_struct *p, unsigned int nr)
1868 +{
1869 +       unsigned int vs_cols = p->par->vs_cols;
1870 +       unsigned int pos = (p->row*vs_cols)+p->col;
1871 +
1872 +       clear_bit(NEED_WRAP, &p->struct_flags);
1873 +       if (test_bit(INC_CURS_POS, &p->struct_flags))
1874 +               lcd_memmove(p, pos+nr, pos, vs_cols-p->col-nr);
1875 +       else
1876 +               lcd_memmove(p, pos-nr, pos, p->col-(nr-1));
1877 +       lcd_memset(p, pos, p->erase_char, nr);
1878 +}
1879 +
1880 +static void lcd_delete_char(struct lcd_struct *p, unsigned int nr)
1881 +{
1882 +       unsigned int vs_cols = p->par->vs_cols;
1883 +       unsigned int pos = (p->row*vs_cols)+p->col;
1884 +
1885 +       clear_bit(NEED_WRAP, &p->struct_flags);
1886 +       if (test_bit(INC_CURS_POS, &p->struct_flags)) {
1887 +               lcd_memmove(p, pos, pos+nr, vs_cols-(p->col+nr));
1888 +               lcd_memset(p, (p->row+1)*vs_cols-nr, p->erase_char, nr);
1889 +       } else {
1890 +               lcd_memmove(p, pos, pos-nr, p->col-(nr-1));
1891 +               lcd_memset(p, (p->row*vs_cols)+(nr-1), p->erase_char, nr);
1892 +       }
1893 +}
1894 +
1895 +
1896 +
1897 +
1898 +
1899 +/******************************************************************************
1900 + *************************      VT 102 Emulation      *************************
1901 + ******************************************************************************/
1902 +
1903 +/**********************
1904 + * Control characters *
1905 + **********************/
1906 +static void bs(struct lcd_struct *p)
1907 +{
1908 +       clear_bit(NEED_WRAP, &p->struct_flags);
1909 +       if (test_bit(INC_CURS_POS, &p->struct_flags)) {
1910 +               if (p->col)
1911 +                       --p->col;
1912 +       } else {
1913 +               if (p->col+1 < p->par->vs_cols)
1914 +                       ++p->col;
1915 +       }
1916 +}
1917 +
1918 +static void cr(struct lcd_struct *p)
1919 +{
1920 +       clear_bit(NEED_WRAP, &p->struct_flags);
1921 +       p->col = (test_bit(INC_CURS_POS, &p->struct_flags) ? 0 : p->par->vs_cols-1);
1922 +}
1923 +
1924 +static void lf(struct lcd_struct *p)
1925 +{
1926 +       clear_bit(NEED_WRAP, &p->struct_flags);
1927 +       if (test_bit(INC_CURS_POS, &p->struct_flags)) {
1928 +               if (p->row+1 == p->bot && INPUT_STATE(p) != RAW) {
1929 +                       make_cursor_visible(p);
1930 +                       scrup(p, p->top, p->bot, 1);
1931 +               } else if (p->row+1 < p->par->vs_rows)
1932 +                       ++p->row;
1933 +       } else {
1934 +               if (p->row == p->top && INPUT_STATE(p) != RAW) {
1935 +                       make_cursor_visible(p);
1936 +                       scrdown(p, p->top, p->bot, 1);
1937 +               } else if (p->row)
1938 +                       --p->row;
1939 +       }
1940 +}
1941 +
1942 +static void ri(struct lcd_struct *p)
1943 +{
1944 +       clear_bit(NEED_WRAP, &p->struct_flags);
1945 +       if (test_bit(INC_CURS_POS, &p->struct_flags)) {
1946 +               if (p->row == p->top) {
1947 +                       make_cursor_visible(p);
1948 +                       scrdown(p, p->top, p->bot, 1);
1949 +               } else if (p->row)
1950 +                       --p->row;
1951 +       } else {
1952 +               if (p->row+1 == p->bot) {
1953 +                       make_cursor_visible(p);
1954 +                       scrup(p, p->top, p->bot, 1);
1955 +               } else if (p->row+1 < p->par->vs_rows)
1956 +                       ++p->row;
1957 +       }
1958 +}
1959 +
1960 +static void ff(struct lcd_struct *p)
1961 +{
1962 +       unsigned int vs_rows = p->par->vs_rows;
1963 +       unsigned int vs_cols = p->par->vs_cols;
1964 +
1965 +       clear_bit(NEED_WRAP, &p->struct_flags);
1966 +       if (p->driver->clear_display) {
1967 +               p->driver->clear_display();
1968 +               __memset_short(p->fb, p->erase_char, p->fb_size);
1969 +               __memset_short(p->display, p->erase_char, p->frame_size);
1970 +               p->frame_base = 0;
1971 +       } else if (test_bit(INC_CURS_POS, &p->struct_flags))
1972 +               lcd_memset(p, 0, p->erase_char, p->fb_size);
1973 +       else
1974 +               lcd_memset(p, p->fb_size-1, p->erase_char, p->fb_size);
1975 +
1976 +       if (test_bit(INC_CURS_POS, &p->struct_flags))
1977 +               p->row = p->col = 0;
1978 +       else {
1979 +               p->row = vs_rows-1;
1980 +               p->col = vs_cols-1;
1981 +       }
1982 +}
1983 +
1984 +static void tab(struct lcd_struct *p)
1985 +{
1986 +       struct lcd_parameters *par = p->par;
1987 +       unsigned int i, vs_cols = par->vs_cols;
1988 +
1989 +       clear_bit(NEED_WRAP, &p->struct_flags);
1990 +
1991 +       if (! par->tabstop)
1992 +               return;
1993 +
1994 +       if (test_bit(INC_CURS_POS, &p->struct_flags)) {
1995 +               i = par->tabstop-(p->col%par->tabstop);
1996 +               if (p->col+i < vs_cols)
1997 +                       p->col += i;
1998 +       } else {
1999 +               i = p->col%par->tabstop;
2000 +               i = (i == 0 ? par->tabstop : i);
2001 +               if (p->col >= i)
2002 +                       p->col -= i;
2003 +       }
2004 +}
2005 +
2006 +/*
2007 + * Control character handler.
2008 + */
2009 +static void control_char(struct lcd_struct *p, unsigned char val)
2010 +{
2011 +       switch (val) {
2012 +       case 0x08:      /* BS: Back Space (^H) */
2013 +       case 0x7f:      /* DEL: Delete */
2014 +               bs(p);
2015 +               return;
2016 +
2017 +       case 0x09:      /* HT: Horizontal Tab (^I) */
2018 +               tab(p);
2019 +               return;
2020 +
2021 +       case 0x0c:      /* FF: Form Feed (^L) */
2022 +               ff(p);
2023 +               return;
2024 +
2025 +       case 0x0a:      /* LF: Line Feed (^J) */
2026 +       case 0x0b:      /* VT: Vertical Tab (^K) */
2027 +               lf(p);
2028 +               if (! test_bit(CRLF, &p->struct_flags))
2029 +                       return;
2030 +
2031 +       case 0x0d:      /* CR: Carriage Return (^M) */
2032 +               cr(p);
2033 +               return;
2034 +
2035 +       case 0x16:      /* SYN: Synchronous Idle (^V) */
2036 +               SET_INPUT_STATE(p, SYN);
2037 +               return;
2038 +
2039 +       case 0x1b:      /* ESC: Start of escape sequence */
2040 +               SET_INPUT_STATE(p, ESC);
2041 +               return;
2042 +
2043 +       case 0x9b:      /* CSI: Start of CSI escape sequence */
2044 +               memset(p->csi_args, 0, sizeof(p->csi_args));
2045 +               p->index = 0;
2046 +               SET_INPUT_STATE(p, CSI);
2047 +               return;
2048 +       }
2049 +}
2050 +
2051 +static void gotoxy(struct lcd_struct *p, int new_col, int new_row)
2052 +{
2053 +       unsigned int vs_rows = p->par->vs_rows;
2054 +       unsigned int vs_cols = p->par->vs_cols;
2055 +
2056 +       clear_bit(NEED_WRAP, &p->struct_flags);
2057 +       if (new_row < 0)
2058 +               p->row = 0;
2059 +       else if (new_row >= vs_rows)
2060 +               p->row = vs_rows-1;
2061 +       else
2062 +               p->row = new_row;
2063 +
2064 +       if (new_col < 0)
2065 +               p->col = 0;
2066 +       else if (new_col >= vs_cols)
2067 +               p->col = vs_cols-1;
2068 +       else
2069 +               p->col = new_col;
2070 +
2071 +       if (make_cursor_visible(p))
2072 +               redraw_screen(p, 0, p->fb_size-1);
2073 +}
2074 +
2075 +
2076 +/******************************
2077 + * ECMA-48 CSI ESC- sequences *
2078 + ******************************/
2079 +static void csi_at(struct lcd_struct *p, unsigned int nr)
2080 +{
2081 +       unsigned int vs_cols = p->par->vs_cols;
2082 +
2083 +       if (p->col+nr > vs_cols)
2084 +               nr = vs_cols-p->col;
2085 +       else if (! nr)
2086 +               ++nr;
2087 +       lcd_insert_char(p, nr);
2088 +}
2089 +
2090 +static void csi_J(struct lcd_struct *p, unsigned int action)
2091 +{
2092 +       unsigned int vs_cols = p->par->vs_cols;
2093 +       unsigned int pos = (p->row*vs_cols)+p->col;
2094 +
2095 +       clear_bit(NEED_WRAP, &p->struct_flags);
2096 +       switch (action) {
2097 +       case 0:         /* From cursor to end of display */
2098 +               lcd_memset(p, pos, p->erase_char, p->fb_size-pos);
2099 +               return;
2100 +
2101 +       case 1:         /* From start of display to cursor */
2102 +               lcd_memset(p, 0, p->erase_char, pos+1);
2103 +               return;
2104 +
2105 +       case 2:         /* Whole display */
2106 +               lcd_memset(p, 0, p->erase_char, p->fb_size);
2107 +               return;
2108 +       }
2109 +}
2110 +
2111 +static void csi_K(struct lcd_struct *p, unsigned int action)
2112 +{
2113 +       unsigned int vs_cols = p->par->vs_cols;
2114 +       unsigned int row_start = p->row*vs_cols;
2115 +
2116 +       clear_bit(NEED_WRAP, &p->struct_flags);
2117 +       switch (action) {
2118 +       case 0:         /* From cursor to end of line */
2119 +               lcd_memset(p, row_start+p->col, p->erase_char, vs_cols-p->col);
2120 +               return;
2121 +
2122 +       case 1:         /* From start of line to cursor */
2123 +               lcd_memset(p, row_start, p->erase_char, p->col+1);
2124 +               return;
2125 +
2126 +       case 2:         /* Whole line */
2127 +               lcd_memset(p, row_start, p->erase_char, vs_cols);
2128 +               return;
2129 +       }
2130 +}
2131 +
2132 +static void csi_L(struct lcd_struct *p, unsigned int nr)
2133 +{
2134 +       unsigned int vs_rows = p->par->vs_rows;
2135 +       unsigned int vs_cols = p->par->vs_cols;
2136 +
2137 +       clear_bit(NEED_WRAP, &p->struct_flags);
2138 +       if (p->row+nr > vs_rows)
2139 +               nr = vs_rows-p->row;
2140 +       else if (! nr)
2141 +               ++nr;;
2142 +       lcd_memmove(p, (p->row+nr)*vs_cols, p->row*vs_cols, (vs_rows-p->row-nr)*vs_cols);
2143 +       lcd_memset(p, p->row*vs_cols, p->erase_char, nr*vs_cols);
2144 +}
2145 +
2146 +static void csi_M(struct lcd_struct *p, unsigned int nr)
2147 +{
2148 +       unsigned int vs_rows = p->par->vs_rows;
2149 +       unsigned int vs_cols = p->par->vs_cols;
2150 +
2151 +       clear_bit(NEED_WRAP, &p->struct_flags);
2152 +       if (p->row+nr > vs_rows)
2153 +               nr = vs_rows-p->row;
2154 +       else if (! nr)
2155 +               ++nr;;
2156 +       lcd_memmove(p, p->row*vs_cols, (p->row+nr)*vs_cols, (vs_rows-p->row-nr)*vs_cols);
2157 +       lcd_memset(p, (vs_rows-nr)*vs_cols, p->erase_char, nr*vs_cols);
2158 +}
2159 +
2160 +static void csi_P(struct lcd_struct *p, unsigned int nr)
2161 +{
2162 +       unsigned int vs_cols = p->par->vs_cols;
2163 +
2164 +       if (p->col+nr > vs_cols)
2165 +               nr = vs_cols-p->col;
2166 +       else if (! nr)
2167 +               ++nr;
2168 +       lcd_delete_char(p, nr);
2169 +}
2170 +
2171 +static void csi_X(struct lcd_struct *p, unsigned int nr)
2172 +{
2173 +       unsigned int vs_cols = p->par->vs_cols;
2174 +
2175 +       clear_bit(NEED_WRAP, &p->struct_flags);
2176 +       if (p->col+nr > vs_cols)
2177 +               nr = vs_cols-p->col;
2178 +       else if (! nr)
2179 +               ++nr;
2180 +       lcd_memset(p, (p->row*vs_cols)+p->col, p->erase_char, nr);
2181 +}
2182 +
2183 +static void csi_su(struct lcd_struct *p, unsigned char input)
2184 +{
2185 +       unsigned int vs_cols = p->par->vs_cols;
2186 +
2187 +       clear_bit(NEED_WRAP, &p->struct_flags);
2188 +       if (input == 'u') {
2189 +               p->row = p->s_offset/vs_cols;
2190 +               p->col = p->s_offset%vs_cols;
2191 +               p->color = p->s_color;
2192 +               p->attributes = p->s_attributes;
2193 +               return;
2194 +       }
2195 +       p->s_offset = (p->row*vs_cols)+p->col;
2196 +       p->s_color = p->color;
2197 +       p->s_attributes = p->attributes;
2198 +}
2199 +
2200 +static unsigned char build_attr(struct lcd_struct *p, unsigned char color, unsigned char intensity,
2201 +                               unsigned char blink, unsigned char underline, unsigned char reverse)
2202 +{
2203 +       unsigned char attr;
2204 +
2205 +       if (test_bit(CAN_DO_COLOR, &p->struct_flags)) {
2206 +               attr = color;
2207 +               if (underline)
2208 +                       attr = (attr & BG_MASK) | p->ulcolor;
2209 +               else if (intensity == 0)
2210 +                       attr = (attr & BG_MASK) | p->halfcolor;
2211 +               if (reverse)
2212 +                       attr = (attr & 0x88) | ((attr & 0x70) >> 4) | ((attr & 0x07) << 4);
2213 +               if (blink)
2214 +                       attr ^= 0x80;
2215 +               if (intensity == 2)
2216 +                       attr ^= 0x08;
2217 +       } else {
2218 +               attr = intensity;
2219 +               attr |= (underline ? ULINE : 0x00);
2220 +               attr |= (reverse ? REVERSE : 0x00);
2221 +               attr |= (blink ? BLINK : 0x00);
2222 +       }
2223 +
2224 +       return (attr);
2225 +}
2226 +
2227 +static void update_attr(struct lcd_struct *p)
2228 +{
2229 +       unsigned char intensity = p->attributes & 0x03;
2230 +       unsigned char underline = (p->attributes >> 2) & 0x01;
2231 +       unsigned char reverse = (p->attributes >> 3) & 0x01;
2232 +       unsigned char blink = (p->attributes >> 7) & 0x01;
2233 +       unsigned char decscnm = (p->struct_flags >> DECSCNM) & 0x01;
2234 +
2235 +       p->attr = build_attr(p, p->color, intensity, blink, underline, reverse^decscnm);
2236 +       p->erase_char = (build_attr(p, p->color, 1, blink, 0, decscnm) << 8) | ' ';
2237 +}
2238 +
2239 +static void default_attr(struct lcd_struct *p)
2240 +{
2241 +       p->attributes = 0x01;
2242 +       p->color = p->defcolor;
2243 +}
2244 +
2245 +static void lcd_invert_screen(struct lcd_struct *p, unsigned int offset, unsigned int len)
2246 +{
2247 +       if (test_bit(CAN_DO_COLOR, &p->struct_flags))
2248 +               while (len--) {
2249 +                       p->fb[offset] = (p->fb[offset] & 0x88ff) | ((p->fb[offset] & 0x7000) >> 4) | ((p->fb[offset] & 0x0700) << 4);
2250 +                       ++offset;
2251 +               }
2252 +       else
2253 +               while (len--) {
2254 +                       p->fb[offset] ^= 0x0800;
2255 +                       ++offset;
2256 +               }
2257 +}
2258 +
2259 +static void csi_m(struct lcd_struct *p, unsigned int n)
2260 +{
2261 +       int i, arg;
2262 +
2263 +       for (i = 0; i <= n; ++i)
2264 +               switch ((arg = p->csi_args[i]))
2265 +               {
2266 +                       case 0:
2267 +                               default_attr(p);
2268 +                               break;
2269 +
2270 +                       case 1:
2271 +                               p->attributes = (p->attributes & ~I_MASK) | 2;
2272 +                               break;
2273 +
2274 +                       case 2:
2275 +                               p->attributes = (p->attributes & ~I_MASK) | 0;
2276 +                               break;
2277 +
2278 +                       case 4:
2279 +                               p->attributes |= ULINE;
2280 +                               break;
2281 +
2282 +                       case 5:
2283 +                               p->attributes |= BLINK;
2284 +                               break;
2285 +
2286 +                       case 7:
2287 +                               p->attributes |= REVERSE;
2288 +                               break;
2289 +
2290 +                       case 21: case 22:
2291 +                               p->attributes = (p->attributes & ~I_MASK) | 1;
2292 +                               break;
2293 +
2294 +                       case 24:
2295 +                               p->attributes &= ~ULINE;
2296 +                               break;
2297 +
2298 +                       case 25:
2299 +                               p->attributes &= ~BLINK;
2300 +                               break;
2301 +
2302 +                       case 27:
2303 +                               p->attributes &= ~REVERSE;
2304 +                               break;
2305 +
2306 +                       case 38:
2307 +                               p->attributes |= ULINE;
2308 +                               p->color = (p->color & BG_MASK) | (p->defcolor & FG_MASK);
2309 +                               break;
2310 +
2311 +                       case 39:
2312 +                               p->attributes &= ~ULINE;
2313 +                               p->color = (p->color & BG_MASK) | (p->defcolor & FG_MASK);
2314 +                               break;
2315 +
2316 +                       case 49:
2317 +                               p->color = (p->defcolor & BG_MASK) | (p->color & FG_MASK);
2318 +                               break;
2319 +
2320 +                       default:
2321 +                               if (arg >= 30 && arg <= 37)
2322 +                                       p->color = (p->color & BG_MASK) | color_table[arg-30];
2323 +                               else if (arg >= 40 && arg <= 47)
2324 +                                       p->color = (p->color & FG_MASK) | (color_table[arg-40] << 4);
2325 +                               break;
2326 +               }
2327 +
2328 +       update_attr(p);
2329 +}
2330 +
2331 +static void csi_h(struct lcd_struct *p, unsigned char n)
2332 +{
2333 +       switch (n) {
2334 +               case 4:         /* Set insert mode */
2335 +                       set_bit(DECIM, &p->struct_flags);
2336 +                       return;
2337 +
2338 +               case 5:         /* Inverted screen mode */
2339 +                       if (test_bit(QUES, &p->struct_flags) && ! test_bit(DECSCNM, &p->struct_flags)) {
2340 +                               set_bit(DECSCNM, &p->struct_flags);
2341 +                               lcd_invert_screen(p, 0, p->fb_size);
2342 +                               update_attr(p);
2343 +                               redraw_screen(p, 0, p->fb_size-1);
2344 +                       }
2345 +                       return;
2346 +
2347 +               case 7:         /* Set autowrap */
2348 +                       if (test_bit(QUES, &p->struct_flags))
2349 +                               set_bit(DECAWM, &p->struct_flags);
2350 +                       return;
2351 +
2352 +               case 20:        /* Set cr lf */
2353 +                       set_bit(CRLF, &p->struct_flags);
2354 +                       return;
2355 +       }
2356 +}
2357 +
2358 +static void csi_l(struct lcd_struct *p, unsigned char n)
2359 +{
2360 +       switch (n) {
2361 +               case 4:         /* Reset insert mode */
2362 +                       clear_bit(DECIM, &p->struct_flags);
2363 +                       return;
2364 +
2365 +               case 5:         /* Normal screen mode */
2366 +                       if (test_bit(QUES, &p->struct_flags) && test_bit(DECSCNM, &p->struct_flags)) {
2367 +                               clear_bit(DECSCNM, &p->struct_flags);
2368 +                               lcd_invert_screen(p, 0, p->fb_size);
2369 +                               update_attr(p);
2370 +                               redraw_screen(p, 0, p->fb_size-1);
2371 +                       }
2372 +                       return;
2373 +
2374 +               case 7:         /* Reset autowrap */
2375 +                       if (test_bit(QUES, &p->struct_flags))
2376 +                               clear_bit(DECAWM, &p->struct_flags);
2377 +                       return;
2378 +
2379 +               case 20:        /* Reset cr lf */
2380 +                       clear_bit(CRLF, &p->struct_flags);
2381 +                       return;
2382 +       }
2383 +}
2384 +
2385 +static void csi_linux(struct lcd_struct *p)
2386 +{
2387 +       switch (p->csi_args[0]) {
2388 +       case 1:
2389 +               if (test_bit(CAN_DO_COLOR, &p->struct_flags) && p->csi_args[1] < 16) {
2390 +                       p->ulcolor = color_table[p->csi_args[1]];
2391 +                       if (p->attributes & ULINE)
2392 +                               update_attr(p);
2393 +               }
2394 +               return;
2395 +
2396 +       case 2:
2397 +               if (test_bit(CAN_DO_COLOR, &p->struct_flags) && p->csi_args[1] < 16) {
2398 +                       p->halfcolor = color_table[p->csi_args[1]];
2399 +                       if ((p->attributes & I_MASK) == 0)
2400 +                               update_attr(p);
2401 +               }
2402 +               return;
2403 +
2404 +       case 8:
2405 +               p->defcolor = p->color;
2406 +               default_attr(p);
2407 +               update_attr(p);
2408 +               return;
2409 +       }
2410 +}
2411 +
2412 +static void csi_r(struct lcd_struct *p, unsigned int top, unsigned int bot)
2413 +{
2414 +       /* Minimum allowed region is 2 lines */
2415 +       if (top < bot) {
2416 +               p->top = top-1;
2417 +               p->bot = bot;
2418 +               gotoxy(p, 0, 0);
2419 +       }
2420 +}
2421 +
2422 +/*
2423 + * ECMA-48 CSI ESC- sequence handler.
2424 + */
2425 +static void handle_csi(struct lcd_struct *p, unsigned char input)
2426 +{
2427 +       if (p->index >= NPAR) {
2428 +               SET_INPUT_STATE(p, NORMAL);
2429 +               printk(KERN_NOTICE "LCD: too many parameters in CSI escape sequence\n");
2430 +       } else if (input == '?') {
2431 +               set_bit(QUES, &p->struct_flags);
2432 +       } else if (input == ';') {
2433 +               ++p->index;
2434 +       } else if (input >= '0' && input <= '9') {
2435 +               p->csi_args[p->index] = (p->csi_args[p->index]*10)+(input-'0');
2436 +       } else {
2437 +               SET_INPUT_STATE(p, NORMAL);
2438 +               if (! test_bit(INC_CURS_POS, &p->struct_flags))
2439 +                       return;
2440 +               switch (input) {
2441 +               case 'h':               /* DECSET sequences and mode switches */
2442 +                       csi_h(p, p->csi_args[0]);
2443 +                       clear_bit(QUES, &p->struct_flags);
2444 +                       return;
2445 +
2446 +               case 'l':               /* DECRST sequences and mode switches */
2447 +                       csi_l(p, p->csi_args[0]);
2448 +                       clear_bit(QUES, &p->struct_flags);
2449 +                       return;
2450 +               }
2451 +               clear_bit(QUES, &p->struct_flags);
2452 +               switch (input) {
2453 +               case '@':               /* Insert # Blank character */
2454 +                       csi_at(p, p->csi_args[0]);
2455 +                       return;
2456 +
2457 +               case 'G': case '`':     /* Cursor to indicated column in current row */
2458 +                       if (p->csi_args[0])
2459 +                               --p->csi_args[0];
2460 +                       gotoxy(p, p->csi_args[0], p->row);
2461 +                       return;
2462 +
2463 +               case 'A':               /* Cursor # rows Up */
2464 +                       if (! p->csi_args[0])
2465 +                               ++p->csi_args[0];
2466 +                       gotoxy(p, p->col, p->row-p->csi_args[0]);
2467 +                       return;
2468 +
2469 +               case 'B': case 'e':     /* Cursor # rows Down */
2470 +                       if (! p->csi_args[0])
2471 +                               ++p->csi_args[0];
2472 +                       gotoxy(p, p->col, p->row+p->csi_args[0]);
2473 +                       return;
2474 +
2475 +               case 'C': case 'a':     /* Cursor # columns Right */
2476 +                       if (! p->csi_args[0])
2477 +                               ++p->csi_args[0];
2478 +                       gotoxy(p, p->col+p->csi_args[0], p->row);
2479 +                       return;
2480 +
2481 +               case 'D':               /* Cursor # columns Left */
2482 +                       if (! p->csi_args[0])
2483 +                               ++p->csi_args[0];
2484 +                       gotoxy(p, p->col-p->csi_args[0], p->row);
2485 +                       return;
2486 +
2487 +               case 'E':               /* Cursor # rows Down, column 1 */
2488 +                       if (! p->csi_args[0])
2489 +                               ++p->csi_args[0];
2490 +                       gotoxy(p, 0, p->row+p->csi_args[0]);
2491 +                       return;
2492 +
2493 +               case 'F':               /* Cursor # rows Up, column 1 */
2494 +                       if (! p->csi_args[0])
2495 +                               ++p->csi_args[0];
2496 +                       gotoxy(p, 0, p->row-p->csi_args[0]);
2497 +                       return;
2498 +
2499 +               case 'd':               /* Cursor to indicated row in current column */
2500 +                       if (p->csi_args[0])
2501 +                               --p->csi_args[0];
2502 +                       gotoxy(p, p->col, p->csi_args[0]);
2503 +                       return;
2504 +
2505 +               case 'H': case 'f':     /* Cursor to indicated row, column (origin 1, 1) */
2506 +                       if (p->csi_args[0])
2507 +                               --p->csi_args[0];
2508 +                       if (p->csi_args[1])
2509 +                               --p->csi_args[1];
2510 +                       gotoxy(p, p->csi_args[1], p->csi_args[0]);
2511 +                       return;
2512 +
2513 +               case 'J':               /* Erase display */
2514 +                       csi_J(p, p->csi_args[0]);
2515 +                       return;
2516 +
2517 +               case 'K':               /* Erase line */
2518 +                       csi_K(p, p->csi_args[0]);
2519 +                       return;
2520 +
2521 +               case 'L':               /* Insert # blank lines */
2522 +                       csi_L(p, p->csi_args[0]);
2523 +                       return;
2524 +
2525 +               case 'M':               /* Delete # blank lines */
2526 +                       csi_M(p, p->csi_args[0]);
2527 +                       return;
2528 +
2529 +               case 'P':               /* Delete # characters on the current line */
2530 +                       csi_P(p, p->csi_args[0]);
2531 +                       return;
2532 +
2533 +               case 'X':               /* Erase # characters on the current line */
2534 +                       csi_X(p, p->csi_args[0]);
2535 +                       return;
2536 +
2537 +               case 'm':               /* Set video attributes */
2538 +                       csi_m(p, p->index);
2539 +                       return;
2540 +
2541 +               case 's':               /* Save cursor position */
2542 +               case 'u':               /* Restore cursor position */
2543 +                       csi_su(p, input);
2544 +                       return;
2545 +
2546 +               case ']':               /* Linux private ESC [ ] sequence */
2547 +                       csi_linux(p);
2548 +                       return;
2549 +
2550 +               case 'r':               /* Set the scrolling region */
2551 +                       if (! p->csi_args[0])
2552 +                               ++p->csi_args[0];
2553 +                       if (! p->csi_args[1] || p->csi_args[1] > p->par->vs_rows)
2554 +                               p->csi_args[1] = p->par->vs_rows;
2555 +                       csi_r(p, p->csi_args[0], p->csi_args[1]);
2556 +                       return;
2557 +
2558 +                                       /* Ignored escape sequences */
2559 +               case 'c':
2560 +               case 'g':
2561 +               case 'n':
2562 +               case 'q':
2563 +                       return;
2564 +
2565 +               default:
2566 +                       printk(KERN_NOTICE "LCD: unrecognized CSI escape sequence: ESC [ %u\n", input);
2567 +                       return;
2568 +               }
2569 +       }
2570 +}
2571 +
2572 +/*
2573 + * Custom ESC- sequence handler.
2574 + */
2575 +static int handle_custom_esc(struct lcd_struct *p, unsigned int _input)
2576 +{
2577 +       unsigned char input = _input & 0xff;
2578 +       struct lcd_parameters *par = p->par;
2579 +
2580 +       if (_input & (~0xff)) {
2581 +               switch (ESC_STATE(p)) {
2582 +               case 's':
2583 +                       if (p->index++) {
2584 +                               unsigned char *buf = p->cgram_buffer+(p->cgram_index-par->cgram_char0)*par->cgram_bytes;
2585 +
2586 +                               buf[p->index-2] = input;
2587 +                               if (p->index == par->cgram_bytes+1)
2588 +                                       write_cgram(p, p->cgram_index, buf);
2589 +                       } else {
2590 +                               if (! p->driver->write_cgram_char) {
2591 +                                       printk(KERN_ERR "LCD: %s: missing function to write to CGRAM\n", p->par->name);
2592 +                                       return (-1);
2593 +                               }
2594 +                               if (input >= par->cgram_char0 && input < par->cgram_char0+par->cgram_chars)
2595 +                                       p->cgram_index = input;
2596 +                               else {
2597 +                                       printk(KERN_NOTICE "LCD: bad CGRAM index\n");
2598 +                                       return (-1);
2599 +                               }
2600 +                       }
2601 +                       return (0);
2602 +
2603 +               case 'G':
2604 +                       if (input >= par->cgram_char0 && input < par->cgram_char0+par->cgram_chars)
2605 +                               write_data(p, (p->attr << 8) | p->driver->charmap[input]);
2606 +                       else {
2607 +                               SET_INPUT_STATE(p, NORMAL);
2608 +                               handle_input(p, (p->attr << 8) | input);
2609 +                       }
2610 +                       return (0);
2611 +
2612 +               case 'r':
2613 +                       if (input == '1')
2614 +                               address_mode(p, -1);
2615 +                       else if (input == '0')
2616 +                               address_mode(p, 1);
2617 +                       return (0);
2618 +
2619 +               case 'A':
2620 +                       scrup(p, p->top, p->bot, input);
2621 +                       return (0);
2622 +
2623 +               case 'B':
2624 +                       scrdown(p, p->top, p->bot, input);
2625 +                       return (0);
2626 +
2627 +               case 'C':
2628 +                       browse_screen(p, input);
2629 +                       return (0);
2630 +               }
2631 +       }
2632 +
2633 +       /* These are the custom ESC- sequences */
2634 +       switch (input) {
2635 +       case 's':       /* CGRAM select */
2636 +               if (p->cgram_buffer) {
2637 +                       SET_ESC_STATE(p, input);
2638 +                       p->index = 0;
2639 +                       return (par->cgram_bytes+1);
2640 +               } else {
2641 +                       printk(KERN_NOTICE "LCD: driver %s does not support CGRAM chars\n", par->name);
2642 +                       return (0);
2643 +               }
2644 +
2645 +       case 'A':       /* Scroll up */
2646 +       case 'B':       /* Scroll down */
2647 +       case 'C':       /* Browse screen */
2648 +       case 'G':       /* Enter cgram mode */
2649 +       case 'r':       /* Decrement counter after data read/write */
2650 +               SET_ESC_STATE(p, input);
2651 +               return (1);
2652 +       }
2653 +
2654 +       return (-1);
2655 +}
2656 +
2657 +/*
2658 + * ESC- but not CSI sequence handler.
2659 + */
2660 +static int handle_esc(struct lcd_struct *p, unsigned char input)
2661 +{
2662 +       int ret;
2663 +
2664 +       SET_INPUT_STATE(p, NORMAL);
2665 +       switch (input) {
2666 +       case 'c':       /* Reset */
2667 +               set_bit(DECAWM, &p->struct_flags);
2668 +               set_bit(INC_CURS_POS, &p->struct_flags);
2669 +               ff(p);
2670 +               return (0);
2671 +
2672 +       case 'D':       /* Line Feed */
2673 +               lf(p);
2674 +               return (0);
2675 +
2676 +       case 'E':       /* New Line */
2677 +               cr(p);
2678 +               lf(p);
2679 +               return (0);
2680 +
2681 +       case 'M':       /* Reverse Line Feed */
2682 +               ri(p);
2683 +               return (0);
2684 +
2685 +       case '7':
2686 +       case '8':
2687 +               csi_su(p, (input == '7' ? 's' : 'u'));
2688 +               return (0);
2689 +
2690 +       /* CSI: Start of CSI escape sequence */
2691 +       case '[':
2692 +               memset(p->csi_args, 0, sizeof(p->csi_args));
2693 +               p->index = 0;
2694 +               SET_INPUT_STATE(p, CSI);
2695 +               return (0);
2696 +
2697 +       /* Ignored escape sequences */
2698 +       case '(':
2699 +               SET_INPUT_STATE(p, ESC_G0);
2700 +               return (1);
2701 +
2702 +       case ')':
2703 +               SET_INPUT_STATE(p, ESC_G1);
2704 +               return (1);
2705 +
2706 +       case '#':
2707 +               SET_INPUT_STATE(p, ESC_HASH);
2708 +               return (1);
2709 +
2710 +       case '%':
2711 +               SET_INPUT_STATE(p, ESC_PERCENT);
2712 +               return (1);
2713 +
2714 +       case 'H':
2715 +       case 'Z':
2716 +       case '>':
2717 +       case '=':
2718 +       case ']':
2719 +               return (0);
2720 +       }
2721 +
2722 +       /* These are the custom ESC- sequences */
2723 +       if ((ret = handle_custom_esc(p, input)) > 0) {
2724 +               SET_INPUT_STATE(p, ARG);
2725 +               return (ret);
2726 +       }
2727 +
2728 +       if (ret < 0 && p->driver->handle_custom_char)
2729 +               if ((ret = p->driver->handle_custom_char(input)) > 0) {
2730 +                       SET_INPUT_STATE(p, ARG_DRIVER);
2731 +                       return (ret);
2732 +               }
2733 +
2734 +       if (ret < 0)
2735 +               printk(KERN_NOTICE "LCD: unrecognized escape sequence: ESC %u\n", input);
2736 +
2737 +       return (0);
2738 +}
2739 +
2740 +/*
2741 + * Main input handler.
2742 + */
2743 +static void handle_input(struct lcd_struct *p, unsigned short _input)
2744 +{
2745 +       unsigned char input = _input & 0xff;
2746 +       struct lcd_driver *driver = p->driver;
2747 +
2748 +       switch (INPUT_STATE(p)) {
2749 +       case NORMAL:
2750 +               if (input < 0x20 || input == 0x9b)
2751 +                       control_char(p, input);
2752 +               else
2753 +                       write_data(p, (_input & 0xff00) | driver->charmap[input]);
2754 +               return;
2755 +
2756 +       case RAW:
2757 +               write_data(p, (_input & 0xff00) | driver->charmap[input]);
2758 +               return;
2759 +
2760 +       case SYN:
2761 +               write_data(p, _input);
2762 +               SET_INPUT_STATE(p, NORMAL);
2763 +               return;
2764 +
2765 +       case ESC:
2766 +               p->esc_args = handle_esc(p, input);
2767 +               return;
2768 +
2769 +       case ESC_G0:
2770 +       case ESC_G1:
2771 +       case ESC_HASH:
2772 +       case ESC_PERCENT:
2773 +               if (! --p->esc_args)
2774 +                       SET_INPUT_STATE(p, NORMAL);
2775 +               return;
2776 +
2777 +       case CSI:
2778 +               handle_csi(p, input);
2779 +               return;
2780 +
2781 +       case ARG:
2782 +               if (handle_custom_esc(p, 0x100 | input) || ! --p->esc_args)
2783 +                       SET_INPUT_STATE(p, NORMAL);
2784 +               return;
2785 +
2786 +       case ARG_DRIVER:
2787 +               if (driver->handle_custom_char(0x100 | input) || ! --p->esc_args)
2788 +                       SET_INPUT_STATE(p, NORMAL);
2789 +               return;
2790 +       }
2791 +}
2792 +
2793 +
2794 +
2795 +
2796 +
2797 +/***************************************
2798 + * Read from/Write to display routines *
2799 + ***************************************/
2800 +
2801 +/*
2802 + * Write character data to the display.
2803 + */
2804 +static void write_data(struct lcd_struct *p, unsigned short data)
2805 +{
2806 +       unsigned int vs_cols = p->par->vs_cols;
2807 +       unsigned int pos;
2808 +       int frame_pos;
2809 +
2810 +       if (test_bit(NEED_WRAP, &p->struct_flags)) {
2811 +               cr(p);
2812 +               lf(p);
2813 +       }
2814 +
2815 +       if (test_bit(DECIM, &p->struct_flags))
2816 +               lcd_insert_char(p, 1);
2817 +
2818 +       pos = (p->row*vs_cols)+p->col;
2819 +       if ((frame_pos = vs_to_frame_(p, pos)) < 0) {
2820 +               make_cursor_visible(p);
2821 +               redraw_screen(p, 0, p->fb_size-1);
2822 +               frame_pos = vs_to_frame_(p, pos);
2823 +       }
2824 +
2825 +       if (p->display[frame_pos] != data) {
2826 +               p->driver->write_char(frame_pos, data);
2827 +               p->display[frame_pos] = data;
2828 +       }
2829 +
2830 +       p->fb[pos] = data;
2831 +
2832 +       if (test_bit(INC_CURS_POS, &p->struct_flags)) {
2833 +               if (p->col+1 < vs_cols)
2834 +                       iterator_inc(p->col, vs_cols);
2835 +               else if (test_bit(DECAWM, &p->struct_flags))
2836 +                       set_bit(NEED_WRAP, &p->struct_flags);
2837 +       } else {
2838 +               if (p->col)
2839 +                       iterator_dec(p->col, vs_cols);
2840 +               else if (test_bit(DECAWM, &p->struct_flags))
2841 +                       set_bit(NEED_WRAP, &p->struct_flags);
2842 +       }
2843 +}
2844 +
2845 +/*
2846 + * Write an entire CGRAM character to the display.
2847 + */
2848 +static void write_cgram(struct lcd_struct *p, unsigned char index, unsigned char *pixels)
2849 +{
2850 +       unsigned int inc_set = test_bit(INC_CURS_POS, &p->struct_flags);
2851 +
2852 +       if (! inc_set)
2853 +               address_mode(p, 1);
2854 +
2855 +       p->driver->write_cgram_char(index, pixels);
2856 +
2857 +       if (! inc_set)
2858 +               address_mode(p, -1);
2859 +}
2860 +
2861 +/*
2862 + * Read character data from the display.
2863 + */
2864 +static void read_data(struct lcd_struct *p, unsigned short *data)
2865 +{
2866 +       unsigned int vs_rows = p->par->vs_rows;
2867 +       unsigned int vs_cols = p->par->vs_cols;
2868 +       unsigned int pos = (p->row*vs_cols)+p->col;
2869 +       int frame_pos;
2870 +
2871 +       if ((frame_pos = vs_to_frame_(p, pos)) < 0) {
2872 +               make_cursor_visible(p);
2873 +               redraw_screen(p, 0, p->fb_size-1);
2874 +               frame_pos = vs_to_frame_(p, pos);
2875 +       }
2876 +
2877 +       p->driver->read_char(frame_pos, data);
2878 +
2879 +       if (test_bit(INC_CURS_POS, &p->struct_flags)) {
2880 +               iterator_inc(p->col, vs_cols);
2881 +               if (! p->col) {
2882 +                       if (p->row+1 < vs_rows)
2883 +                               ++p->row;
2884 +               }
2885 +       } else {
2886 +               iterator_dec(p->col, vs_cols);
2887 +               if (p->col+1 == vs_cols) {
2888 +                       if (p->row)
2889 +                               --p->row;
2890 +               }
2891 +       }
2892 +}
2893 +
2894 +/*
2895 + * Read an entire CGRAM character from the display.
2896 + */
2897 +static void read_cgram(struct lcd_struct *p, unsigned char index, unsigned char *pixels)
2898 +{
2899 +       unsigned int inc_set = test_bit(INC_CURS_POS, &p->struct_flags);
2900 +
2901 +       if (! inc_set)
2902 +               address_mode(p, 1);
2903 +
2904 +       p->driver->read_cgram_char(index, pixels);
2905 +
2906 +       if (! inc_set)
2907 +               address_mode(p, -1);
2908 +}
2909 +
2910 +
2911 +
2912 +
2913 +
2914 +/****************************
2915 + * Proc filesystem routines *
2916 + ****************************/
2917 +#ifdef USE_PROC
2918 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
2919 +/* create_proc_read_entry is missing in 2.2.x kernels */
2920 +static struct proc_dir_entry *create_proc_read_entry(const char *name, mode_t mode,
2921 +                       struct proc_dir_entry *parent, read_proc_t *read_proc, void *data)
2922 +{
2923 +       struct proc_dir_entry *res = create_proc_entry(name, mode, parent);
2924 +
2925 +       if (res) {
2926 +               res->read_proc = read_proc;
2927 +               res->data = data;
2928 +       }
2929 +
2930 +       return (res);
2931 +}
2932 +#endif
2933 +
2934 +static int proc_fb_read(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
2935 +{
2936 +       char *temp = buffer;
2937 +       struct lcd_struct *p = (struct lcd_struct *)data;
2938 +       unsigned int vs_cols;
2939 +       static unsigned int nr, need_wrap;
2940 +       static off_t _offset;
2941 +
2942 +       down(&p->lcd_sem);
2943 +       if (! offset)
2944 +               _offset = 0;
2945 +       if ((*eof = (_offset >= p->fb_size))) {
2946 +               up(&p->lcd_sem);
2947 +               return (0);
2948 +       }
2949 +       vs_cols = p->par->vs_cols;
2950 +       if (size && need_wrap) {
2951 +               need_wrap = 0;
2952 +               temp += sprintf(temp, "\n");
2953 +               --size;
2954 +       }
2955 +       if (! nr)
2956 +               nr = vs_cols;
2957 +       *start = (char *)0;
2958 +       while (size && nr) {
2959 +               unsigned char c = (p->fb[_offset] & 0xff);
2960 +
2961 +               temp += sprintf(temp, "%c", (c < 0x20 ? '·' : c));
2962 +               --size;
2963 +               --nr;
2964 +               ++*start;
2965 +               ++_offset;
2966 +       }
2967 +       if (! nr) {
2968 +               if (size) {
2969 +                       temp += sprintf(temp, "\n");
2970 +                       --size;
2971 +               } else
2972 +                       need_wrap = 1;
2973 +       }
2974 +       up(&p->lcd_sem);
2975 +
2976 +       return (temp-buffer);
2977 +}
2978 +
2979 +static int proc_display_read(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
2980 +{
2981 +       char *temp = buffer;
2982 +       struct lcd_struct *p = (struct lcd_struct *)data;
2983 +       unsigned int i, frame_cols;
2984 +       int frame_pos;
2985 +
2986 +       down(&p->lcd_sem);
2987 +       frame_cols = p->par->cntr_cols;
2988 +       frame_pos = vs_to_frame_(p, (p->row*p->par->vs_cols)+p->col);
2989 +       temp += sprintf(temp, "    ");
2990 +       for (i = 2; i <= frame_cols; i += 2)
2991 +               temp += sprintf(temp, " %d", i%10);
2992 +       temp += sprintf(temp, "\n");
2993 +
2994 +       temp += sprintf(temp, "   +");
2995 +       for (i = 0; i < frame_cols; ++i)
2996 +               temp += sprintf(temp, "-");
2997 +       temp += sprintf(temp, "+\n");
2998 +
2999 +       for (i = 0; i < p->frame_size; ++i) {
3000 +               unsigned char c = (p->display[i] & 0xff);
3001 +
3002 +               if (! (i%frame_cols))
3003 +                       temp += sprintf(temp, "%2d |", 1+i/frame_cols);
3004 +               if (frame_pos--)
3005 +                       temp += sprintf(temp, "%c", (c < 0x20 ? '·' : c));
3006 +               else
3007 +                       temp += sprintf(temp, "_");
3008 +               if (! ((i+1)%frame_cols))
3009 +                       temp += sprintf(temp, "|\n");
3010 +       }
3011 +
3012 +       temp += sprintf(temp, "   +");
3013 +       for (i = 0; i < frame_cols; ++i)
3014 +               temp += sprintf(temp, "-");
3015 +       temp += sprintf(temp, "+\n");
3016 +       up(&p->lcd_sem);
3017 +
3018 +       return (temp-buffer);
3019 +}
3020 +
3021 +static int proc_charmap_read(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
3022 +{
3023 +       char *temp = buffer;
3024 +       struct lcd_struct *p = (struct lcd_struct *)data;
3025 +       unsigned char *charmap;
3026 +       unsigned int i;
3027 +
3028 +       down(&p->lcd_sem);
3029 +       charmap = p->driver->charmap;
3030 +       temp += sprintf(temp,   "static unsigned char charmap[] = {");
3031 +       for (i = 0; i < 255; ++i) {
3032 +               if (! (i & 7)) {
3033 +                       temp += sprintf(temp, "\n");
3034 +                       if (! (i & 31))
3035 +                               temp += sprintf(temp, "\n/* %d - %d */\n", i, i+31);
3036 +               }
3037 +               temp += sprintf(temp, "0x%.2x, ", *charmap++);
3038 +       }
3039 +       temp += sprintf(temp, "0x%.2x\n\n};\n", *charmap);
3040 +       up(&p->lcd_sem);
3041 +
3042 +       return (temp-buffer);
3043 +}
3044 +
3045 +static int proc_registered_drivers(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
3046 +{
3047 +       char *temp = buffer;
3048 +       struct list_head *entry;
3049 +
3050 +       down(&drivers_sem);
3051 +       temp += sprintf(temp, "Registered drivers:\n");
3052 +       list_for_each(entry, &lcd_drivers) {
3053 +               struct lcd_struct *p = list_entry(entry, struct lcd_struct, lcd_list);
3054 +
3055 +               down(&p->lcd_sem);
3056 +               temp += sprintf(temp, "%3d %s\n", p->par->minor, p->par->name);
3057 +               up(&p->lcd_sem);
3058 +       }
3059 +       up(&drivers_sem);
3060 +
3061 +       return (temp-buffer);
3062 +}
3063 +
3064 +static void create_driver_proc_entries(struct lcd_struct *p)
3065 +{
3066 +       struct proc_dir_entry *driver_proc_root = p->driver->driver_proc_root;
3067 +       int proc_level = 0;
3068 +
3069 +       SET_PROC_LEVEL(p, proc_level);
3070 +       if (create_proc_read_entry("framebuffer", 0, driver_proc_root, proc_fb_read, p) == NULL) {
3071 +               printk(KERN_ERR "LCD: cannot create /proc/lcd/%s/framebuffer\n", p->par->name);
3072 +               return;
3073 +       }
3074 +       SET_PROC_LEVEL(p, ++proc_level);
3075 +       if (create_proc_read_entry("display", 0, driver_proc_root, proc_display_read, p) == NULL) {
3076 +               printk(KERN_ERR "LCD: cannot create /proc/lcd/%s/display\n", p->par->name);
3077 +               return;
3078 +       }
3079 +       SET_PROC_LEVEL(p, ++proc_level);
3080 +       if (create_proc_read_entry("charmap.h", 0, driver_proc_root, proc_charmap_read, p) == NULL) {
3081 +               printk(KERN_ERR "LCD: cannot create /proc/lcd/%s/charmap.h\n", p->par->name);
3082 +               return;
3083 +       }
3084 +       SET_PROC_LEVEL(p, ++proc_level);
3085 +}
3086 +
3087 +static void remove_driver_proc_entries(struct lcd_struct *p)
3088 +{
3089 +       struct proc_dir_entry *driver_proc_root = p->driver->driver_proc_root;
3090 +
3091 +       switch (PROC_LEVEL(p)) {
3092 +       case 3:
3093 +               remove_proc_entry("charmap.h", driver_proc_root);
3094 +       case 2:
3095 +               remove_proc_entry("display", driver_proc_root);
3096 +       case 1:
3097 +               remove_proc_entry("framebuffer", driver_proc_root);
3098 +       }
3099 +       SET_PROC_LEVEL(p, 0);
3100 +}
3101 +#endif
3102 +
3103 +
3104 +
3105 +
3106 +
3107 +/*****************************
3108 + * Low level file operations *
3109 + *****************************/
3110 +static ssize_t do_lcd_read(struct lcd_struct *p, void *buffer, size_t length)
3111 +{
3112 +       unsigned int i;
3113 +       unsigned short tmp;
3114 +
3115 +       if (! p->refcount)
3116 +               return (-ENXIO);
3117 +
3118 +       if (! p->driver->read_char) {
3119 +               printk(KERN_NOTICE "LCD: driver %s doesn't support reading\n", p->par->name);
3120 +               return (-ENOSYS);
3121 +       }
3122 +
3123 +       if (test_bit(WITH_ATTR, &p->struct_flags))
3124 +               for (i = 0; i < length; ++i) {
3125 +                       read_data(p, &tmp);
3126 +                       ((unsigned short *)buffer)[i] = tmp;
3127 +               }
3128 +       else
3129 +               for (i = 0; i < length; ++i) {
3130 +                       read_data(p, &tmp);
3131 +                       ((unsigned char *)buffer)[i] = tmp & 0xff;
3132 +               }
3133 +
3134 +       return (length);
3135 +}
3136 +
3137 +static ssize_t do_lcd_write(struct lcd_struct *p, const void *buffer, size_t length)
3138 +{
3139 +       unsigned int i;
3140 +
3141 +       if (! p->refcount)
3142 +               return (-ENXIO);
3143 +
3144 +       if (test_bit(WITH_ATTR, &p->struct_flags))
3145 +               for (i = 0; i < length; ++i)
3146 +                       handle_input(p, ((const unsigned short *)buffer)[i]);
3147 +       else
3148 +               for (i = 0; i < length; ++i)
3149 +                       handle_input(p, (p->attr << 8) | ((const unsigned char *)buffer)[i]);
3150 +
3151 +       return (length);
3152 +}
3153 +
3154 +static int do_lcd_open(struct lcd_struct *p)
3155 +{
3156 +       if (! p->refcount) {
3157 +               if (p->driver->driver_module) {
3158 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
3159 +                       if (! try_module_get(p->driver->driver_module))
3160 +                               return (-EBUSY);
3161 +#else
3162 +                       if (__MOD_IN_USE(p->driver->driver_module))
3163 +                               return (-EBUSY);
3164 +
3165 +                       __MOD_INC_USE_COUNT(p->driver->driver_module);
3166 +#endif
3167 +               }
3168 +       }
3169 +
3170 +       ++p->refcount;
3171 +
3172 +       return (0);
3173 +}
3174 +
3175 +static int do_lcd_release(struct lcd_struct *p)
3176 +{
3177 +       if (! p->refcount)
3178 +               return (0);
3179 +
3180 +       if (p->refcount == 1) {
3181 +               if (p->driver->driver_module)
3182 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
3183 +                       module_put(p->driver->driver_module);
3184 +#else
3185 +                       __MOD_DEC_USE_COUNT(p->driver->driver_module);
3186 +#endif
3187 +       }
3188 +
3189 +       --p->refcount;
3190 +
3191 +       return (0);
3192 +}
3193 +
3194 +static int cgram_ioctl(struct lcd_struct *p, unsigned int cmd, unsigned char *argp)
3195 +{
3196 +       struct lcd_parameters *par = p->par;
3197 +       unsigned int length = par->cgram_bytes;
3198 +       unsigned char index = argp[0];
3199 +       unsigned char *buffer = argp+1;
3200 +       unsigned char *cgram_buffer = p->cgram_buffer+(index-par->cgram_char0)*length;
3201 +
3202 +       if (index < par->cgram_char0 || index >= par->cgram_char0+par->cgram_chars)
3203 +               return (-EINVAL);
3204 +
3205 +       if (cmd == LCDL_SET_CGRAM_CHAR) {
3206 +               if (! p->driver->write_cgram_char) {
3207 +                       printk(KERN_ERR "LCD: %s: missing function to write to CGRAM\n", p->par->name);
3208 +                       return (-ENOSYS);
3209 +               }
3210 +               if (test_bit(USER_SPACE, &p->struct_flags)) {
3211 +                       if (copy_from_user(cgram_buffer, buffer, length))
3212 +                               return (-EFAULT);
3213 +               } else
3214 +                       memcpy(cgram_buffer, buffer, length);
3215 +               write_cgram(p, index, cgram_buffer);
3216 +       } else {
3217 +               if (! p->driver->read_cgram_char) {
3218 +                       printk(KERN_ERR "LCD: %s: missing function to read from CGRAM or unable to read\n", p->par->name);
3219 +                       return (-ENOSYS);
3220 +               }
3221 +               read_cgram(p, index, cgram_buffer);
3222 +               if (test_bit(USER_SPACE, &p->struct_flags)) {
3223 +                       if (copy_to_user(buffer, cgram_buffer, length))
3224 +                               return (-EFAULT);
3225 +               } else
3226 +                       memcpy(buffer, cgram_buffer, length);
3227 +       }
3228 +
3229 +       return (0);
3230 +}
3231 +
3232 +static int do_lcd_ioctl(struct lcd_struct *p, unsigned int cmd, unsigned long arg)
3233 +{
3234 +       int i;
3235 +       struct lcd_driver *driver = p->driver;
3236 +       struct lcd_parameters *par = p->par;
3237 +       unsigned char *argp = (unsigned char *)arg;
3238 +
3239 +       if (! p->refcount)
3240 +               return (-ENXIO);
3241 +
3242 +       switch (cmd) {
3243 +       case LCDL_SET_PARAM:
3244 +               if ((i = cleanup_driver(p)))
3245 +                       return (i);
3246 +               i = par->minor;
3247 +               if (test_bit(USER_SPACE, &p->struct_flags)) {
3248 +                       if (copy_from_user(par, argp, sizeof(struct lcd_parameters)))
3249 +                               return (-EFAULT);
3250 +               } else
3251 +                       memcpy(par, argp, sizeof(struct lcd_parameters));
3252 +               par->minor = i;
3253 +               return (init_driver(p));
3254 +
3255 +       case LCDL_GET_PARAM:
3256 +               if (test_bit(USER_SPACE, &p->struct_flags)) {
3257 +                       if (copy_to_user(argp, par, sizeof(struct lcd_parameters)))
3258 +                               return (-EFAULT);
3259 +               } else
3260 +                       memcpy(argp, par, sizeof(struct lcd_parameters));
3261 +               return (0);
3262 +
3263 +       case LCDL_RESET_CHARMAP:
3264 +               for (i = 0; i < 256; ++i)
3265 +                       driver->charmap[i] = i;
3266 +               return (0);
3267 +
3268 +       case LCDL_CHARSUBST:
3269 +               if (test_bit(USER_SPACE, &p->struct_flags)) {
3270 +                       get_user(i, argp);
3271 +                       get_user(driver->charmap[i], argp+1);
3272 +               } else {
3273 +                       i = argp[0];
3274 +                       driver->charmap[i] = argp[1];
3275 +               }
3276 +               return (0);
3277 +
3278 +       case LCDL_SAVE_CHARMAP:
3279 +               memcpy(p->s_charmap, driver->charmap, 256);
3280 +               return (0);
3281 +
3282 +       case LCDL_RESTORE_CHARMAP:
3283 +               memcpy(driver->charmap, p->s_charmap, 256);
3284 +               return (0);
3285 +
3286 +       case LCDL_SWAP_CHARMAP:
3287 +               {
3288 +                       unsigned char *tmp;
3289 +
3290 +                       tmp = driver->charmap;
3291 +                       driver->charmap = p->s_charmap;
3292 +                       p->s_charmap = tmp;
3293 +               }
3294 +               return (0);
3295 +
3296 +       case LCDL_RAW_MODE:
3297 +               if (arg) {
3298 +                       clear_bit(NEED_WRAP, &p->struct_flags);
3299 +                       clear_bit(DECIM, &p->struct_flags);
3300 +                       clear_bit(DECAWM, &p->struct_flags);
3301 +                       SET_INPUT_STATE(p, RAW);
3302 +               } else {
3303 +                       set_bit(DECAWM, &p->struct_flags);
3304 +                       SET_INPUT_STATE(p, NORMAL);
3305 +               }
3306 +               return (0);
3307 +
3308 +       case LCDL_CLEAR_DISP:
3309 +               ff(p);
3310 +               return (0);
3311 +
3312 +       case LCDL_SET_CGRAM_CHAR:
3313 +       case LCDL_GET_CGRAM_CHAR:
3314 +               if (p->cgram_buffer)
3315 +                       return (cgram_ioctl(p, cmd, argp));
3316 +               else
3317 +                       printk(KERN_NOTICE "LCD: driver %s does not support CGRAM chars\n", par->name);
3318 +               return (0);
3319 +
3320 +       case LCDL_SET_CHARMAP:
3321 +               if (test_bit(USER_SPACE, &p->struct_flags)) {
3322 +                       if (copy_from_user(driver->charmap, argp, 256))
3323 +                               return (-EFAULT);
3324 +               } else
3325 +                       memcpy(driver->charmap, argp, 256);
3326 +               return (0);
3327 +
3328 +       case LCDL_GET_CHARMAP:
3329 +               if (test_bit(USER_SPACE, &p->struct_flags)) {
3330 +                       if (copy_to_user(argp, driver->charmap, 256))
3331 +                               return (-EFAULT);
3332 +               } else
3333 +                       memcpy(argp, driver->charmap, 256);
3334 +               return (0);
3335 +
3336 +       case LCDL_MEMSET:
3337 +       case LCDL_MEMMOVE:
3338 +       {
3339 +               int buf[3];
3340 +
3341 +               if (test_bit(USER_SPACE, &p->struct_flags)) {
3342 +                       if (copy_from_user(buf, argp, sizeof(buf)))
3343 +                               return (-EFAULT);
3344 +               } else
3345 +                       memcpy(buf, argp, sizeof(buf));
3346 +
3347 +               if (cmd == LCDL_MEMSET)
3348 +                       lcd_memset(p, buf[0], buf[1], buf[2]);
3349 +               else
3350 +                       lcd_memmove(p, buf[0], buf[1], buf[2]);
3351 +
3352 +               return (0);
3353 +       }
3354 +
3355 +       default:
3356 +               if (driver->handle_custom_ioctl)
3357 +                       return (driver->handle_custom_ioctl(cmd, arg, test_bit(USER_SPACE, &p->struct_flags)));
3358 +       }
3359 +
3360 +       return (-ENOIOCTLCMD);
3361 +}
3362 +
3363 +
3364 +
3365 +
3366 +
3367 +/**************************************************
3368 + * Kernel register/unregister lcd driver routines *
3369 + **************************************************/
3370 +/*
3371 + * Find a driver in lcd_drivers linked list
3372 + */
3373 +static struct lcd_struct *find_lcd_struct(unsigned short minor)
3374 +{
3375 +       struct list_head *entry;
3376 +
3377 +       list_for_each(entry, &lcd_drivers) {
3378 +               struct lcd_struct *p = list_entry(entry, struct lcd_struct, lcd_list);
3379 +
3380 +               if (p->par->minor == minor)
3381 +                       return (p);
3382 +       }
3383 +
3384 +       return (NULL);
3385 +}
3386 +
3387 +static void list_add_sorted(struct list_head *new)
3388 +{
3389 +       struct list_head *entry;
3390 +       unsigned short new_minor = (list_entry(new, struct lcd_struct, lcd_list))->par->minor;
3391 +
3392 +       list_for_each(entry, &lcd_drivers) {
3393 +               struct lcd_struct *p = list_entry(entry, struct lcd_struct, lcd_list);
3394 +
3395 +               if (p->par->minor > new_minor)
3396 +                       break;
3397 +       }
3398 +       list_add_tail(new, entry);
3399 +}
3400 +
3401 +/* Exported function */
3402 +int lcd_register_driver(struct lcd_driver *driver, struct lcd_parameters *par)
3403 +{
3404 +       int ret;
3405 +       struct lcd_struct *p;
3406 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
3407 +       struct device *lcd_device;
3408 +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
3409 +       struct class_device *lcd_class_device;
3410 +#endif
3411 +
3412 +       if (! driver || ! par || par->minor >= minors)
3413 +               return (-EINVAL);
3414 +       if (! driver->write_char || ! driver->init_port || ! driver->cleanup_port) {
3415 +               printk(KERN_ERR "LCD: missing functions\n");
3416 +               return (-EINVAL);
3417 +       }
3418 +
3419 +       down(&drivers_sem);
3420 +
3421 +       if (find_lcd_struct(par->minor)) {
3422 +               up(&drivers_sem);
3423 +               return (-EBUSY);
3424 +       }
3425 +
3426 +       if ((p = (struct lcd_struct *)kmalloc(sizeof(struct lcd_struct), GFP_KERNEL)) == NULL) {
3427 +               printk(KERN_ERR "LCD: memory allocation failed (kmalloc)\n");
3428 +               up(&drivers_sem);
3429 +               return (-ENOMEM);
3430 +       }
3431 +       memset(p, 0, sizeof(struct lcd_struct));
3432 +
3433 +       p->driver = driver;
3434 +       p->par = par;
3435 +       p->refcount = 0;
3436 +       SET_INIT_LEVEL(p, 0);
3437 +       SET_INPUT_STATE(p, NORMAL);
3438 +       set_bit(DECAWM, &p->struct_flags);
3439 +       set_bit(INC_CURS_POS, &p->struct_flags);
3440 +
3441 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
3442 +       lcd_device = device_create(lcd_linux_class, NULL, MKDEV(major, par->minor), "%s", par->name);
3443 +       if (IS_ERR(lcd_device)) {
3444 +               kfree(p);
3445 +               up(&drivers_sem);
3446 +               return (PTR_ERR(lcd_device));
3447 +       }
3448 +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 15)
3449 +       lcd_class_device = class_device_create(lcd_linux_class, NULL, MKDEV(major, par->minor), NULL, "%s", par->name);
3450 +       if (IS_ERR(lcd_class_device)) {
3451 +               kfree(p);
3452 +               up(&drivers_sem);
3453 +               return (PTR_ERR(lcd_class_device));
3454 +       }
3455 +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
3456 +       lcd_class_device = class_device_create(lcd_linux_class, MKDEV(major, par->minor), NULL, "%s", par->name);
3457 +       if (IS_ERR(lcd_class_device)) {
3458 +               kfree(p);
3459 +               up(&drivers_sem);
3460 +               return (PTR_ERR(lcd_class_device));
3461 +       }
3462 +#endif
3463 +
3464 +#ifdef USE_PROC
3465 +       if (lcd_proc_root && (driver->driver_proc_root = proc_mkdir(par->name, lcd_proc_root)) == NULL)
3466 +               printk(KERN_ERR "LCD: cannot create /proc/lcd/%s/\n", par->name);
3467 +#endif
3468 +
3469 +       if ((ret = init_driver(p))) {
3470 +#ifdef USE_PROC
3471 +               if (driver->driver_proc_root)
3472 +                       remove_proc_entry(p->par->name, lcd_proc_root);
3473 +#endif
3474 +               kfree(p);
3475 +               up(&drivers_sem);
3476 +               return (ret);
3477 +       }
3478 +
3479 +       init_MUTEX(&p->lcd_sem);
3480 +
3481 +       list_add_sorted(&p->lcd_list);
3482 +
3483 +       up(&drivers_sem);
3484 +
3485 +#ifdef MODULE
3486 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
3487 +       try_module_get(THIS_MODULE);
3488 +#else
3489 +       MOD_INC_USE_COUNT;
3490 +#endif
3491 +#endif
3492 +
3493 +       return (0);
3494 +}
3495 +EXPORT_SYMBOL(lcd_register_driver);
3496 +
3497 +/* Exported function */
3498 +int lcd_unregister_driver(struct lcd_driver *driver, struct lcd_parameters *par)
3499 +{
3500 +       int ret;
3501 +       struct lcd_struct *p;
3502 +
3503 +       if (! driver || ! par || par->minor >= minors)
3504 +               return (-EINVAL);
3505 +
3506 +       down(&drivers_sem);
3507 +
3508 +       if ((p = find_lcd_struct(par->minor)) == NULL || p->driver != driver) {
3509 +               printk(KERN_ERR "LCD: driver not found; lcd_unregister_driver failed\n");
3510 +               up(&drivers_sem);
3511 +               return (-ENODEV);
3512 +       }
3513 +
3514 +       down(&p->lcd_sem);
3515 +
3516 +       if (p->refcount) {
3517 +               printk(KERN_ERR "LCD: driver busy; lcd_unregister_driver failed\n");
3518 +               up(&p->lcd_sem);
3519 +               up(&drivers_sem);
3520 +               return (-EBUSY);
3521 +       }
3522 +
3523 +       if ((ret = cleanup_driver(p))) {
3524 +               up(&p->lcd_sem);
3525 +               up(&drivers_sem);
3526 +               return (ret);
3527 +       }
3528 +
3529 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
3530 +       device_destroy(lcd_linux_class, MKDEV(major, par->minor));
3531 +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
3532 +       class_device_destroy(lcd_linux_class, MKDEV(major, par->minor));
3533 +#endif
3534 +
3535 +#ifdef USE_PROC
3536 +       if (p->driver->driver_proc_root)
3537 +               remove_proc_entry(p->par->name, lcd_proc_root);
3538 +#endif
3539 +
3540 +       list_del(&p->lcd_list);
3541 +       kfree(p);
3542 +
3543 +       up(&drivers_sem);
3544 +
3545 +#ifdef MODULE
3546 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
3547 +       module_put(THIS_MODULE);
3548 +#else
3549 +       MOD_DEC_USE_COUNT;
3550 +#endif
3551 +#endif
3552 +
3553 +       return (0);
3554 +}
3555 +EXPORT_SYMBOL(lcd_unregister_driver);
3556 +
3557 +
3558 +
3559 +
3560 +
3561 +/************************
3562 + * Kernel I/O interface *
3563 + ************************/
3564 +/* Exported function */
3565 +int lcd_open(unsigned short minor, struct lcd_struct **pp)
3566 +{
3567 +       int ret;
3568 +       struct lcd_struct *p;
3569 +
3570 +       down(&drivers_sem);
3571 +
3572 +       if (minor >= minors || (*pp = p = find_lcd_struct(minor)) == NULL) {
3573 +               printk(KERN_ERR "LCD: lcd_open failed. Device not found.\n");
3574 +               up(&drivers_sem);
3575 +               return (-ENODEV);
3576 +       }
3577 +
3578 +       down(&p->lcd_sem);
3579 +       up(&drivers_sem);
3580 +
3581 +       ret = do_lcd_open(p);
3582 +
3583 +       up(&p->lcd_sem);
3584 +
3585 +       return (ret);
3586 +}
3587 +EXPORT_SYMBOL(lcd_open);
3588 +
3589 +/* Exported function */
3590 +int lcd_close(struct lcd_struct **pp)
3591 +{
3592 +       int ret;
3593 +       struct lcd_struct *p;
3594 +
3595 +       if (! pp || ! (p = *pp)) {
3596 +               printk(KERN_ERR "LCD: NULL pointer in lcd_close\n");
3597 +               return (-ENODEV);
3598 +       }
3599 +
3600 +       down(&p->lcd_sem);
3601 +
3602 +       if (! (ret = do_lcd_release(p)))
3603 +               *pp = NULL;
3604 +
3605 +       up(&p->lcd_sem);
3606 +
3607 +       return (ret);
3608 +}
3609 +EXPORT_SYMBOL(lcd_close);
3610 +
3611 +static inline loff_t offset_to_row_col(struct lcd_struct *p, loff_t offset)
3612 +{
3613 +       unsigned long _offset = offset;
3614 +       unsigned int vs_cols = p->par->vs_cols;
3615 +
3616 +       gotoxy(p, _offset%vs_cols, _offset/vs_cols);
3617 +
3618 +       return ((p->row*vs_cols)+p->col);
3619 +}
3620 +
3621 +/* Exported function */
3622 +ssize_t lcd_read(struct lcd_struct *p, void *bufp, size_t length, loff_t offset, unsigned int with_attr)
3623 +{
3624 +       ssize_t ret = 0;
3625 +
3626 +       if (! p) {
3627 +               printk(KERN_ERR "LCD: NULL pointer in lcd_read\n");
3628 +               return (-ENODEV);
3629 +       }
3630 +       if (! bufp)
3631 +               return (-EFAULT);
3632 +       if (offset < 0 || offset >= p->fb_size)
3633 +               return (-EINVAL);
3634 +
3635 +       if (length+offset > p->fb_size)
3636 +               length = p->fb_size-offset;
3637 +
3638 +       if (with_attr)
3639 +               set_bit(WITH_ATTR, &p->struct_flags);
3640 +
3641 +       offset_to_row_col(p, offset);
3642 +       ret = do_lcd_read(p, bufp, length);
3643 +
3644 +       if (with_attr)
3645 +               clear_bit(WITH_ATTR, &p->struct_flags);
3646 +
3647 +       return (ret);
3648 +}
3649 +EXPORT_SYMBOL(lcd_read);
3650 +
3651 +/* Exported function */
3652 +ssize_t lcd_write(struct lcd_struct *p, const void *bufp, size_t length, loff_t offset, unsigned int with_attr)
3653 +{
3654 +       ssize_t ret;
3655 +
3656 +       if (! p) {
3657 +               printk(KERN_ERR "LCD: NULL pointer in lcd_write\n");
3658 +               return (-ENODEV);
3659 +       }
3660 +       if (! bufp)
3661 +               return (-EFAULT);
3662 +       if (offset < 0 || offset >= p->fb_size)
3663 +               return (-EINVAL);
3664 +
3665 +       if (with_attr)
3666 +               set_bit(WITH_ATTR, &p->struct_flags);
3667 +
3668 +       offset_to_row_col(p, offset);
3669 +       ret = do_lcd_write(p, bufp, length);
3670 +
3671 +       if (with_attr)
3672 +               clear_bit(WITH_ATTR, &p->struct_flags);
3673 +
3674 +       return (ret);
3675 +}
3676 +EXPORT_SYMBOL(lcd_write);
3677 +
3678 +/* Exported function */
3679 +int lcd_ioctl(struct lcd_struct *p, unsigned int cmd, ...)
3680 +{
3681 +       int ret;
3682 +       unsigned long arg;
3683 +       va_list ap;
3684 +
3685 +       if (! p) {
3686 +               printk(KERN_ERR "LCD: NULL pointer in lcd_ioctl\n");
3687 +               return (-ENODEV);
3688 +       }
3689 +
3690 +       down(&p->lcd_sem);
3691 +       va_start(ap, cmd);
3692 +       arg = va_arg(ap, unsigned long);
3693 +       ret = do_lcd_ioctl(p, cmd, arg);
3694 +       va_end(ap);
3695 +       up(&p->lcd_sem);
3696 +
3697 +       return (ret);
3698 +}
3699 +EXPORT_SYMBOL(lcd_ioctl);
3700 +
3701 +
3702 +
3703 +
3704 +
3705 +/*******************
3706 + * File operations *
3707 + *******************/
3708 +static loff_t lcd_fops_llseek(struct file *filp, loff_t offset, int orig)
3709 +{
3710 +       struct lcd_struct *p;
3711 +
3712 +       if (! (p = filp->private_data))
3713 +               return (-ENODEV);
3714 +
3715 +       down(&p->lcd_sem);
3716 +
3717 +       switch (orig) {
3718 +       case 0:
3719 +               filp->f_pos = offset;
3720 +               break;
3721 +
3722 +       case 1:
3723 +               filp->f_pos += offset;
3724 +               break;
3725 +
3726 +       default:
3727 +               up(&p->lcd_sem);
3728 +               return (-EINVAL);     /* SEEK_END not supported */
3729 +       }
3730 +
3731 +       filp->f_pos = offset_to_row_col(p, filp->f_pos);
3732 +
3733 +       up(&p->lcd_sem);
3734 +
3735 +       return (filp->f_pos);
3736 +}
3737 +
3738 +static ssize_t lcd_fops_read(struct file *filp, char *buffer, size_t length, loff_t *offp)
3739 +{
3740 +       ssize_t ret = 0;
3741 +       char *bufp = buffer;
3742 +       struct lcd_struct *p;
3743 +
3744 +       if (! bufp)
3745 +               return (-EFAULT);
3746 +       if (! (p = filp->private_data))
3747 +               return (-ENODEV);
3748 +
3749 +       down(&p->lcd_sem);
3750 +
3751 +       if (*offp < 0 || *offp >= p->fb_size) {
3752 +               up(&p->lcd_sem);
3753 +               return (-EINVAL);
3754 +       }
3755 +
3756 +       if (length+(*offp) > p->fb_size)
3757 +               length = p->fb_size-(*offp);
3758 +
3759 +       while (length) {
3760 +               ret = (length > FLIP_BUF_SIZE ? FLIP_BUF_SIZE : length);
3761 +               if ((ret = do_lcd_read(p, p->flip_buf, ret)) < 0)
3762 +                       break;
3763 +               *offp = (p->row*p->par->vs_cols)+p->col;
3764 +               if (copy_to_user(bufp, p->flip_buf, ret)) {
3765 +                       ret = -EFAULT;
3766 +                       break;
3767 +               }
3768 +               length -= ret;
3769 +               bufp += ret;
3770 +               ret = bufp-buffer;
3771 +               if (length)
3772 +                       schedule();
3773 +       }
3774 +
3775 +       up(&p->lcd_sem);
3776 +
3777 +       return (ret);
3778 +}
3779 +
3780 +static ssize_t lcd_fops_write(struct file *filp, const char *buffer, size_t length, loff_t *offp)
3781 +{
3782 +       ssize_t ret = 0;
3783 +       const char *bufp = buffer;
3784 +       struct lcd_struct *p;
3785 +
3786 +       if (! bufp)
3787 +               return (-EFAULT);
3788 +       if (! (p = filp->private_data))
3789 +               return (-ENODEV);
3790 +
3791 +       down(&p->lcd_sem);
3792 +
3793 +       if (*offp < 0 || *offp >= p->fb_size) {
3794 +               up(&p->lcd_sem);
3795 +               return (-EINVAL);
3796 +       }
3797 +
3798 +       while (length) {
3799 +               ret = (length > FLIP_BUF_SIZE ? FLIP_BUF_SIZE : length);
3800 +               if (copy_from_user(p->flip_buf, bufp, ret)) {
3801 +                       ret = -EFAULT;
3802 +                       break;
3803 +               }
3804 +               if ((ret = do_lcd_write(p, p->flip_buf, ret)) < 0)
3805 +                       break;
3806 +               *offp = (p->row*p->par->vs_cols)+p->col;
3807 +               length -= ret;
3808 +               bufp += ret;
3809 +               ret = bufp-buffer;
3810 +               if (length)
3811 +                       schedule();
3812 +       }
3813 +
3814 +       up(&p->lcd_sem);
3815 +
3816 +       return (ret);
3817 +}
3818 +
3819 +static int lcd_fops_open(struct inode *inop, struct file *filp)
3820 +{
3821 +       unsigned short minor;
3822 +       int ret;
3823 +       struct lcd_struct *p;
3824 +
3825 +       down(&drivers_sem);
3826 +
3827 +       if ((minor = MINOR(inop->i_rdev)) >= minors || (filp->private_data = p = find_lcd_struct(minor)) == NULL) {
3828 +               up(&drivers_sem);
3829 +               return (-ENODEV);
3830 +       }
3831 +
3832 +       down(&p->lcd_sem);
3833 +       up(&drivers_sem);
3834 +
3835 +       ret = do_lcd_open(p);
3836 +
3837 +       up(&p->lcd_sem);
3838 +
3839 +       return (ret);
3840 +}
3841 +
3842 +static int lcd_fops_release(struct inode *inop, struct file *filp)
3843 +{
3844 +       struct lcd_struct *p;
3845 +       int ret;
3846 +
3847 +       if (! (p = filp->private_data))
3848 +               return (-ENODEV);
3849 +
3850 +       down(&p->lcd_sem);
3851 +
3852 +       if (! (ret = do_lcd_release(p)))
3853 +               filp->private_data = NULL;
3854 +
3855 +       up(&p->lcd_sem);
3856 +
3857 +       return (ret);
3858 +}
3859 +
3860 +static int lcd_fops_ioctl(struct inode *inop, struct file *filp, unsigned int cmd, unsigned long arg)
3861 +{
3862 +       struct lcd_struct *p;
3863 +       int ret;
3864 +
3865 +       if (! (p = filp->private_data))
3866 +               return (-ENODEV);
3867 +
3868 +       down(&p->lcd_sem);
3869 +
3870 +       set_bit(USER_SPACE, &p->struct_flags);
3871 +       ret = do_lcd_ioctl(p, cmd, arg);
3872 +       clear_bit(USER_SPACE, &p->struct_flags);
3873 +
3874 +       up(&p->lcd_sem);
3875 +
3876 +       return (ret);
3877 +}
3878 +
3879 +static struct file_operations lcd_linux_fops = {
3880 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
3881 +       .owner          = THIS_MODULE,
3882 +#endif
3883 +       .llseek         = lcd_fops_llseek,
3884 +       .read           = lcd_fops_read,
3885 +       .write          = lcd_fops_write,
3886 +       .open           = lcd_fops_open,
3887 +       .release        = lcd_fops_release,
3888 +       .ioctl          = lcd_fops_ioctl,
3889 +};
3890 +
3891 +
3892 +
3893 +
3894 +
3895 +/********************************
3896 + * Init/Cleanup driver routines *
3897 + ********************************/
3898 +static int do_init_driver(struct lcd_struct *p)
3899 +{
3900 +       int ret, init_level;
3901 +       struct lcd_driver *driver = p->driver;
3902 +       struct lcd_parameters *par = p->par;
3903 +       unsigned int frame_rows = par->cntr_rows*par->num_cntr;
3904 +       unsigned int frame_cols = par->cntr_cols;
3905 +
3906 +       switch ((init_level = INIT_LEVEL(p))) {
3907 +       case 0:
3908 +               if (frame_rows == 0 || frame_cols == 0 || ! par->name) {
3909 +                       printk(KERN_ERR "LCD: wrong lcd parameters\n");
3910 +                       return (-EINVAL);
3911 +               }
3912 +               if (driver->validate_driver) {
3913 +                       if ((ret = driver->validate_driver()) < 0) {
3914 +                               printk(KERN_ERR "LCD: validate_driver failed\n");
3915 +                               return (-EINVAL);
3916 +                       } else if (ret > 0) {
3917 +                               set_bit(CAN_DO_COLOR, &p->struct_flags);
3918 +                               p->defcolor = 0x07;
3919 +                               p->ulcolor = 0x0f;
3920 +                               p->halfcolor = 0x08;
3921 +                       }
3922 +               }
3923 +               default_attr(p);
3924 +               update_attr(p);
3925 +               p->frame_size = frame_rows*frame_cols;
3926 +               if (par->vs_rows < frame_rows)
3927 +                       par->vs_rows = frame_rows;
3928 +               if (par->vs_cols < frame_cols)
3929 +                       par->vs_cols = frame_cols;
3930 +               p->fb_size = par->vs_rows*par->vs_cols;
3931 +
3932 +               ret = sizeof(short)*p->fb_size;
3933 +               ret += sizeof(short)*p->frame_size;
3934 +               ret += FLIP_BUF_SIZE;
3935 +               ret += (p->driver->charmap ? 256 : 512);
3936 +               ret += par->cgram_chars*par->cgram_bytes;
3937 +               if ((p->fb = (unsigned short *)vmalloc(ret)) == NULL) {
3938 +                       printk(KERN_ERR "LCD: memory allocation failed (vmalloc)\n");
3939 +                       return (-ENOMEM);
3940 +               }
3941 +               __memset_short(p->fb, p->erase_char, p->fb_size+p->frame_size);
3942 +
3943 +               p->display = p->fb+p->fb_size;
3944 +               p->flip_buf = (unsigned char *)(p->display+p->frame_size);
3945 +
3946 +               if (! p->driver->charmap) {
3947 +                       set_bit(NULL_CHARMAP, &p->struct_flags);
3948 +                       p->driver->charmap = p->flip_buf+FLIP_BUF_SIZE;
3949 +                       for (ret = 0; ret < 256; ++ret)
3950 +                               p->driver->charmap[ret] = ret;
3951 +                       p->s_charmap = p->driver->charmap+256;
3952 +               } else
3953 +                       p->s_charmap = p->flip_buf+FLIP_BUF_SIZE;
3954 +               memset(p->s_charmap, 0, 256);
3955 +
3956 +               if (par->cgram_chars*par->cgram_bytes) {
3957 +                       p->cgram_buffer = p->s_charmap+256;
3958 +                       memset(p->cgram_buffer, 0, par->cgram_chars*par->cgram_bytes);
3959 +               } else
3960 +                       p->cgram_buffer = NULL;
3961 +
3962 +               p->frame_base = 0;
3963 +               p->row = p->col = 0;
3964 +               p->top = 0;
3965 +               p->bot = par->vs_rows;
3966 +               SET_INIT_LEVEL(p, ++init_level);
3967 +
3968 +       case 1:
3969 +               /* Initialize the communication port */
3970 +               if ((ret = driver->init_port())) {
3971 +                       printk(KERN_ERR "LCD: failure while initializing the communication port\n");
3972 +                       return (ret);
3973 +               }
3974 +               SET_INIT_LEVEL(p, ++init_level);
3975 +
3976 +       case 2:
3977 +               /* Initialize LCD display */
3978 +               if (driver->init_display && (ret = driver->init_display())) {
3979 +                       printk(KERN_ERR "LCD: failure while initializing the display\n");
3980 +                       return (ret);
3981 +               }
3982 +
3983 +#ifdef USE_PROC
3984 +               /* Create entries in /proc/lcd/"driver" */
3985 +               if (driver->driver_proc_root)
3986 +                       create_driver_proc_entries(p);
3987 +#endif
3988 +               SET_INIT_LEVEL(p, ++init_level);
3989 +       }
3990 +
3991 +       return (0);
3992 +}
3993 +
3994 +static int do_cleanup_driver(struct lcd_struct *p)
3995 +{
3996 +       int ret, init_level;
3997 +       struct lcd_driver *driver = p->driver;
3998 +
3999 +       switch ((init_level = INIT_LEVEL(p))) {
4000 +       case 3:
4001 +#ifdef USE_PROC
4002 +               if (driver->driver_proc_root)
4003 +                       remove_driver_proc_entries(p);
4004 +#endif
4005 +               if (driver->cleanup_display && (ret = driver->cleanup_display())) {
4006 +                       printk(KERN_ERR "LCD: failure while cleaning the display\n");
4007 +                       return (ret);
4008 +               }
4009 +               SET_INIT_LEVEL(p, --init_level);
4010 +
4011 +       case 2:
4012 +               if ((ret = driver->cleanup_port())) {
4013 +                       printk(KERN_ERR "LCD: failure while cleaning the communication port\n");
4014 +                       return (ret);
4015 +               }
4016 +               SET_INIT_LEVEL(p, --init_level);
4017 +
4018 +       case 1:
4019 +               if (test_bit(NULL_CHARMAP, &p->struct_flags)) {
4020 +                       p->driver->charmap = NULL;
4021 +                       clear_bit(NULL_CHARMAP, &p->struct_flags);
4022 +               }
4023 +               vfree(p->fb);
4024 +               p->fb = NULL;
4025 +               SET_INIT_LEVEL(p, --init_level);
4026 +       }
4027 +
4028 +       return (0);
4029 +}
4030 +
4031 +static int init_driver(struct lcd_struct *p)
4032 +{
4033 +       int ret;
4034 +
4035 +       if ((ret = do_init_driver(p))) {
4036 +               do_cleanup_driver(p);
4037 +               printk(KERN_ERR "LCD: init_driver failed\n");
4038 +       }
4039 +
4040 +       return (ret);
4041 +}
4042 +
4043 +static int cleanup_driver(struct lcd_struct *p)
4044 +{
4045 +       int ret;
4046 +
4047 +       if ((ret = do_cleanup_driver(p))) {
4048 +               do_init_driver(p);
4049 +               printk(KERN_ERR "LCD: cleanup_driver failed\n");
4050 +       }
4051 +
4052 +       return (ret);
4053 +}
4054 +
4055 +
4056 +
4057 +
4058 +
4059 +/********************************
4060 + * Init/Cleanup module routines *
4061 + ********************************/
4062 +static int __init lcd_linux_init_module(void)
4063 +{
4064 +       int ret;
4065 +
4066 +       if (! minors || minors > 256)
4067 +               minors = LCD_MINORS;
4068 +
4069 +       init_MUTEX(&drivers_sem);
4070 +
4071 +       if ((ret = register_chrdev(major, LCD_LINUX_STRING, &lcd_linux_fops)) < 0) {
4072 +               printk(KERN_ERR "LCD: register_chrdev failed\n");
4073 +               return (ret);
4074 +       }
4075 +       if (major == 0)
4076 +               major = ret;
4077 +
4078 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
4079 +       if (IS_ERR((lcd_linux_class = class_create(THIS_MODULE, "lcd")))) {
4080 +               ret = PTR_ERR(lcd_linux_class);
4081 +               unregister_chrdev(major, LCD_LINUX_STRING);
4082 +               return (ret);
4083 +       }
4084 +#endif
4085 +
4086 +#ifdef USE_PROC
4087 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
4088 +       if ((lcd_proc_root = proc_mkdir("lcd", NULL)) == NULL)
4089 +#else
4090 +       if ((lcd_proc_root = proc_mkdir("lcd", &proc_root)) == NULL)
4091 +#endif
4092 +               printk(KERN_ERR "LCD: cannot create /proc/lcd/\n");
4093 +       else if (create_proc_read_entry("drivers", 0, lcd_proc_root, proc_registered_drivers, NULL) == NULL)
4094 +               printk(KERN_ERR "LCD: cannot create /proc/lcd/drivers\n");
4095 +#endif
4096 +
4097 +       printk(KERN_INFO "LCD: --> LCD-Linux " LCD_LINUX_VERSION " <--\n");
4098 +       printk(KERN_INFO "LCD: --> Mattia Jona-Lasinio <mjona@users.sourceforge.net> <--\n" );
4099 +
4100 +
4101 +       return (0);
4102 +}
4103 +
4104 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
4105 +static void __exit lcd_linux_cleanup_module(void)
4106 +#else
4107 +/* __exit is not defined in 2.2.x kernels */
4108 +static void lcd_linux_cleanup_module(void)
4109 +#endif
4110 +{
4111 +#ifdef USE_PROC
4112 +       if (lcd_proc_root) {
4113 +               remove_proc_entry("drivers", lcd_proc_root);
4114 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
4115 +               remove_proc_entry("lcd", NULL);
4116 +#else
4117 +               remove_proc_entry("lcd", &proc_root);
4118 +#endif
4119 +       }
4120 +#endif
4121 +
4122 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
4123 +       class_destroy(lcd_linux_class);
4124 +#endif
4125 +
4126 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
4127 +       unregister_chrdev(major, LCD_LINUX_STRING);
4128 +#else
4129 +       if (unregister_chrdev(major, LCD_LINUX_STRING))
4130 +               printk(KERN_ERR "LCD: unregister_chrdev failed\n");
4131 +#endif
4132 +}
4133 +
4134 +module_init(lcd_linux_init_module)
4135 +module_exit(lcd_linux_cleanup_module)
4136 Index: linux-2.6.30.9/include/linux/hd44780.h
4137 ===================================================================
4138 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
4139 +++ linux-2.6.30.9/include/linux/hd44780.h      2009-11-24 02:01:42.000000000 +0100
4140 @@ -0,0 +1,46 @@
4141 +/* hd44780.h
4142 + *
4143 + *
4144 + * LCD-Linux:
4145 + * Driver for HD44780 compatible displays connected to the parallel port.
4146 + *
4147 + * HD44780 header file.
4148 + *
4149 + * Copyright (C) 2004 - 2007  Mattia Jona-Lasinio (mjona@users.sourceforge.net)
4150 + *
4151 + *  This program is free software; you can redistribute it and/or modify
4152 + *  it under the terms of the GNU General Public License as published by
4153 + *  the Free Software Foundation; either version 2 of the License, or
4154 + *  (at your option) any later version.
4155 + *
4156 + *  This program is distributed in the hope that it will be useful,
4157 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
4158 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4159 + *  GNU General Public License for more details.
4160 + *
4161 + *  You should have received a copy of the GNU General Public License
4162 + *  along with this program; if not, write to the Free Software
4163 + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
4164 + *
4165 + */
4166 +
4167 +#ifndef HD44780_H
4168 +#define HD44780_H
4169 +
4170 +#include <linux/lcd-linux.h>
4171 +
4172 +#define HD44780_VERSION                LCD_LINUX_VERSION       /* Version number */
4173 +#define HD44780_STRING         "hd44780"
4174 +
4175 +#define HD44780_MINOR          0       /* Minor number for the hd44780 driver */
4176 +
4177 +
4178 +/* flags */
4179 +#define HD44780_CHECK_BF       0x00000001      /* Do busy flag checking */
4180 +#define HD44780_4BITS_BUS      0x00000002      /* Set the bus length to 4 bits */
4181 +#define HD44780_5X10_FONT      0x00000004      /* Use 5x10 dots fonts */
4182 +
4183 +/* IOCTLs */
4184 +#define HD44780_READ_AC                _IOR(LCD_MAJOR, 0x00, unsigned char *)
4185 +
4186 +#endif /* HD44780 included */
4187 Index: linux-2.6.30.9/include/linux/lcd-linux.h
4188 ===================================================================
4189 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
4190 +++ linux-2.6.30.9/include/linux/lcd-linux.h    2009-11-24 02:01:42.000000000 +0100
4191 @@ -0,0 +1,151 @@
4192 +/* lcd-linux.h
4193 + *
4194 + *
4195 + * Software layer to drive LCD displays under Linux.
4196 + *
4197 + * External interface header file.
4198 + *
4199 + * Copyright (C) 2005 - 2007  Mattia Jona-Lasinio (mjona@users.sourceforge.net)
4200 + *
4201 + *  This program is free software; you can redistribute it and/or modify
4202 + *  it under the terms of the GNU General Public License as published by
4203 + *  the Free Software Foundation; either version 2 of the License, or
4204 + *  (at your option) any later version.
4205 + *
4206 + *  This program is distributed in the hope that it will be useful,
4207 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
4208 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4209 + *  GNU General Public License for more details.
4210 + *
4211 + *  You should have received a copy of the GNU General Public License
4212 + *  along with this program; if not, write to the Free Software
4213 + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
4214 + *
4215 + */
4216 +
4217 +#ifndef LCD_LINUX_H
4218 +#define LCD_LINUX_H
4219 +
4220 +#ifndef LCD_LINUX_MAIN
4221 +#warning
4222 +#warning LCD-Linux is still in development stage and
4223 +#warning aims at speed and optimization. For these
4224 +#warning reasons there is no guarantee of backward
4225 +#warning compatibility between different LCD-Linux
4226 +#warning versions. Be sure to use the lcd-linux.h
4227 +#warning file of the same version as the module.
4228 +#warning "http://lcd-linux.sourceforge.net/"
4229 +#warning
4230 +#endif
4231 +
4232 +#define LCD_LINUX_VERSION      "0.13.6"        /* Version number */
4233 +#define LCD_LINUX_STRING       "lcd"
4234 +
4235 +#define LCD_MAJOR              120     /* Major number for this device
4236 +                                        * Set this to 0 for dynamic allocation
4237 +                                        */
4238 +#define LCD_MINORS             8       /* Minors allocated for LCD-Linux*/
4239 +
4240 +#include <linux/types.h>
4241 +
4242 +#define        str(s) #s
4243 +#define        string(s) str(s)
4244 +
4245 +struct lcd_parameters {
4246 +       const char      *name;          /* Driver's name */
4247 +       unsigned long   flags;          /* Flags (see documentation) */
4248 +       unsigned short  minor;          /* Minor number of the char device */
4249 +       unsigned short  tabstop;        /* Tab character length */
4250 +       unsigned short  num_cntr;       /* Controllers to drive */
4251 +       unsigned short  cntr_rows;      /* Rows per controller */
4252 +       unsigned short  cntr_cols;      /* Display columns */
4253 +       unsigned short  vs_rows;        /* Virtual screen rows */
4254 +       unsigned short  vs_cols;        /* Virtual screen columns */
4255 +       unsigned short  cgram_chars;    /* Number of user definable characters */
4256 +       unsigned short  cgram_bytes;    /* Number of bytes required to define a
4257 +                                        * user definable character */
4258 +       unsigned char   cgram_char0;    /* Ascii of first user definable character */
4259 +};
4260 +
4261 +/* IOCTLs */
4262 +#include <asm/ioctl.h>
4263 +#define LCDL_SET_PARAM         _IOW(LCD_MAJOR, 0x80, struct lcd_parameters *)
4264 +#define LCDL_GET_PARAM         _IOR(LCD_MAJOR, 0x81, struct lcd_parameters *)
4265 +#define LCDL_CHARSUBST         _IOW(LCD_MAJOR, 0x82, unsigned char *)
4266 +#define LCDL_RAW_MODE          _IOW(LCD_MAJOR, 0x83, unsigned int)
4267 +#define LCDL_RESET_CHARMAP     _IO(LCD_MAJOR, 0x84)
4268 +#define LCDL_SAVE_CHARMAP      _IO(LCD_MAJOR, 0x85)
4269 +#define LCDL_RESTORE_CHARMAP   _IO(LCD_MAJOR, 0x86)
4270 +#define LCDL_SWAP_CHARMAP      _IO(LCD_MAJOR, 0x87)
4271 +#define LCDL_CLEAR_DISP                _IO(LCD_MAJOR, 0x88)
4272 +#define LCDL_SET_CGRAM_CHAR    _IOW(LCD_MAJOR, 0x89, unsigned char *)
4273 +#define LCDL_GET_CGRAM_CHAR    _IOR(LCD_MAJOR, 0x8a, unsigned char *)
4274 +#define LCDL_SET_CHARMAP       _IOW(LCD_MAJOR, 0x8b, unsigned char *)
4275 +#define LCDL_GET_CHARMAP       _IOR(LCD_MAJOR, 0x8c, unsigned char *)
4276 +#define LCDL_MEMSET            _IOW(LCD_MAJOR, 0x8d, unsigned int *)
4277 +#define LCDL_MEMMOVE           _IOW(LCD_MAJOR, 0x8e, unsigned int *)
4278 +
4279 +
4280 +
4281 +#ifdef __KERNEL__ /* The rest is for kernel only */
4282 +
4283 +#include <linux/kernel.h>
4284 +#include <linux/module.h>
4285 +
4286 +
4287 +struct lcd_driver {
4288 +       void    (*read_char)(unsigned int offset, unsigned short *data);
4289 +       void    (*read_cgram_char)(unsigned char index, unsigned char *pixmap);
4290 +       void    (*write_char)(unsigned int offset, unsigned short data);
4291 +       void    (*write_cgram_char)(unsigned char index, unsigned char *pixmap);
4292 +       void    (*clear_display)(void);
4293 +       void    (*address_mode)(int mode);
4294 +       int     (*validate_driver)(void);
4295 +       int     (*init_display)(void);
4296 +       int     (*cleanup_display)(void);
4297 +       int     (*init_port)(void);
4298 +       int     (*cleanup_port)(void);
4299 +       int     (*handle_custom_char)(unsigned int data);
4300 +       int     (*handle_custom_ioctl)(unsigned int cmd, unsigned long arg, unsigned int arg_in_userspace);
4301 +
4302 +       /* The character map to be used */
4303 +       unsigned char *charmap;
4304 +
4305 +       /* The root where the driver can create its own proc files.
4306 +        * Will be filled by the lcd-linux layer.
4307 +        */
4308 +       struct proc_dir_entry *driver_proc_root;
4309 +
4310 +       /* Set this field to 'driver_module_init' or call lcd_driver_setup
4311 +        * just before registering the driver with lcd_register_driver.
4312 +        */
4313 +       struct module *driver_module;
4314 +};
4315 +
4316 +#ifdef MODULE
4317 +#define driver_module_init     THIS_MODULE
4318 +#else
4319 +#define driver_module_init     NULL
4320 +#endif
4321 +
4322 +/* Always call lcd_driver_setup just before registering the driver
4323 + * with lcd_register_driver.
4324 + */
4325 +static inline void lcd_driver_setup(struct lcd_driver *p)
4326 +{
4327 +       p->driver_module = driver_module_init;
4328 +}
4329 +
4330 +/* External interface */
4331 +struct lcd_struct;
4332 +int lcd_register_driver(struct lcd_driver *drv, struct lcd_parameters *par);
4333 +int lcd_unregister_driver(struct lcd_driver *drv, struct lcd_parameters *par);
4334 +int lcd_open(unsigned short minor, struct lcd_struct **lcd);
4335 +int lcd_close(struct lcd_struct **lcd);
4336 +int lcd_ioctl(struct lcd_struct *lcd, unsigned int cmd, ...);
4337 +ssize_t lcd_write(struct lcd_struct *lcd, const void *buffer, size_t length, loff_t offset, unsigned int);
4338 +ssize_t lcd_read(struct lcd_struct *lcd, void *buffer, size_t length, loff_t offset, unsigned int);
4339 +
4340 +#endif /* __KERNEL__ */
4341 +
4342 +#endif /* External interface included */