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
7 source "drivers/accessibility/Kconfig"
9 +source "drivers/lcd-linux/Kconfig"
11 source "drivers/leds/Kconfig"
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
19 obj-$(CONFIG_SSB) += ssb/
20 obj-$(CONFIG_VIRTIO) += virtio/
21 obj-$(CONFIG_STAGING) += staging/
22 +obj-$(CONFIG_LCD_LINUX) += lcd-linux/
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
29 +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
30 + mainmenu_option next_comment
31 + comment 'LCD support'
33 + tristate 'LCD-Linux layer' CONFIG_LCD_LINUX
34 + dep_tristate ' HD44780 controller' CONFIG_LCD_HD44780 $CONFIG_LCD_LINUX
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
42 +menu "LCD-Linux support"
43 + depends on EXPERIMENTAL
46 + tristate "LCD-Linux layer"
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/
57 + To compile LCD-Linux as a module, choose M here:
58 + the module will be called lcd-linux.
61 + tristate "HD44780 controller"
62 + depends on LCD_LINUX && MACH_SIM_ONE
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.
69 + To compile this driver as a module, choose M here:
70 + the module will be called hd44780.
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
82 +# Standard Makefile to statically compile LCD-Linux into the kernel
85 +obj-$(CONFIG_LCD_LINUX) += lcd-linux.o
86 +obj-$(CONFIG_LCD_HD44780) += hd44780.o
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
97 + * Default user defined characters for lcdmod.
99 + * Copyright (C) by Michael McLellan (mikey@cs.auckland.ac.nz)
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.
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.
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
118 +static void init_charmap(void)
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
139 + * Character mapping for HD44780 devices by Mark Haemmerling <mail@markh.de>.
141 + * Translates ISO 8859-1 to HD44780 charset.
142 + * HD44780 charset reference: http://markh.de/hd44780-charset.png
144 + * Initial table taken from lcd.o Linux kernel driver by
145 + * Nils Faerber <nilsf@users.sourceforge.net>. Thanks!
147 + * This file is released under the GNU General Public License. Refer to the
148 + * COPYING file distributed with this package.
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
155 + * Alternative mappings:
156 + * - #112 ("p") -> #240 (large "p"), orig. mapped -> #112
157 + * - #113 ("q") -> #241 (large "q"), orig. mapped -> #113
159 + * HD44780 misses backslash
163 +static unsigned char charmap[] = {
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,
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,
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,
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,
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,
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,
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,
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
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
224 + * Driver for HD44780 compatible displays connected to the parallel port.
226 + * HD44780 commands.
228 + * Copyright (C) 2004 - 2007 Mattia Jona-Lasinio (mjona@users.sourceforge.net)
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.
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.
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
246 +#ifndef HD44780_COMMANDS_H
247 +#define HD44780_COMMANDS_H
249 +/*** HD44780 Command Set ***/
252 +#define CLR_DISP 0x01 /* Clear entire display; cursor at row 0, column 0 */
255 +#define RET_HOME 0x02 /* Cursor at row 0, column 0; display content doesn't change */
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 */
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 */
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 */
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 */
289 +/* Set CGRAM Address */
290 +#define CGRAM_IO 0x40 /* Base CGRAM address */
292 +/* Set DDRAM Address */
293 +#define DDRAM_IO 0x80 /* Base DDRAM address */
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
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.
308 + * Copyright (C) 2005 - 2007 Mattia Jona-Lasinio (mjona@users.sourceforge.net)
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.
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.
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
327 +/* Setup the default user defined characters in CGRAM */
328 +#include "cgram/default.h"
330 +/* Don't modify the default timing constants
331 + * unless you know what you are doing.
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) */
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) */
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 */
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) */
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)
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 */
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)
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
384 + * Driver for HD44780 compatible displays connected to the parallel port.
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)
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.
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.
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
406 +#include <linux/autoconf.h>
409 +#ifdef CONFIG_PROC_FS
415 +#include <linux/bitops.h>
416 +#include <linux/kernel.h>
417 +#include <linux/module.h>
419 +#include <linux/delay.h>
420 +#include <linux/fs.h>
422 +#include <asm/uaccess.h>
423 +#include <linux/init.h>
426 +#include <linux/ioport.h>
427 +#include <asm/gpio.h>
430 +#include <linux/proc_fs.h>
433 +#define LCD_LINUX_MAIN
434 +#include <linux/hd44780.h>
436 +#include "charmap.h"
437 +#include "commands.h"
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);
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);
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 *);
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 *);
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);
466 +/* Proc operations */
468 +static void create_proc_entries(void);
469 +static void remove_proc_entries(void);
472 +/* hd44780 access */
473 +#define ACCESS_TO_READ 0
474 +#define ACCESS_TO_WRITE 1
475 +#define ACCESS_TO_DATA 2
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
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)
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 */
501 +static struct lcd_parameters par = {
502 + .name = HD44780_STRING,
503 + .minor = HD44780_MINOR,
504 + .flags = DFLT_FLAGS,
505 + .tabstop = DFLT_TABSTOP,
507 + .cntr_rows = DFLT_CNTR_ROWS,
508 + .cntr_cols = DFLT_CNTR_COLS,
509 + .vs_rows = DFLT_VS_ROWS,
510 + .vs_cols = DFLT_VS_COLS,
515 +/* End of globals */
518 +#include <linux/device.h>
519 +MODULE_ALIAS_CHARDEV(LCD_MAJOR, HD44780_MINOR);
520 +#include <linux/kmod.h>
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;
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");
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);
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) ")");
553 + * Parse boot command line
555 + * hd44780=cntr_rows,cntr_cols,vs_rows,vs_cols,flags,minor,tabstop
557 +static int __init hd44780_boot_init(char *cmdline)
559 + char *str = cmdline;
561 + unsigned short *args[] = {
572 + while (*cmdline && idx < (sizeof(args)/sizeof(unsigned short *))) {
577 + if (strlen(cmdline))
578 + *args[idx] = simple_strtoul(cmdline, NULL, 0);
591 +__setup("hd44780=", hd44780_boot_init);
594 +/* Macros for iterator handling */
595 +static inline unsigned int iterator_inc_(unsigned int iterator, const unsigned int module)
597 + return ((++iterator)%module);
600 +static inline unsigned int iterator_dec_(unsigned int iterator, const unsigned int module)
602 + return (iterator ? --iterator : module-1);
605 +#define iterator_inc(iterator, module) (iterator = iterator_inc_(iterator, module))
606 +#define iterator_dec(iterator, module) (iterator = iterator_dec_(iterator, module))
608 +static inline void set_lines(unsigned char bitmask)
610 + gpio_set_value(SIMONE_LCD_EN, 0); /* Disable */
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 */
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 */
627 + if(bitmask & ACCESS_TO_DATA )
628 + gpio_set_value(SIMONE_LCD_RS, 1); /* Data */
630 + gpio_set_value(SIMONE_LCD_RS, 0); /* Cmds*/
632 + if(test_bit(BACKLIGHT, &hd44780_flags))
633 + gpio_set_value(SIMONE_LCD_BCKLIGHT, 1);
635 + gpio_set_value(SIMONE_LCD_BCKLIGHT, 0);
639 +/* Low level read from the display */
640 +static inline unsigned char __read_display(unsigned char bitmask)
642 + unsigned char byte;
644 + set_lines (bitmask);
646 + ndelay(T_AS); /* Address set-up time */
647 + gpio_set_value(SIMONE_LCD_EN, 1); /* Enable */
648 + ndelay(T_EH);/* Enable high time */
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);
655 + gpio_set_value(SIMONE_LCD_EN, 0); /* Disable */
657 + ndelay(T_EL); /* Enable low time */
664 +/* Low level write to the display */
665 +static inline void __write_display(unsigned char data, unsigned char bitmask)
667 + set_lines(bitmask);
670 + gpio_set_value(SIMONE_LCD_DATA0, 1);
672 + gpio_set_value(SIMONE_LCD_DATA0, 0);
675 + gpio_set_value(SIMONE_LCD_DATA1, 1);
677 + gpio_set_value(SIMONE_LCD_DATA1, 0);
680 + gpio_set_value(SIMONE_LCD_DATA2, 1);
682 + gpio_set_value(SIMONE_LCD_DATA2, 0);
685 + gpio_set_value(SIMONE_LCD_DATA3, 1);
687 + gpio_set_value(SIMONE_LCD_DATA3, 0);
689 + ndelay(T_AS); /* Address set-up time */
690 + gpio_set_value(SIMONE_LCD_EN, 1);
691 + ndelay(T_EH); /* Enable high time */
693 + gpio_set_value(SIMONE_LCD_EN, 0); /* Disable */
694 + ndelay(T_EL); /* Enable low time */
698 +/* Read data from the display (4 bit bus, check busy flag) */
699 +static void read_display (unsigned char *byte,unsigned char bitmask)
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));
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)
712 + __write_display(HIGH_NIBBLE_WRITE(byte),bitmask);
714 + __write_display(LOW_NIBBLE_WRITE(byte),bitmask);
718 +/* Read Address Counter AC from the display */
719 +static unsigned char read_ac(unsigned char bitmask)
721 + unsigned char byte;
723 + read_display(&byte, bitmask);
729 +/* Do busy-flag check */
730 +static void check_bf(unsigned char bitmask)
732 + unsigned int timeout = 20;
733 + static unsigned char do_check_bf = 5;
734 + gpio_set_value(SIMONE_LCD_EN, 0); /* Disable */
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);
741 + gpio_set_value(SIMONE_LCD_RD, 1); /* Read */
742 + gpio_set_value(SIMONE_LCD_RS, 0); /* Instru */
744 + ndelay(T_AS); /* Address set-up time */
745 + gpio_set_value(SIMONE_LCD_EN, 1); /* Enable */
746 + ndelay(T_EH);/* Enable high time */
750 + } while (gpio_get_value(SIMONE_LCD_DATA3) && --timeout);
753 + if (! --do_check_bf) {
754 + printk(KERN_NOTICE "hd44780 error: is the LCD connected?\n");
758 + gpio_set_value(SIMONE_LCD_EN, 0); /* Disable */
760 + ndelay(T_EL); /* Enable low time */
763 +/* Send commands to the display */
764 +static void write_command(unsigned char command)
766 + write_display(command, ACCESS_TO_WRITE);
768 + if (command <= 0x03)
772 +static inline void set_cursor(unsigned int offset)
774 + unsigned int disp_number = offset/disp_size;
775 + unsigned int local_offset = offset%disp_size;
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;
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;
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.
792 +static inline void mov_cursor(unsigned int disp_number)
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;
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;
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,
820 + .charmap = charmap,
823 +static void hd44780_read_char(unsigned int offset, unsigned short *data)
825 + unsigned int disp_number = offset/disp_size;
828 + set_cursor(offset);
829 + read_display(&tmp, ACCESS_TO_DATA);
831 + mov_cursor(disp_number);
834 +static void hd44780_read_cgram_char(unsigned char index, unsigned char *pixels)
838 + write_command(CGRAM_IO | (index << 3));
839 + set_bit(CGRAM_STATE+0, &hd44780_flags);
841 + for (i = 0; i < 8; ++i) {
842 + read_display(pixels+i, ACCESS_TO_DATA );
847 +static void hd44780_write_char(unsigned int offset, unsigned short data)
849 + unsigned int disp_number = offset/disp_size;
851 + set_cursor(offset);
852 + write_display(data & 0xff, ACCESS_TO_WRITE | ACCESS_TO_DATA );
853 + mov_cursor(disp_number);
856 +static void hd44780_write_cgram_char(unsigned char index, unsigned char *pixels)
860 + /* Move address pointer to index in CGRAM */
861 + write_command(CGRAM_IO | (index << 3));
863 + set_bit(CGRAM_STATE+0, &hd44780_flags);
865 + for (i = 0; i < 8; ++i) {
867 + write_display(pixels[i], ACCESS_TO_WRITE | ACCESS_TO_DATA );
871 +/* Increment/decrement address mode after a data read/write */
872 +static void hd44780_address_mode(int mode)
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);
883 +static void hd44780_clear_display(void)
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));
891 +static int hd44780_validate_driver(void)
893 + if (par.cntr_rows != 1 && par.cntr_rows != 2 && par.cntr_rows != 4)
894 + par.cntr_rows = DFLT_CNTR_ROWS;
896 + if (par.cntr_rows != 1)
897 + par.flags &= ~HD44780_5X10_FONT;
900 + if (! par.cntr_cols || par.cntr_cols > MAX_CNTR_COLS/par.cntr_rows)
901 + par.cntr_cols = MAX_CNTR_COLS/par.cntr_rows;
903 + disp_size = par.cntr_rows*par.cntr_cols;
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;
913 +/* Send init commands to the display */
914 +static void write_init_command(void)
916 + unsigned char command = 0x30;
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); */
931 +static int hd44780_init_display(void)
933 + if (par.flags & HD44780_CHECK_BF)
934 + set_bit(_CHECK_BF, &hd44780_flags);
936 + clear_bit(_CHECK_BF, &hd44780_flags);
938 + if (par.flags & HD44780_4BITS_BUS)
939 + set_bit(_4BITS_BUS, &hd44780_flags);
941 + clear_bit(_4BITS_BUS, &hd44780_flags);
943 + if (par.flags & HD44780_5X10_FONT)
944 + set_bit(_5X10_FONT, &hd44780_flags);
946 + clear_bit(_5X10_FONT, &hd44780_flags);
948 + write_init_command();
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);
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);
971 +static int hd44780_cleanup_display(void)
973 + hd44780_clear_display();
978 +static int hd44780_init_port(void)
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 */
989 +static int hd44780_cleanup_port(void)
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);
1003 +static void display_attr(unsigned char input)
1005 + unsigned char command;
1007 + switch (ESC_STATE) {
1008 + case 'a': /* Turn on/off the display cursor */
1010 + set_bit(SHOW_CURSOR, &hd44780_flags);
1011 + else if (input == '0')
1012 + clear_bit(SHOW_CURSOR, &hd44780_flags);
1014 + case 'b': /* Turn on/off the display cursor blinking */
1016 + set_bit(CURSOR_BLINK, &hd44780_flags);
1017 + else if (input == '0')
1018 + clear_bit(CURSOR_BLINK, &hd44780_flags);
1020 + case 'h': /* Turn on/off the display */
1022 + set_bit(DISPLAY_ON, &hd44780_flags);
1023 + else if (input == '0')
1024 + clear_bit(DISPLAY_ON, &hd44780_flags);
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);
1032 + if (ESC_STATE == 'h')
1033 + write_command(command);
1036 +static int hd44780_handle_custom_char(unsigned int _input)
1038 + unsigned char input = _input & 0xff;
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);
1047 + case 'l': /* Turn on/off the backlight */
1049 + set_bit(BACKLIGHT, &hd44780_flags);
1050 + else if (input == '0')
1051 + clear_bit(BACKLIGHT, &hd44780_flags);
1052 + read_ac(ACCESS_TO_READ);
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);
1064 + case 'd': /* Shift display cursor Right */
1065 + write_command(SHIFT_CURS | SHIFT_RIGHT);
1067 + case 'e': /* Shift display cursor Left */
1068 + write_command(SHIFT_CURS | SHIFT_LEFT);
1070 + case 'f': /* Shift display Right */
1071 + write_command(SHIFT_DISP | SHIFT_RIGHT);
1073 + case 'g': /* Shift display Left */
1074 + write_command(SHIFT_DISP | SHIFT_LEFT);
1081 +static int hd44780_handle_custom_ioctl(unsigned int num, unsigned long arg, unsigned int user_space)
1083 + unsigned char *buffer = (unsigned char *)arg;
1085 + if (num != HD44780_READ_AC)
1086 + return (-ENOIOCTLCMD);
1089 + put_user(read_ac(ACCESS_TO_READ), buffer);
1091 + buffer[0] = read_ac(ACCESS_TO_READ);
1097 +static int hd44780_proc_status(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
1099 + char *temp = buffer;
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"),
1118 + return (temp-buffer);
1121 +static int hd44780_proc_cgram(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
1123 + char *temp = buffer;
1126 + temp += sprintf(temp, "static void init_charmap(void)\n{\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"
1139 + for (i = 0; i < 8; ++i) {
1140 + unsigned char cgram_buffer[8];
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" : ", "));
1149 + return (temp-buffer);
1152 +static void create_proc_entries(void)
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);
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);
1167 + SET_PROC_LEVEL(++count);
1171 +static void remove_proc_entries(void)
1173 + switch (PROC_LEVEL) {
1175 + remove_proc_entry("cgram.h", hd44780.driver_proc_root);
1177 + remove_proc_entry("status", hd44780.driver_proc_root);
1179 + SET_PROC_LEVEL(0);
1183 +/* Initialization */
1184 +static int __init hd44780_init_module(void)
1190 + if ((ret = request_module("lcd-linux"))) {
1191 + if (ret != -ENOSYS) {
1192 + printk(KERN_ERR "hd44780: failure while loading module lcd-linux\n");
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");
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;
1209 + lcd_driver_setup(&hd44780);
1210 + if ((ret = lcd_register_driver(&hd44780, &par)))
1214 + if (hd44780.driver_proc_root)
1215 + create_proc_entries();
1218 + printk(KERN_INFO "HD44780 driver (LCD-Linux" HD44780_VERSION ")\n");
1219 + printk(KERN_INFO "Nuccio Raciti <raciti.nuccio@gmail.com>\n");
1227 +static void __exit hd44780_cleanup_module(void)
1230 + if (hd44780.driver_proc_root)
1231 + remove_proc_entries();
1234 + lcd_unregister_driver(&hd44780, &par);
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
1248 + * Software layer to drive LCD displays under Linux.
1250 + * Copyright (C) 2005 - 2007 Mattia Jona-Lasinio (mjona@users.sourceforge.net)
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.
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.
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
1268 +#include <linux/version.h>
1270 +#ifndef KERNEL_VERSION
1271 +#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
1274 +#ifndef LINUX_VERSION_CODE
1275 +#error - LINUX_VERSION_CODE undefined in 'linux/version.h'
1278 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
1279 +#include <linux/autoconf.h>
1281 +#include <linux/config.h>
1283 +#ifdef CONFIG_PROC_FS
1289 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
1290 +#include <linux/semaphore.h>
1292 +#include <asm/semaphore.h>
1294 +#include <linux/bitops.h>
1295 +#include <linux/kernel.h>
1296 +#include <linux/module.h>
1297 +#include <linux/sched.h>
1299 +#include <linux/fs.h>
1301 +#include <asm/uaccess.h>
1302 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
1303 +#include <linux/device.h>
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>
1312 +#include <linux/proc_fs.h>
1315 +#define LCD_LINUX_MAIN
1316 +#include <linux/lcd-linux.h>
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 *
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 */
1342 +/*** Color attributes ***/
1343 +#define FG_MASK 0x0f /* Foreground color */
1344 +#define BG_MASK 0xf0 /* Background color */
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
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)
1373 +#define NPAR 16 /* Max number of parameters in CSI escape sequence */
1374 +#define FLIP_BUF_SIZE (1 << 6) /* Flip buffer size (64 bytes) */
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 */
1384 + unsigned short *display; /* The display buffer */
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 */
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 */
1395 + unsigned int top; /* Top scroll row in virtual screen */
1396 + unsigned int bot; /* Bottom scroll row in virtual screen */
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 */
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 */
1414 + unsigned char *s_charmap; /* Saved character map for this driver */
1415 + unsigned char *flip_buf; /* High speed flip buffer */
1418 +/** Function prototypes **/
1420 +/* Init/Cleanup the driver */
1421 +static int init_driver(struct lcd_struct *);
1422 +static int cleanup_driver(struct lcd_struct *);
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 *);
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);
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);
1446 +/* Proc functions */
1448 +static void create_driver_proc_entries(struct lcd_struct *);
1449 +static void remove_driver_proc_entries(struct lcd_struct *);
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;
1461 +static struct proc_dir_entry *lcd_proc_root;
1463 +/* End of globals */
1466 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
1467 +#include <linux/device.h>
1468 +MODULE_ALIAS_CHARDEV_MAJOR(LCD_MAJOR);
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");
1475 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
1476 +module_param(minors, ushort, 0444);
1478 +MODULE_PARM(minors, "h");
1480 +MODULE_PARM_DESC(minors, "Minor numbers allocated for LCD-Linux (default: " string(LCD_MINORS) ")");
1484 + * Parse boot command line
1488 +static int __init lcd_linux_boot_init(char *cmdline)
1490 + unsigned short args;
1492 + if ((args = simple_strtoul(cmdline, NULL, 0)))
1498 +__setup("lcd=", lcd_linux_boot_init);
1499 +#endif /* MODULE */
1501 +/* Macros for iterator handling */
1502 +static inline unsigned int iterator_inc_(unsigned int iterator, const unsigned int module)
1504 + return ((++iterator)%module);
1507 +static inline unsigned int iterator_dec_(unsigned int iterator, const unsigned int module)
1509 + return (iterator ? --iterator : module-1);
1512 +#define iterator_inc(iterator, module) (iterator = iterator_inc_(iterator, module))
1513 +#define iterator_dec(iterator, module) (iterator = iterator_dec_(iterator, module))
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
1521 +/************************************
1522 + * Low level routines and utilities *
1523 + ************************************/
1525 + * Set whether the address counter should be incremented
1526 + * or decremented after a Read/Write
1528 +static void address_mode(struct lcd_struct *p, int mode)
1530 + struct lcd_driver *driver = p->driver;
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);
1543 +/* WARNING!! This function returns an int because if iterator is not
1544 + * within the visible area of the frame it returns -1
1546 +static inline int vs_to_frame_(struct lcd_struct *p, unsigned int iterator)
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;
1556 + if (row < frame_base_row || row >= frame_base_row+frame_rows)
1558 + if (col < frame_base_col || col >= frame_base_col+frame_cols)
1561 + return ((row-frame_base_row)*frame_cols+(col-frame_base_col));
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.
1567 +static unsigned int round_vs_(struct lcd_struct *p, unsigned int iterator)
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;
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);
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);
1587 + return ((row*vs_cols)+col);
1590 +#define round_vs(p, iterator) (iterator = round_vs_(p, iterator))
1593 + * Sync the frame area starting at offset s, ending at offset e with fb content.
1595 +static void redraw_screen(struct lcd_struct *p, unsigned int s, unsigned int e)
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;
1604 + if (s >= p->fb_size || e >= p->fb_size || e < s || e < p->frame_base)
1615 + p->row = s/vs_cols;
1616 + p->col = s%vs_cols;
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);
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;
1631 + write_data(p, p->fb[s++]);
1632 + if (test_bit(NEED_WRAP, &p->struct_flags)) {
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;
1645 + write_data(p, p->fb[s--]);
1646 + if (test_bit(NEED_WRAP, &p->struct_flags)) {
1651 + p->struct_flags = flags;
1653 + p->row = row; p->col = col;
1656 +static int make_cursor_visible(struct lcd_struct *p)
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;
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);
1674 + tmp = (tmp-(frame_base_col%tmp))%tmp;
1675 + if (frame_base_col+tmp <= vs_cols-frame_cols)
1676 + frame_base_col += tmp;
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;
1688 + tmp = frame_base_col%tmp;
1689 + if (frame_base_col >= tmp)
1690 + frame_base_col -= tmp;
1695 + frame_base = p->frame_base;
1696 + p->frame_base = (frame_base_row*vs_cols)+frame_base_col;
1698 + return (frame_base != p->frame_base);
1702 + * Move the visible screen area at user's wish
1704 +static void browse_screen(struct lcd_struct *p, unsigned char dir)
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;
1714 + case '1': /* Up */
1715 + if (! frame_base_row)
1719 + case '2': /* Down */
1720 + if (frame_base_row >= vs_rows-frame_rows)
1724 + case '3': /* Left */
1725 + if (! frame_base_col)
1729 + case '4': /* Right */
1730 + if (frame_base_col >= vs_cols-frame_cols)
1738 + p->frame_base = (frame_base_row*vs_cols)+frame_base_col;
1739 + redraw_screen(p, 0, p->fb_size-1);
1742 +static inline void __memset_short(unsigned short *buf, unsigned short c, unsigned int len)
1749 + * A memset implementation writing to LCD instead of memory locations.
1751 +static void lcd_memset(struct lcd_struct *p, unsigned int d, unsigned short c, unsigned int len)
1753 + unsigned int inc_set = test_bit(INC_CURS_POS, &p->struct_flags);
1755 + if (! len || d >= p->fb_size)
1758 + if (inc_set && d+len > p->fb_size)
1759 + len = p->fb_size-d;
1760 + else if (! inc_set && len > d+1)
1765 + __memset_short(p->fb+d, c, len);
1767 + if (make_cursor_visible(p))
1768 + redraw_screen(p, 0, p->fb_size-1);
1770 + redraw_screen(p, d, d+(len-1));
1773 +static inline void __memcpy_short(unsigned short *d, unsigned short *s, unsigned int len, int dir)
1784 + * A memmove implementation writing to LCD instead of memory locations.
1785 + * Copy is done in a non destructive way. Display regions may overlap.
1787 +static void lcd_memmove(struct lcd_struct *p, unsigned int d, unsigned int s, unsigned int len)
1789 + if (! len || d == s || d >= p->fb_size || s >= p->fb_size)
1793 + if (test_bit(INC_CURS_POS, &p->struct_flags)) {
1794 + if (s+len > p->fb_size)
1795 + len = p->fb_size-s;
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);
1806 + redraw_screen(p, d, d+(len-1));
1808 + if (test_bit(INC_CURS_POS, &p->struct_flags)) {
1809 + if (d+len > p->fb_size)
1810 + len = p->fb_size-d;
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);
1821 + redraw_screen(p, d-(len-1), d);
1825 +static void scrup(struct lcd_struct *p, unsigned int t, unsigned int b, unsigned int nr)
1827 + unsigned int vs_rows = p->par->vs_rows;
1828 + unsigned int vs_cols = p->par->vs_cols;
1829 + unsigned int d, s;
1833 + if (b > vs_rows || t >= b || nr < 1)
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);
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);
1846 +static void scrdown(struct lcd_struct *p, unsigned int t, unsigned int b, unsigned int nr)
1848 + unsigned int vs_rows = p->par->vs_rows;
1849 + unsigned int vs_cols = p->par->vs_cols;
1850 + unsigned int d, s;
1854 + if (b > vs_rows || t >= b || nr < 1)
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);
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);
1867 +static void lcd_insert_char(struct lcd_struct *p, unsigned int nr)
1869 + unsigned int vs_cols = p->par->vs_cols;
1870 + unsigned int pos = (p->row*vs_cols)+p->col;
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);
1876 + lcd_memmove(p, pos-nr, pos, p->col-(nr-1));
1877 + lcd_memset(p, pos, p->erase_char, nr);
1880 +static void lcd_delete_char(struct lcd_struct *p, unsigned int nr)
1882 + unsigned int vs_cols = p->par->vs_cols;
1883 + unsigned int pos = (p->row*vs_cols)+p->col;
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);
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);
1899 +/******************************************************************************
1900 + ************************* VT 102 Emulation *************************
1901 + ******************************************************************************/
1903 +/**********************
1904 + * Control characters *
1905 + **********************/
1906 +static void bs(struct lcd_struct *p)
1908 + clear_bit(NEED_WRAP, &p->struct_flags);
1909 + if (test_bit(INC_CURS_POS, &p->struct_flags)) {
1913 + if (p->col+1 < p->par->vs_cols)
1918 +static void cr(struct lcd_struct *p)
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);
1924 +static void lf(struct lcd_struct *p)
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)
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)
1942 +static void ri(struct lcd_struct *p)
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)
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)
1960 +static void ff(struct lcd_struct *p)
1962 + unsigned int vs_rows = p->par->vs_rows;
1963 + unsigned int vs_cols = p->par->vs_cols;
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);
1974 + lcd_memset(p, p->fb_size-1, p->erase_char, p->fb_size);
1976 + if (test_bit(INC_CURS_POS, &p->struct_flags))
1977 + p->row = p->col = 0;
1979 + p->row = vs_rows-1;
1980 + p->col = vs_cols-1;
1984 +static void tab(struct lcd_struct *p)
1986 + struct lcd_parameters *par = p->par;
1987 + unsigned int i, vs_cols = par->vs_cols;
1989 + clear_bit(NEED_WRAP, &p->struct_flags);
1991 + if (! par->tabstop)
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)
1999 + i = p->col%par->tabstop;
2000 + i = (i == 0 ? par->tabstop : i);
2007 + * Control character handler.
2009 +static void control_char(struct lcd_struct *p, unsigned char val)
2012 + case 0x08: /* BS: Back Space (^H) */
2013 + case 0x7f: /* DEL: Delete */
2017 + case 0x09: /* HT: Horizontal Tab (^I) */
2021 + case 0x0c: /* FF: Form Feed (^L) */
2025 + case 0x0a: /* LF: Line Feed (^J) */
2026 + case 0x0b: /* VT: Vertical Tab (^K) */
2028 + if (! test_bit(CRLF, &p->struct_flags))
2031 + case 0x0d: /* CR: Carriage Return (^M) */
2035 + case 0x16: /* SYN: Synchronous Idle (^V) */
2036 + SET_INPUT_STATE(p, SYN);
2039 + case 0x1b: /* ESC: Start of escape sequence */
2040 + SET_INPUT_STATE(p, ESC);
2043 + case 0x9b: /* CSI: Start of CSI escape sequence */
2044 + memset(p->csi_args, 0, sizeof(p->csi_args));
2046 + SET_INPUT_STATE(p, CSI);
2051 +static void gotoxy(struct lcd_struct *p, int new_col, int new_row)
2053 + unsigned int vs_rows = p->par->vs_rows;
2054 + unsigned int vs_cols = p->par->vs_cols;
2056 + clear_bit(NEED_WRAP, &p->struct_flags);
2059 + else if (new_row >= vs_rows)
2060 + p->row = vs_rows-1;
2066 + else if (new_col >= vs_cols)
2067 + p->col = vs_cols-1;
2071 + if (make_cursor_visible(p))
2072 + redraw_screen(p, 0, p->fb_size-1);
2076 +/******************************
2077 + * ECMA-48 CSI ESC- sequences *
2078 + ******************************/
2079 +static void csi_at(struct lcd_struct *p, unsigned int nr)
2081 + unsigned int vs_cols = p->par->vs_cols;
2083 + if (p->col+nr > vs_cols)
2084 + nr = vs_cols-p->col;
2087 + lcd_insert_char(p, nr);
2090 +static void csi_J(struct lcd_struct *p, unsigned int action)
2092 + unsigned int vs_cols = p->par->vs_cols;
2093 + unsigned int pos = (p->row*vs_cols)+p->col;
2095 + clear_bit(NEED_WRAP, &p->struct_flags);
2097 + case 0: /* From cursor to end of display */
2098 + lcd_memset(p, pos, p->erase_char, p->fb_size-pos);
2101 + case 1: /* From start of display to cursor */
2102 + lcd_memset(p, 0, p->erase_char, pos+1);
2105 + case 2: /* Whole display */
2106 + lcd_memset(p, 0, p->erase_char, p->fb_size);
2111 +static void csi_K(struct lcd_struct *p, unsigned int action)
2113 + unsigned int vs_cols = p->par->vs_cols;
2114 + unsigned int row_start = p->row*vs_cols;
2116 + clear_bit(NEED_WRAP, &p->struct_flags);
2118 + case 0: /* From cursor to end of line */
2119 + lcd_memset(p, row_start+p->col, p->erase_char, vs_cols-p->col);
2122 + case 1: /* From start of line to cursor */
2123 + lcd_memset(p, row_start, p->erase_char, p->col+1);
2126 + case 2: /* Whole line */
2127 + lcd_memset(p, row_start, p->erase_char, vs_cols);
2132 +static void csi_L(struct lcd_struct *p, unsigned int nr)
2134 + unsigned int vs_rows = p->par->vs_rows;
2135 + unsigned int vs_cols = p->par->vs_cols;
2137 + clear_bit(NEED_WRAP, &p->struct_flags);
2138 + if (p->row+nr > vs_rows)
2139 + nr = vs_rows-p->row;
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);
2146 +static void csi_M(struct lcd_struct *p, unsigned int nr)
2148 + unsigned int vs_rows = p->par->vs_rows;
2149 + unsigned int vs_cols = p->par->vs_cols;
2151 + clear_bit(NEED_WRAP, &p->struct_flags);
2152 + if (p->row+nr > vs_rows)
2153 + nr = vs_rows-p->row;
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);
2160 +static void csi_P(struct lcd_struct *p, unsigned int nr)
2162 + unsigned int vs_cols = p->par->vs_cols;
2164 + if (p->col+nr > vs_cols)
2165 + nr = vs_cols-p->col;
2168 + lcd_delete_char(p, nr);
2171 +static void csi_X(struct lcd_struct *p, unsigned int nr)
2173 + unsigned int vs_cols = p->par->vs_cols;
2175 + clear_bit(NEED_WRAP, &p->struct_flags);
2176 + if (p->col+nr > vs_cols)
2177 + nr = vs_cols-p->col;
2180 + lcd_memset(p, (p->row*vs_cols)+p->col, p->erase_char, nr);
2183 +static void csi_su(struct lcd_struct *p, unsigned char input)
2185 + unsigned int vs_cols = p->par->vs_cols;
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;
2195 + p->s_offset = (p->row*vs_cols)+p->col;
2196 + p->s_color = p->color;
2197 + p->s_attributes = p->attributes;
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)
2203 + unsigned char attr;
2205 + if (test_bit(CAN_DO_COLOR, &p->struct_flags)) {
2208 + attr = (attr & BG_MASK) | p->ulcolor;
2209 + else if (intensity == 0)
2210 + attr = (attr & BG_MASK) | p->halfcolor;
2212 + attr = (attr & 0x88) | ((attr & 0x70) >> 4) | ((attr & 0x07) << 4);
2215 + if (intensity == 2)
2219 + attr |= (underline ? ULINE : 0x00);
2220 + attr |= (reverse ? REVERSE : 0x00);
2221 + attr |= (blink ? BLINK : 0x00);
2227 +static void update_attr(struct lcd_struct *p)
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;
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) | ' ';
2239 +static void default_attr(struct lcd_struct *p)
2241 + p->attributes = 0x01;
2242 + p->color = p->defcolor;
2245 +static void lcd_invert_screen(struct lcd_struct *p, unsigned int offset, unsigned int len)
2247 + if (test_bit(CAN_DO_COLOR, &p->struct_flags))
2249 + p->fb[offset] = (p->fb[offset] & 0x88ff) | ((p->fb[offset] & 0x7000) >> 4) | ((p->fb[offset] & 0x0700) << 4);
2254 + p->fb[offset] ^= 0x0800;
2259 +static void csi_m(struct lcd_struct *p, unsigned int n)
2263 + for (i = 0; i <= n; ++i)
2264 + switch ((arg = p->csi_args[i]))
2271 + p->attributes = (p->attributes & ~I_MASK) | 2;
2275 + p->attributes = (p->attributes & ~I_MASK) | 0;
2279 + p->attributes |= ULINE;
2283 + p->attributes |= BLINK;
2287 + p->attributes |= REVERSE;
2291 + p->attributes = (p->attributes & ~I_MASK) | 1;
2295 + p->attributes &= ~ULINE;
2299 + p->attributes &= ~BLINK;
2303 + p->attributes &= ~REVERSE;
2307 + p->attributes |= ULINE;
2308 + p->color = (p->color & BG_MASK) | (p->defcolor & FG_MASK);
2312 + p->attributes &= ~ULINE;
2313 + p->color = (p->color & BG_MASK) | (p->defcolor & FG_MASK);
2317 + p->color = (p->defcolor & BG_MASK) | (p->color & FG_MASK);
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);
2331 +static void csi_h(struct lcd_struct *p, unsigned char n)
2334 + case 4: /* Set insert mode */
2335 + set_bit(DECIM, &p->struct_flags);
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);
2343 + redraw_screen(p, 0, p->fb_size-1);
2347 + case 7: /* Set autowrap */
2348 + if (test_bit(QUES, &p->struct_flags))
2349 + set_bit(DECAWM, &p->struct_flags);
2352 + case 20: /* Set cr lf */
2353 + set_bit(CRLF, &p->struct_flags);
2358 +static void csi_l(struct lcd_struct *p, unsigned char n)
2361 + case 4: /* Reset insert mode */
2362 + clear_bit(DECIM, &p->struct_flags);
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);
2370 + redraw_screen(p, 0, p->fb_size-1);
2374 + case 7: /* Reset autowrap */
2375 + if (test_bit(QUES, &p->struct_flags))
2376 + clear_bit(DECAWM, &p->struct_flags);
2379 + case 20: /* Reset cr lf */
2380 + clear_bit(CRLF, &p->struct_flags);
2385 +static void csi_linux(struct lcd_struct *p)
2387 + switch (p->csi_args[0]) {
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)
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)
2405 + p->defcolor = p->color;
2412 +static void csi_r(struct lcd_struct *p, unsigned int top, unsigned int bot)
2414 + /* Minimum allowed region is 2 lines */
2423 + * ECMA-48 CSI ESC- sequence handler.
2425 +static void handle_csi(struct lcd_struct *p, unsigned char input)
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 == ';') {
2434 + } else if (input >= '0' && input <= '9') {
2435 + p->csi_args[p->index] = (p->csi_args[p->index]*10)+(input-'0');
2437 + SET_INPUT_STATE(p, NORMAL);
2438 + if (! test_bit(INC_CURS_POS, &p->struct_flags))
2441 + case 'h': /* DECSET sequences and mode switches */
2442 + csi_h(p, p->csi_args[0]);
2443 + clear_bit(QUES, &p->struct_flags);
2446 + case 'l': /* DECRST sequences and mode switches */
2447 + csi_l(p, p->csi_args[0]);
2448 + clear_bit(QUES, &p->struct_flags);
2451 + clear_bit(QUES, &p->struct_flags);
2453 + case '@': /* Insert # Blank character */
2454 + csi_at(p, p->csi_args[0]);
2457 + case 'G': case '`': /* Cursor to indicated column in current row */
2458 + if (p->csi_args[0])
2460 + gotoxy(p, p->csi_args[0], p->row);
2463 + case 'A': /* Cursor # rows Up */
2464 + if (! p->csi_args[0])
2466 + gotoxy(p, p->col, p->row-p->csi_args[0]);
2469 + case 'B': case 'e': /* Cursor # rows Down */
2470 + if (! p->csi_args[0])
2472 + gotoxy(p, p->col, p->row+p->csi_args[0]);
2475 + case 'C': case 'a': /* Cursor # columns Right */
2476 + if (! p->csi_args[0])
2478 + gotoxy(p, p->col+p->csi_args[0], p->row);
2481 + case 'D': /* Cursor # columns Left */
2482 + if (! p->csi_args[0])
2484 + gotoxy(p, p->col-p->csi_args[0], p->row);
2487 + case 'E': /* Cursor # rows Down, column 1 */
2488 + if (! p->csi_args[0])
2490 + gotoxy(p, 0, p->row+p->csi_args[0]);
2493 + case 'F': /* Cursor # rows Up, column 1 */
2494 + if (! p->csi_args[0])
2496 + gotoxy(p, 0, p->row-p->csi_args[0]);
2499 + case 'd': /* Cursor to indicated row in current column */
2500 + if (p->csi_args[0])
2502 + gotoxy(p, p->col, p->csi_args[0]);
2505 + case 'H': case 'f': /* Cursor to indicated row, column (origin 1, 1) */
2506 + if (p->csi_args[0])
2508 + if (p->csi_args[1])
2510 + gotoxy(p, p->csi_args[1], p->csi_args[0]);
2513 + case 'J': /* Erase display */
2514 + csi_J(p, p->csi_args[0]);
2517 + case 'K': /* Erase line */
2518 + csi_K(p, p->csi_args[0]);
2521 + case 'L': /* Insert # blank lines */
2522 + csi_L(p, p->csi_args[0]);
2525 + case 'M': /* Delete # blank lines */
2526 + csi_M(p, p->csi_args[0]);
2529 + case 'P': /* Delete # characters on the current line */
2530 + csi_P(p, p->csi_args[0]);
2533 + case 'X': /* Erase # characters on the current line */
2534 + csi_X(p, p->csi_args[0]);
2537 + case 'm': /* Set video attributes */
2538 + csi_m(p, p->index);
2541 + case 's': /* Save cursor position */
2542 + case 'u': /* Restore cursor position */
2546 + case ']': /* Linux private ESC [ ] sequence */
2550 + case 'r': /* Set the scrolling region */
2551 + if (! 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]);
2558 + /* Ignored escape sequences */
2566 + printk(KERN_NOTICE "LCD: unrecognized CSI escape sequence: ESC [ %u\n", input);
2573 + * Custom ESC- sequence handler.
2575 +static int handle_custom_esc(struct lcd_struct *p, unsigned int _input)
2577 + unsigned char input = _input & 0xff;
2578 + struct lcd_parameters *par = p->par;
2580 + if (_input & (~0xff)) {
2581 + switch (ESC_STATE(p)) {
2584 + unsigned char *buf = p->cgram_buffer+(p->cgram_index-par->cgram_char0)*par->cgram_bytes;
2586 + buf[p->index-2] = input;
2587 + if (p->index == par->cgram_bytes+1)
2588 + write_cgram(p, p->cgram_index, buf);
2590 + if (! p->driver->write_cgram_char) {
2591 + printk(KERN_ERR "LCD: %s: missing function to write to CGRAM\n", p->par->name);
2594 + if (input >= par->cgram_char0 && input < par->cgram_char0+par->cgram_chars)
2595 + p->cgram_index = input;
2597 + printk(KERN_NOTICE "LCD: bad CGRAM index\n");
2604 + if (input >= par->cgram_char0 && input < par->cgram_char0+par->cgram_chars)
2605 + write_data(p, (p->attr << 8) | p->driver->charmap[input]);
2607 + SET_INPUT_STATE(p, NORMAL);
2608 + handle_input(p, (p->attr << 8) | input);
2614 + address_mode(p, -1);
2615 + else if (input == '0')
2616 + address_mode(p, 1);
2620 + scrup(p, p->top, p->bot, input);
2624 + scrdown(p, p->top, p->bot, input);
2628 + browse_screen(p, input);
2633 + /* These are the custom ESC- sequences */
2635 + case 's': /* CGRAM select */
2636 + if (p->cgram_buffer) {
2637 + SET_ESC_STATE(p, input);
2639 + return (par->cgram_bytes+1);
2641 + printk(KERN_NOTICE "LCD: driver %s does not support CGRAM chars\n", par->name);
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);
2658 + * ESC- but not CSI sequence handler.
2660 +static int handle_esc(struct lcd_struct *p, unsigned char input)
2664 + SET_INPUT_STATE(p, NORMAL);
2666 + case 'c': /* Reset */
2667 + set_bit(DECAWM, &p->struct_flags);
2668 + set_bit(INC_CURS_POS, &p->struct_flags);
2672 + case 'D': /* Line Feed */
2676 + case 'E': /* New Line */
2681 + case 'M': /* Reverse Line Feed */
2687 + csi_su(p, (input == '7' ? 's' : 'u'));
2690 + /* CSI: Start of CSI escape sequence */
2692 + memset(p->csi_args, 0, sizeof(p->csi_args));
2694 + SET_INPUT_STATE(p, CSI);
2697 + /* Ignored escape sequences */
2699 + SET_INPUT_STATE(p, ESC_G0);
2703 + SET_INPUT_STATE(p, ESC_G1);
2707 + SET_INPUT_STATE(p, ESC_HASH);
2711 + SET_INPUT_STATE(p, ESC_PERCENT);
2722 + /* These are the custom ESC- sequences */
2723 + if ((ret = handle_custom_esc(p, input)) > 0) {
2724 + SET_INPUT_STATE(p, ARG);
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);
2735 + printk(KERN_NOTICE "LCD: unrecognized escape sequence: ESC %u\n", input);
2741 + * Main input handler.
2743 +static void handle_input(struct lcd_struct *p, unsigned short _input)
2745 + unsigned char input = _input & 0xff;
2746 + struct lcd_driver *driver = p->driver;
2748 + switch (INPUT_STATE(p)) {
2750 + if (input < 0x20 || input == 0x9b)
2751 + control_char(p, input);
2753 + write_data(p, (_input & 0xff00) | driver->charmap[input]);
2757 + write_data(p, (_input & 0xff00) | driver->charmap[input]);
2761 + write_data(p, _input);
2762 + SET_INPUT_STATE(p, NORMAL);
2766 + p->esc_args = handle_esc(p, input);
2773 + if (! --p->esc_args)
2774 + SET_INPUT_STATE(p, NORMAL);
2778 + handle_csi(p, input);
2782 + if (handle_custom_esc(p, 0x100 | input) || ! --p->esc_args)
2783 + SET_INPUT_STATE(p, NORMAL);
2787 + if (driver->handle_custom_char(0x100 | input) || ! --p->esc_args)
2788 + SET_INPUT_STATE(p, NORMAL);
2797 +/***************************************
2798 + * Read from/Write to display routines *
2799 + ***************************************/
2802 + * Write character data to the display.
2804 +static void write_data(struct lcd_struct *p, unsigned short data)
2806 + unsigned int vs_cols = p->par->vs_cols;
2810 + if (test_bit(NEED_WRAP, &p->struct_flags)) {
2815 + if (test_bit(DECIM, &p->struct_flags))
2816 + lcd_insert_char(p, 1);
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);
2825 + if (p->display[frame_pos] != data) {
2826 + p->driver->write_char(frame_pos, data);
2827 + p->display[frame_pos] = data;
2830 + p->fb[pos] = data;
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);
2839 + iterator_dec(p->col, vs_cols);
2840 + else if (test_bit(DECAWM, &p->struct_flags))
2841 + set_bit(NEED_WRAP, &p->struct_flags);
2846 + * Write an entire CGRAM character to the display.
2848 +static void write_cgram(struct lcd_struct *p, unsigned char index, unsigned char *pixels)
2850 + unsigned int inc_set = test_bit(INC_CURS_POS, &p->struct_flags);
2853 + address_mode(p, 1);
2855 + p->driver->write_cgram_char(index, pixels);
2858 + address_mode(p, -1);
2862 + * Read character data from the display.
2864 +static void read_data(struct lcd_struct *p, unsigned short *data)
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;
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);
2877 + p->driver->read_char(frame_pos, data);
2879 + if (test_bit(INC_CURS_POS, &p->struct_flags)) {
2880 + iterator_inc(p->col, vs_cols);
2882 + if (p->row+1 < vs_rows)
2886 + iterator_dec(p->col, vs_cols);
2887 + if (p->col+1 == vs_cols) {
2895 + * Read an entire CGRAM character from the display.
2897 +static void read_cgram(struct lcd_struct *p, unsigned char index, unsigned char *pixels)
2899 + unsigned int inc_set = test_bit(INC_CURS_POS, &p->struct_flags);
2902 + address_mode(p, 1);
2904 + p->driver->read_cgram_char(index, pixels);
2907 + address_mode(p, -1);
2914 +/****************************
2915 + * Proc filesystem routines *
2916 + ****************************/
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)
2923 + struct proc_dir_entry *res = create_proc_entry(name, mode, parent);
2926 + res->read_proc = read_proc;
2934 +static int proc_fb_read(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
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;
2942 + down(&p->lcd_sem);
2945 + if ((*eof = (_offset >= p->fb_size))) {
2949 + vs_cols = p->par->vs_cols;
2950 + if (size && need_wrap) {
2952 + temp += sprintf(temp, "\n");
2957 + *start = (char *)0;
2958 + while (size && nr) {
2959 + unsigned char c = (p->fb[_offset] & 0xff);
2961 + temp += sprintf(temp, "%c", (c < 0x20 ? '·' : c));
2969 + temp += sprintf(temp, "\n");
2976 + return (temp-buffer);
2979 +static int proc_display_read(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
2981 + char *temp = buffer;
2982 + struct lcd_struct *p = (struct lcd_struct *)data;
2983 + unsigned int i, frame_cols;
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");
2994 + temp += sprintf(temp, " +");
2995 + for (i = 0; i < frame_cols; ++i)
2996 + temp += sprintf(temp, "-");
2997 + temp += sprintf(temp, "+\n");
2999 + for (i = 0; i < p->frame_size; ++i) {
3000 + unsigned char c = (p->display[i] & 0xff);
3002 + if (! (i%frame_cols))
3003 + temp += sprintf(temp, "%2d |", 1+i/frame_cols);
3005 + temp += sprintf(temp, "%c", (c < 0x20 ? '·' : c));
3007 + temp += sprintf(temp, "_");
3008 + if (! ((i+1)%frame_cols))
3009 + temp += sprintf(temp, "|\n");
3012 + temp += sprintf(temp, " +");
3013 + for (i = 0; i < frame_cols; ++i)
3014 + temp += sprintf(temp, "-");
3015 + temp += sprintf(temp, "+\n");
3018 + return (temp-buffer);
3021 +static int proc_charmap_read(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
3023 + char *temp = buffer;
3024 + struct lcd_struct *p = (struct lcd_struct *)data;
3025 + unsigned char *charmap;
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) {
3033 + temp += sprintf(temp, "\n");
3035 + temp += sprintf(temp, "\n/* %d - %d */\n", i, i+31);
3037 + temp += sprintf(temp, "0x%.2x, ", *charmap++);
3039 + temp += sprintf(temp, "0x%.2x\n\n};\n", *charmap);
3042 + return (temp-buffer);
3045 +static int proc_registered_drivers(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
3047 + char *temp = buffer;
3048 + struct list_head *entry;
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);
3055 + down(&p->lcd_sem);
3056 + temp += sprintf(temp, "%3d %s\n", p->par->minor, p->par->name);
3061 + return (temp-buffer);
3064 +static void create_driver_proc_entries(struct lcd_struct *p)
3066 + struct proc_dir_entry *driver_proc_root = p->driver->driver_proc_root;
3067 + int proc_level = 0;
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);
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);
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);
3084 + SET_PROC_LEVEL(p, ++proc_level);
3087 +static void remove_driver_proc_entries(struct lcd_struct *p)
3089 + struct proc_dir_entry *driver_proc_root = p->driver->driver_proc_root;
3091 + switch (PROC_LEVEL(p)) {
3093 + remove_proc_entry("charmap.h", driver_proc_root);
3095 + remove_proc_entry("display", driver_proc_root);
3097 + remove_proc_entry("framebuffer", driver_proc_root);
3099 + SET_PROC_LEVEL(p, 0);
3107 +/*****************************
3108 + * Low level file operations *
3109 + *****************************/
3110 +static ssize_t do_lcd_read(struct lcd_struct *p, void *buffer, size_t length)
3113 + unsigned short tmp;
3115 + if (! p->refcount)
3118 + if (! p->driver->read_char) {
3119 + printk(KERN_NOTICE "LCD: driver %s doesn't support reading\n", p->par->name);
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;
3129 + for (i = 0; i < length; ++i) {
3130 + read_data(p, &tmp);
3131 + ((unsigned char *)buffer)[i] = tmp & 0xff;
3137 +static ssize_t do_lcd_write(struct lcd_struct *p, const void *buffer, size_t length)
3141 + if (! p->refcount)
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]);
3148 + for (i = 0; i < length; ++i)
3149 + handle_input(p, (p->attr << 8) | ((const unsigned char *)buffer)[i]);
3154 +static int do_lcd_open(struct lcd_struct *p)
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))
3162 + if (__MOD_IN_USE(p->driver->driver_module))
3165 + __MOD_INC_USE_COUNT(p->driver->driver_module);
3175 +static int do_lcd_release(struct lcd_struct *p)
3177 + if (! p->refcount)
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);
3185 + __MOD_DEC_USE_COUNT(p->driver->driver_module);
3194 +static int cgram_ioctl(struct lcd_struct *p, unsigned int cmd, unsigned char *argp)
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;
3202 + if (index < par->cgram_char0 || index >= par->cgram_char0+par->cgram_chars)
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);
3210 + if (test_bit(USER_SPACE, &p->struct_flags)) {
3211 + if (copy_from_user(cgram_buffer, buffer, length))
3214 + memcpy(cgram_buffer, buffer, length);
3215 + write_cgram(p, index, cgram_buffer);
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);
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))
3226 + memcpy(buffer, cgram_buffer, length);
3232 +static int do_lcd_ioctl(struct lcd_struct *p, unsigned int cmd, unsigned long arg)
3235 + struct lcd_driver *driver = p->driver;
3236 + struct lcd_parameters *par = p->par;
3237 + unsigned char *argp = (unsigned char *)arg;
3239 + if (! p->refcount)
3243 + case LCDL_SET_PARAM:
3244 + if ((i = cleanup_driver(p)))
3247 + if (test_bit(USER_SPACE, &p->struct_flags)) {
3248 + if (copy_from_user(par, argp, sizeof(struct lcd_parameters)))
3251 + memcpy(par, argp, sizeof(struct lcd_parameters));
3253 + return (init_driver(p));
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)))
3260 + memcpy(argp, par, sizeof(struct lcd_parameters));
3263 + case LCDL_RESET_CHARMAP:
3264 + for (i = 0; i < 256; ++i)
3265 + driver->charmap[i] = i;
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);
3274 + driver->charmap[i] = argp[1];
3278 + case LCDL_SAVE_CHARMAP:
3279 + memcpy(p->s_charmap, driver->charmap, 256);
3282 + case LCDL_RESTORE_CHARMAP:
3283 + memcpy(driver->charmap, p->s_charmap, 256);
3286 + case LCDL_SWAP_CHARMAP:
3288 + unsigned char *tmp;
3290 + tmp = driver->charmap;
3291 + driver->charmap = p->s_charmap;
3292 + p->s_charmap = tmp;
3296 + case LCDL_RAW_MODE:
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);
3303 + set_bit(DECAWM, &p->struct_flags);
3304 + SET_INPUT_STATE(p, NORMAL);
3308 + case LCDL_CLEAR_DISP:
3312 + case LCDL_SET_CGRAM_CHAR:
3313 + case LCDL_GET_CGRAM_CHAR:
3314 + if (p->cgram_buffer)
3315 + return (cgram_ioctl(p, cmd, argp));
3317 + printk(KERN_NOTICE "LCD: driver %s does not support CGRAM chars\n", par->name);
3320 + case LCDL_SET_CHARMAP:
3321 + if (test_bit(USER_SPACE, &p->struct_flags)) {
3322 + if (copy_from_user(driver->charmap, argp, 256))
3325 + memcpy(driver->charmap, argp, 256);
3328 + case LCDL_GET_CHARMAP:
3329 + if (test_bit(USER_SPACE, &p->struct_flags)) {
3330 + if (copy_to_user(argp, driver->charmap, 256))
3333 + memcpy(argp, driver->charmap, 256);
3337 + case LCDL_MEMMOVE:
3341 + if (test_bit(USER_SPACE, &p->struct_flags)) {
3342 + if (copy_from_user(buf, argp, sizeof(buf)))
3345 + memcpy(buf, argp, sizeof(buf));
3347 + if (cmd == LCDL_MEMSET)
3348 + lcd_memset(p, buf[0], buf[1], buf[2]);
3350 + lcd_memmove(p, buf[0], buf[1], buf[2]);
3356 + if (driver->handle_custom_ioctl)
3357 + return (driver->handle_custom_ioctl(cmd, arg, test_bit(USER_SPACE, &p->struct_flags)));
3360 + return (-ENOIOCTLCMD);
3367 +/**************************************************
3368 + * Kernel register/unregister lcd driver routines *
3369 + **************************************************/
3371 + * Find a driver in lcd_drivers linked list
3373 +static struct lcd_struct *find_lcd_struct(unsigned short minor)
3375 + struct list_head *entry;
3377 + list_for_each(entry, &lcd_drivers) {
3378 + struct lcd_struct *p = list_entry(entry, struct lcd_struct, lcd_list);
3380 + if (p->par->minor == minor)
3387 +static void list_add_sorted(struct list_head *new)
3389 + struct list_head *entry;
3390 + unsigned short new_minor = (list_entry(new, struct lcd_struct, lcd_list))->par->minor;
3392 + list_for_each(entry, &lcd_drivers) {
3393 + struct lcd_struct *p = list_entry(entry, struct lcd_struct, lcd_list);
3395 + if (p->par->minor > new_minor)
3398 + list_add_tail(new, entry);
3401 +/* Exported function */
3402 +int lcd_register_driver(struct lcd_driver *driver, struct lcd_parameters *par)
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;
3412 + if (! driver || ! par || par->minor >= minors)
3414 + if (! driver->write_char || ! driver->init_port || ! driver->cleanup_port) {
3415 + printk(KERN_ERR "LCD: missing functions\n");
3419 + down(&drivers_sem);
3421 + if (find_lcd_struct(par->minor)) {
3426 + if ((p = (struct lcd_struct *)kmalloc(sizeof(struct lcd_struct), GFP_KERNEL)) == NULL) {
3427 + printk(KERN_ERR "LCD: memory allocation failed (kmalloc)\n");
3431 + memset(p, 0, sizeof(struct lcd_struct));
3433 + p->driver = driver;
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);
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)) {
3446 + return (PTR_ERR(lcd_device));
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)) {
3453 + return (PTR_ERR(lcd_class_device));
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)) {
3460 + return (PTR_ERR(lcd_class_device));
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);
3469 + if ((ret = init_driver(p))) {
3471 + if (driver->driver_proc_root)
3472 + remove_proc_entry(p->par->name, lcd_proc_root);
3479 + init_MUTEX(&p->lcd_sem);
3481 + list_add_sorted(&p->lcd_list);
3486 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
3487 + try_module_get(THIS_MODULE);
3489 + MOD_INC_USE_COUNT;
3495 +EXPORT_SYMBOL(lcd_register_driver);
3497 +/* Exported function */
3498 +int lcd_unregister_driver(struct lcd_driver *driver, struct lcd_parameters *par)
3501 + struct lcd_struct *p;
3503 + if (! driver || ! par || par->minor >= minors)
3506 + down(&drivers_sem);
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");
3514 + down(&p->lcd_sem);
3516 + if (p->refcount) {
3517 + printk(KERN_ERR "LCD: driver busy; lcd_unregister_driver failed\n");
3523 + if ((ret = cleanup_driver(p))) {
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));
3536 + if (p->driver->driver_proc_root)
3537 + remove_proc_entry(p->par->name, lcd_proc_root);
3540 + list_del(&p->lcd_list);
3546 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
3547 + module_put(THIS_MODULE);
3549 + MOD_DEC_USE_COUNT;
3555 +EXPORT_SYMBOL(lcd_unregister_driver);
3561 +/************************
3562 + * Kernel I/O interface *
3563 + ************************/
3564 +/* Exported function */
3565 +int lcd_open(unsigned short minor, struct lcd_struct **pp)
3568 + struct lcd_struct *p;
3570 + down(&drivers_sem);
3572 + if (minor >= minors || (*pp = p = find_lcd_struct(minor)) == NULL) {
3573 + printk(KERN_ERR "LCD: lcd_open failed. Device not found.\n");
3578 + down(&p->lcd_sem);
3581 + ret = do_lcd_open(p);
3587 +EXPORT_SYMBOL(lcd_open);
3589 +/* Exported function */
3590 +int lcd_close(struct lcd_struct **pp)
3593 + struct lcd_struct *p;
3595 + if (! pp || ! (p = *pp)) {
3596 + printk(KERN_ERR "LCD: NULL pointer in lcd_close\n");
3600 + down(&p->lcd_sem);
3602 + if (! (ret = do_lcd_release(p)))
3609 +EXPORT_SYMBOL(lcd_close);
3611 +static inline loff_t offset_to_row_col(struct lcd_struct *p, loff_t offset)
3613 + unsigned long _offset = offset;
3614 + unsigned int vs_cols = p->par->vs_cols;
3616 + gotoxy(p, _offset%vs_cols, _offset/vs_cols);
3618 + return ((p->row*vs_cols)+p->col);
3621 +/* Exported function */
3622 +ssize_t lcd_read(struct lcd_struct *p, void *bufp, size_t length, loff_t offset, unsigned int with_attr)
3627 + printk(KERN_ERR "LCD: NULL pointer in lcd_read\n");
3632 + if (offset < 0 || offset >= p->fb_size)
3635 + if (length+offset > p->fb_size)
3636 + length = p->fb_size-offset;
3639 + set_bit(WITH_ATTR, &p->struct_flags);
3641 + offset_to_row_col(p, offset);
3642 + ret = do_lcd_read(p, bufp, length);
3645 + clear_bit(WITH_ATTR, &p->struct_flags);
3649 +EXPORT_SYMBOL(lcd_read);
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)
3657 + printk(KERN_ERR "LCD: NULL pointer in lcd_write\n");
3662 + if (offset < 0 || offset >= p->fb_size)
3666 + set_bit(WITH_ATTR, &p->struct_flags);
3668 + offset_to_row_col(p, offset);
3669 + ret = do_lcd_write(p, bufp, length);
3672 + clear_bit(WITH_ATTR, &p->struct_flags);
3676 +EXPORT_SYMBOL(lcd_write);
3678 +/* Exported function */
3679 +int lcd_ioctl(struct lcd_struct *p, unsigned int cmd, ...)
3682 + unsigned long arg;
3686 + printk(KERN_ERR "LCD: NULL pointer in lcd_ioctl\n");
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);
3699 +EXPORT_SYMBOL(lcd_ioctl);
3705 +/*******************
3706 + * File operations *
3707 + *******************/
3708 +static loff_t lcd_fops_llseek(struct file *filp, loff_t offset, int orig)
3710 + struct lcd_struct *p;
3712 + if (! (p = filp->private_data))
3715 + down(&p->lcd_sem);
3719 + filp->f_pos = offset;
3723 + filp->f_pos += offset;
3728 + return (-EINVAL); /* SEEK_END not supported */
3731 + filp->f_pos = offset_to_row_col(p, filp->f_pos);
3735 + return (filp->f_pos);
3738 +static ssize_t lcd_fops_read(struct file *filp, char *buffer, size_t length, loff_t *offp)
3741 + char *bufp = buffer;
3742 + struct lcd_struct *p;
3746 + if (! (p = filp->private_data))
3749 + down(&p->lcd_sem);
3751 + if (*offp < 0 || *offp >= p->fb_size) {
3756 + if (length+(*offp) > p->fb_size)
3757 + length = p->fb_size-(*offp);
3760 + ret = (length > FLIP_BUF_SIZE ? FLIP_BUF_SIZE : length);
3761 + if ((ret = do_lcd_read(p, p->flip_buf, ret)) < 0)
3763 + *offp = (p->row*p->par->vs_cols)+p->col;
3764 + if (copy_to_user(bufp, p->flip_buf, ret)) {
3770 + ret = bufp-buffer;
3780 +static ssize_t lcd_fops_write(struct file *filp, const char *buffer, size_t length, loff_t *offp)
3783 + const char *bufp = buffer;
3784 + struct lcd_struct *p;
3788 + if (! (p = filp->private_data))
3791 + down(&p->lcd_sem);
3793 + if (*offp < 0 || *offp >= p->fb_size) {
3799 + ret = (length > FLIP_BUF_SIZE ? FLIP_BUF_SIZE : length);
3800 + if (copy_from_user(p->flip_buf, bufp, ret)) {
3804 + if ((ret = do_lcd_write(p, p->flip_buf, ret)) < 0)
3806 + *offp = (p->row*p->par->vs_cols)+p->col;
3809 + ret = bufp-buffer;
3819 +static int lcd_fops_open(struct inode *inop, struct file *filp)
3821 + unsigned short minor;
3823 + struct lcd_struct *p;
3825 + down(&drivers_sem);
3827 + if ((minor = MINOR(inop->i_rdev)) >= minors || (filp->private_data = p = find_lcd_struct(minor)) == NULL) {
3832 + down(&p->lcd_sem);
3835 + ret = do_lcd_open(p);
3842 +static int lcd_fops_release(struct inode *inop, struct file *filp)
3844 + struct lcd_struct *p;
3847 + if (! (p = filp->private_data))
3850 + down(&p->lcd_sem);
3852 + if (! (ret = do_lcd_release(p)))
3853 + filp->private_data = NULL;
3860 +static int lcd_fops_ioctl(struct inode *inop, struct file *filp, unsigned int cmd, unsigned long arg)
3862 + struct lcd_struct *p;
3865 + if (! (p = filp->private_data))
3868 + down(&p->lcd_sem);
3870 + set_bit(USER_SPACE, &p->struct_flags);
3871 + ret = do_lcd_ioctl(p, cmd, arg);
3872 + clear_bit(USER_SPACE, &p->struct_flags);
3879 +static struct file_operations lcd_linux_fops = {
3880 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
3881 + .owner = THIS_MODULE,
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,
3895 +/********************************
3896 + * Init/Cleanup driver routines *
3897 + ********************************/
3898 +static int do_init_driver(struct lcd_struct *p)
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;
3906 + switch ((init_level = INIT_LEVEL(p))) {
3908 + if (frame_rows == 0 || frame_cols == 0 || ! par->name) {
3909 + printk(KERN_ERR "LCD: wrong lcd parameters\n");
3912 + if (driver->validate_driver) {
3913 + if ((ret = driver->validate_driver()) < 0) {
3914 + printk(KERN_ERR "LCD: validate_driver failed\n");
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;
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;
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");
3941 + __memset_short(p->fb, p->erase_char, p->fb_size+p->frame_size);
3943 + p->display = p->fb+p->fb_size;
3944 + p->flip_buf = (unsigned char *)(p->display+p->frame_size);
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;
3953 + p->s_charmap = p->flip_buf+FLIP_BUF_SIZE;
3954 + memset(p->s_charmap, 0, 256);
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);
3960 + p->cgram_buffer = NULL;
3962 + p->frame_base = 0;
3963 + p->row = p->col = 0;
3965 + p->bot = par->vs_rows;
3966 + SET_INIT_LEVEL(p, ++init_level);
3969 + /* Initialize the communication port */
3970 + if ((ret = driver->init_port())) {
3971 + printk(KERN_ERR "LCD: failure while initializing the communication port\n");
3974 + SET_INIT_LEVEL(p, ++init_level);
3977 + /* Initialize LCD display */
3978 + if (driver->init_display && (ret = driver->init_display())) {
3979 + printk(KERN_ERR "LCD: failure while initializing the display\n");
3984 + /* Create entries in /proc/lcd/"driver" */
3985 + if (driver->driver_proc_root)
3986 + create_driver_proc_entries(p);
3988 + SET_INIT_LEVEL(p, ++init_level);
3994 +static int do_cleanup_driver(struct lcd_struct *p)
3996 + int ret, init_level;
3997 + struct lcd_driver *driver = p->driver;
3999 + switch ((init_level = INIT_LEVEL(p))) {
4002 + if (driver->driver_proc_root)
4003 + remove_driver_proc_entries(p);
4005 + if (driver->cleanup_display && (ret = driver->cleanup_display())) {
4006 + printk(KERN_ERR "LCD: failure while cleaning the display\n");
4009 + SET_INIT_LEVEL(p, --init_level);
4012 + if ((ret = driver->cleanup_port())) {
4013 + printk(KERN_ERR "LCD: failure while cleaning the communication port\n");
4016 + SET_INIT_LEVEL(p, --init_level);
4019 + if (test_bit(NULL_CHARMAP, &p->struct_flags)) {
4020 + p->driver->charmap = NULL;
4021 + clear_bit(NULL_CHARMAP, &p->struct_flags);
4025 + SET_INIT_LEVEL(p, --init_level);
4031 +static int init_driver(struct lcd_struct *p)
4035 + if ((ret = do_init_driver(p))) {
4036 + do_cleanup_driver(p);
4037 + printk(KERN_ERR "LCD: init_driver failed\n");
4043 +static int cleanup_driver(struct lcd_struct *p)
4047 + if ((ret = do_cleanup_driver(p))) {
4048 + do_init_driver(p);
4049 + printk(KERN_ERR "LCD: cleanup_driver failed\n");
4059 +/********************************
4060 + * Init/Cleanup module routines *
4061 + ********************************/
4062 +static int __init lcd_linux_init_module(void)
4066 + if (! minors || minors > 256)
4067 + minors = LCD_MINORS;
4069 + init_MUTEX(&drivers_sem);
4071 + if ((ret = register_chrdev(major, LCD_LINUX_STRING, &lcd_linux_fops)) < 0) {
4072 + printk(KERN_ERR "LCD: register_chrdev failed\n");
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);
4087 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
4088 + if ((lcd_proc_root = proc_mkdir("lcd", NULL)) == NULL)
4090 + if ((lcd_proc_root = proc_mkdir("lcd", &proc_root)) == NULL)
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");
4097 + printk(KERN_INFO "LCD: --> LCD-Linux " LCD_LINUX_VERSION " <--\n");
4098 + printk(KERN_INFO "LCD: --> Mattia Jona-Lasinio <mjona@users.sourceforge.net> <--\n" );
4104 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
4105 +static void __exit lcd_linux_cleanup_module(void)
4107 +/* __exit is not defined in 2.2.x kernels */
4108 +static void lcd_linux_cleanup_module(void)
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);
4117 + remove_proc_entry("lcd", &proc_root);
4122 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
4123 + class_destroy(lcd_linux_class);
4126 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
4127 + unregister_chrdev(major, LCD_LINUX_STRING);
4129 + if (unregister_chrdev(major, LCD_LINUX_STRING))
4130 + printk(KERN_ERR "LCD: unregister_chrdev failed\n");
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
4145 + * Driver for HD44780 compatible displays connected to the parallel port.
4147 + * HD44780 header file.
4149 + * Copyright (C) 2004 - 2007 Mattia Jona-Lasinio (mjona@users.sourceforge.net)
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.
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.
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
4170 +#include <linux/lcd-linux.h>
4172 +#define HD44780_VERSION LCD_LINUX_VERSION /* Version number */
4173 +#define HD44780_STRING "hd44780"
4175 +#define HD44780_MINOR 0 /* Minor number for the hd44780 driver */
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 */
4184 +#define HD44780_READ_AC _IOR(LCD_MAJOR, 0x00, unsigned char *)
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
4195 + * Software layer to drive LCD displays under Linux.
4197 + * External interface header file.
4199 + * Copyright (C) 2005 - 2007 Mattia Jona-Lasinio (mjona@users.sourceforge.net)
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.
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.
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
4217 +#ifndef LCD_LINUX_H
4218 +#define LCD_LINUX_H
4220 +#ifndef LCD_LINUX_MAIN
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/"
4232 +#define LCD_LINUX_VERSION "0.13.6" /* Version number */
4233 +#define LCD_LINUX_STRING "lcd"
4235 +#define LCD_MAJOR 120 /* Major number for this device
4236 + * Set this to 0 for dynamic allocation
4238 +#define LCD_MINORS 8 /* Minors allocated for LCD-Linux*/
4240 +#include <linux/types.h>
4243 +#define string(s) str(s)
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 */
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 *)
4281 +#ifdef __KERNEL__ /* The rest is for kernel only */
4283 +#include <linux/kernel.h>
4284 +#include <linux/module.h>
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);
4302 + /* The character map to be used */
4303 + unsigned char *charmap;
4305 + /* The root where the driver can create its own proc files.
4306 + * Will be filled by the lcd-linux layer.
4308 + struct proc_dir_entry *driver_proc_root;
4310 + /* Set this field to 'driver_module_init' or call lcd_driver_setup
4311 + * just before registering the driver with lcd_register_driver.
4313 + struct module *driver_module;
4317 +#define driver_module_init THIS_MODULE
4319 +#define driver_module_init NULL
4322 +/* Always call lcd_driver_setup just before registering the driver
4323 + * with lcd_register_driver.
4325 +static inline void lcd_driver_setup(struct lcd_driver *p)
4327 + p->driver_module = driver_module_init;
4330 +/* External interface */
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);
4340 +#endif /* __KERNEL__ */
4342 +#endif /* External interface included */