linux-2.6.34: update kernel patchset
authorPetr Štetiar <ynezz@true.cz>
Thu, 21 Oct 2010 19:48:28 +0000 (21:48 +0200)
committerPetr Štetiar <ynezz@true.cz>
Sun, 28 Nov 2010 22:11:03 +0000 (23:11 +0100)
- update base patch for ts7300
- add SD card support for ts7300
- add OpenCores ethernet driver for ts7300
- add new patch in which we use CPLD watchdog to reset the board
- add new patch for console (uses hd44780 LCD on LCD connector)
- add new patch lcd-linux (uses hd44780 LCD on LCD connector)

Tested-by: Bridges Seth <seth@sethbridges.com>
Tested-by: Ian Thompson <ian.thompson@pgs.com>
Signed-off-by: Petr Štetiar <ynezz@true.cz>
26 files changed:
recipes/linux/linux-2.6.34/ts72xx/0001-ts72xx_base.patch
recipes/linux/linux-2.6.34/ts72xx/0002-ts72xx_force_machine-id.patch
recipes/linux/linux-2.6.34/ts72xx/0003-ep93xx_cpuinfo.patch
recipes/linux/linux-2.6.34/ts72xx/0004-ep93xx_eth.patch
recipes/linux/linux-2.6.34/ts72xx/0005-ep93xx-m2m-DMA-support.patch
recipes/linux/linux-2.6.34/ts72xx/0006-ts72xx_rs485.patch
recipes/linux/linux-2.6.34/ts72xx/0007-ts72xx_ts_ser1.patch
recipes/linux/linux-2.6.34/ts72xx/0008-ts72xx_ts_eth100.patch
recipes/linux/linux-2.6.34/ts72xx/0009-ts72xx_pata.patch
recipes/linux/linux-2.6.34/ts72xx/0010-ts72xx_gpio_i2c.patch
recipes/linux/linux-2.6.34/ts72xx/0011-ts72xx_dio_keypad.patch
recipes/linux/linux-2.6.34/ts72xx/0012-ts72xx_sbcinfo.patch
recipes/linux/linux-2.6.34/ts72xx/0013-ts72xx_max197.patch
recipes/linux/linux-2.6.34/ts72xx/0014-ts7200_nor_flash.patch
recipes/linux/linux-2.6.34/ts72xx/0015-ts72xx_sdcard.patch
recipes/linux/linux-2.6.34/ts72xx/0016-ts72xx_nand_flash.patch
recipes/linux/linux-2.6.34/ts72xx/0017-ep93xx_spi.patch
recipes/linux/linux-2.6.34/ts72xx/0018-ts72xx_spi_tmp124.patch
recipes/linux/linux-2.6.34/ts72xx/0019-ts72xx-use-CPLD-watchdog-for-reset.patch [new file with mode: 0644]
recipes/linux/linux-2.6.34/ts72xx/0020-ethoc-ts7300-fixes.patch [new file with mode: 0644]
recipes/linux/linux-2.6.34/ts72xx/0021-ts7300-add-ethernet-support.patch [new file with mode: 0644]
recipes/linux/linux-2.6.34/ts72xx/0022-watchdog-ts72xx_wdt-disable-watchdog-at-probe.patch [moved from recipes/linux/linux-2.6.34/ts72xx/0019-watchdog-ts72xx_wdt-disable-watchdog-at-probe.patch with 89% similarity]
recipes/linux/linux-2.6.34/ts72xx/0024-TS-72XX-LCD-console-driver.patch [new file with mode: 0644]
recipes/linux/linux-2.6.34/ts72xx/0025-ts72xx-add-lcd-linux-driver.patch [new file with mode: 0644]
recipes/linux/linux-2.6.34/ts72xx/defconfig
recipes/linux/linux_2.6.34.bb

index 247601b..456469d 100644 (file)
@@ -1,22 +1,27 @@
-From 9a60df856b54ba2f09dc0bbe4229627372f0a122 Mon Sep 17 00:00:00 2001
+From 370a47d42411dfafd224714eea88c7312a53ed18 Mon Sep 17 00:00:00 2001
 From: Matthieu Crapet <mcrapet@gmail.com>
 Date: Thu, 10 Jun 2010 10:43:24 +0200
-Subject: [PATCH 01/18] ts72xx_base
+Subject: [PATCH 01/25] ts72xx_base
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
 - patch: allow to force nF bit in control reg
 - register pwm1
+
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
 ---
  arch/arm/Kconfig                                |    1 +
  arch/arm/mach-ep93xx/Kconfig                    |    9 ++
  arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |    8 ++
- arch/arm/mach-ep93xx/include/mach/memory.h      |   28 +++++
- arch/arm/mach-ep93xx/include/mach/ts72xx.h      |  147 ++++++++++++++++++++---
+ arch/arm/mach-ep93xx/include/mach/memory.h      |   28 ++++
+ arch/arm/mach-ep93xx/include/mach/ts72xx.h      |  153 ++++++++++++++++++++---
  arch/arm/mach-ep93xx/ts72xx.c                   |   40 ++++++-
  arch/arm/mm/proc-arm920.S                       |    5 +-
- 7 files changed, 218 insertions(+), 20 deletions(-)
+ 7 files changed, 224 insertions(+), 20 deletions(-)
 
 diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
-index 92622eb..ab19836 100644
+index 811dedc..0675f74 100644
 --- a/arch/arm/Kconfig
 +++ b/arch/arm/Kconfig
 @@ -321,6 +321,7 @@ config ARCH_EP93XX
@@ -128,7 +133,7 @@ index 554064e..78eaacf 100644
 +
  #endif
 diff --git a/arch/arm/mach-ep93xx/include/mach/ts72xx.h b/arch/arm/mach-ep93xx/include/mach/ts72xx.h
-index 93107d8..83ed0e6 100644
+index 93107d8..71c80fd 100644
 --- a/arch/arm/mach-ep93xx/include/mach/ts72xx.h
 +++ b/arch/arm/mach-ep93xx/include/mach/ts72xx.h
 @@ -8,38 +8,40 @@
@@ -199,7 +204,7 @@ index 93107d8..83ed0e6 100644
  
  #define TS72XX_RTC_INDEX_VIRT_BASE    0xfebf9000
  #define TS72XX_RTC_INDEX_PHYS_BASE    0x10800000
-@@ -68,32 +71,140 @@
+@@ -68,32 +71,146 @@
  #define TS72XX_WDT_CONTROL_PHYS_BASE  0x23800000
  #define TS72XX_WDT_FEED_PHYS_BASE     0x23c00000
  
@@ -307,6 +312,12 @@ index 93107d8..83ed0e6 100644
 +                      TS7XXX_MODEL_MASK) == TS7XXX_MODEL_TS7260;
 +}
 +
++static inline int board_is_ts7300(void)
++{
++      return (__raw_readb(TS72XX_MODEL_VIRT_BASE) &
++                      TS7XXX_MODEL_MASK) == TS7XXX_MODEL_TS7300;
++}
++
 +static inline int board_is_ts7400(void)
 +{
 +      return (__raw_readb(TS72XX_MODEL_VIRT_BASE) &
@@ -441,5 +452,5 @@ index 8be8199..a4f123d 100644
        .size   __arm920_setup, . - __arm920_setup
  
 -- 
-1.7.1
+1.7.0.4
 
index e59bb4e..900998d 100644 (file)
@@ -1,8 +1,12 @@
-From 453060da6afa4c32d2e2704e69ad32f200d4d240 Mon Sep 17 00:00:00 2001
+From aa694357a2b206488ebd31b9e4ebf734e377d749 Mon Sep 17 00:00:00 2001
 From: Matthieu Crapet <mcrapet@gmail.com>
 Date: Thu, 10 Jun 2010 10:51:39 +0200
-Subject: [PATCH 02/18] ts72xx_force_machine-id
+Subject: [PATCH 02/25] ts72xx_force_machine-id
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
 ---
  arch/arm/kernel/head.S       |    3 +++
  arch/arm/mach-ep93xx/Kconfig |    7 +++++++
@@ -41,5 +45,5 @@ index b6be37e..bd463a0 100644
  
  endif
 -- 
-1.7.1
+1.7.0.4
 
index 83519d6..c7f1560 100644 (file)
@@ -1,8 +1,12 @@
-From cbb613e31ddb5f27e7bffa95be458c260fa4de11 Mon Sep 17 00:00:00 2001
+From 054658b33bdcac8d03357c95845edbc03e7e913e Mon Sep 17 00:00:00 2001
 From: Matthieu Crapet <mcrapet@gmail.com>
 Date: Thu, 10 Jun 2010 10:59:31 +0200
-Subject: [PATCH 03/18] ep93xx_cpuinfo
+Subject: [PATCH 03/25] ep93xx_cpuinfo
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
 ---
  arch/arm/kernel/setup.c |    9 +++++++++
  1 files changed, 9 insertions(+), 0 deletions(-)
@@ -28,5 +32,5 @@ index c91c77b..867387c 100644
        seq_printf(m, "Serial\t\t: %08x%08x\n",
                   system_serial_high, system_serial_low);
 -- 
-1.7.1
+1.7.0.4
 
index 4e3caf4..a945793 100644 (file)
@@ -1,8 +1,12 @@
-From 9f020e91022926d1fe36b8a6e28b16bcca2d37e5 Mon Sep 17 00:00:00 2001
+From ee4150171586b463632fc577f8dd9cd32dd15d46 Mon Sep 17 00:00:00 2001
 From: Matthieu Crapet <mcrapet@gmail.com>
 Date: Thu, 10 Jun 2010 13:34:14 +0200
-Subject: [PATCH 04/18] ep93xx_eth
+Subject: [PATCH 04/25] ep93xx_eth
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
 ---
  drivers/net/arm/Kconfig      |    1 +
  drivers/net/arm/ep93xx_eth.c |  346 ++++++++++++++++++++++++++++++++++--------
@@ -547,5 +551,5 @@ index cd17d09..d18824b 100644
 +MODULE_DESCRIPTION("EP93XX Ethernet driver");
 +MODULE_ALIAS("platform:" DRV_NAME);
 -- 
-1.7.1
+1.7.0.4
 
index 5adc450..7e7ab0d 100644 (file)
@@ -1,8 +1,12 @@
-From 62a8847f18ac66120bf1dc07a497a4d74e099036 Mon Sep 17 00:00:00 2001
+From f1039372e78e75dc86915257008cc8a13f8f7e29 Mon Sep 17 00:00:00 2001
 From: Matthieu Crapet <mcrapet@gmail.com>
 Date: Thu, 10 Jun 2010 16:40:16 +0200
-Subject: [PATCH 05/18] ep93xx: m2m DMA support
+Subject: [PATCH 05/25] ep93xx: m2m DMA support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
 ---
  arch/arm/mach-ep93xx/Makefile           |    2 +-
  arch/arm/mach-ep93xx/dma-m2m.c          |  753 +++++++++++++++++++++++++++++++
@@ -878,5 +882,5 @@ index 3a5961d..6a3552b 100644
 +
  #endif /* __ASM_ARCH_DMA_H */
 -- 
-1.7.1
+1.7.0.4
 
index ae7fefe..bb65acd 100644 (file)
@@ -1,9 +1,14 @@
-From 6f231c654139e014473ccf0e79725dd313435c8c Mon Sep 17 00:00:00 2001
+From d7c51b7f17a61af71ad3018d755ed0c49825d4e1 Mon Sep 17 00:00:00 2001
 From: Matthieu Crapet <mcrapet@gmail.com>
 Date: Thu, 10 Jun 2010 17:00:12 +0200
-Subject: [PATCH 06/18] ts72xx_rs485
+Subject: [PATCH 06/25] ts72xx_rs485
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
 Crude hack...
+
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
 ---
  arch/arm/include/asm/ioctls.h |    3 +
  drivers/serial/Kconfig        |    8 +++
@@ -214,5 +219,5 @@ index b09a638..a12922a 100644
                        uart_unregister_driver(&amba_reg);
        }
 -- 
-1.7.1
+1.7.0.4
 
index a6fab75..1d5966b 100644 (file)
@@ -1,9 +1,14 @@
-From f5b0dc2b5e15d83cbc51404d2a754ea8ea8961b5 Mon Sep 17 00:00:00 2001
+From 9b05d681f209a1ab5c2e1d0ad531488c02dc4e9e Mon Sep 17 00:00:00 2001
 From: Matthieu Crapet <mcrapet@gmail.com>
 Date: Wed, 16 Jun 2010 14:44:44 +0200
-Subject: [PATCH 07/18] ts72xx_ts_ser1
+Subject: [PATCH 07/25] ts72xx_ts_ser1
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
 TS-SER1 - Serial Port PC/104 peripheral
+
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
 ---
  drivers/serial/8250_ts_ser1.c |  197 +++++++++++++++++++++++++++++++++++++++++
  drivers/serial/Kconfig        |   17 ++++
@@ -255,5 +260,5 @@ index 6aa4723..a3b1cf2 100644
  obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
  obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
 -- 
-1.7.1
+1.7.0.4
 
index 75d5303..a526674 100644 (file)
@@ -1,9 +1,14 @@
-From 9a9465369f2fdbd22b68e545b4744b8dca1608ff Mon Sep 17 00:00:00 2001
+From c8adb8a465e0c7e3af7f2eb031064a07bef2c623 Mon Sep 17 00:00:00 2001
 From: Matthieu Crapet <mcrapet@gmail.com>
 Date: Fri, 18 Jun 2010 17:39:09 +0200
-Subject: [PATCH 08/18] ts72xx_ts_eth100
+Subject: [PATCH 08/25] ts72xx_ts_eth100
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
 TS-ETH100 - 10/100 Ethernet PC/104 peripheral
+
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
 ---
  drivers/net/Kconfig             |   10 ++
  drivers/net/Makefile            |    1 +
@@ -269,5 +274,5 @@ index 0000000..448b3e3
 +MODULE_LICENSE("GPL");
 +MODULE_VERSION("0.21");
 -- 
-1.7.1
+1.7.0.4
 
index 1575e0e..5169a3b 100644 (file)
@@ -1,11 +1,16 @@
-From 2500e39a54c9c37abbddd1ad552575b24420e1a8 Mon Sep 17 00:00:00 2001
+From 4c1ed6eb94871a4d343459a8548c03626df0e3a7 Mon Sep 17 00:00:00 2001
 From: Matthieu Crapet <mcrapet@gmail.com>
 Date: Sat, 19 Jun 2010 11:25:31 +0200
-Subject: [PATCH 09/18] ts72xx_pata
+Subject: [PATCH 09/25] ts72xx_pata
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
 Support:
 TS-7200 - Compact flash
 TS-9600 - IDE interface PC/104 peripheral
+
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
 ---
  drivers/ata/Kconfig          |   20 +++++
  drivers/ata/Makefile         |    3 +
@@ -428,5 +433,5 @@ index 0000000..7a70550
 +MODULE_LICENSE("GPL");
 +MODULE_VERSION(DRV_VERSION);
 -- 
-1.7.1
+1.7.0.4
 
index b984736..f38dc19 100644 (file)
@@ -1,8 +1,12 @@
-From 93e23786cb9a055fca63f4bdfdfaeff63bae745b Mon Sep 17 00:00:00 2001
+From 296a2917205f3cec6f56146a8dfc05005ce31ce6 Mon Sep 17 00:00:00 2001
 From: Matthieu Crapet <mcrapet@gmail.com>
 Date: Sat, 19 Jun 2010 11:45:39 +0200
-Subject: [PATCH 10/18] ts72xx_gpio_i2c
+Subject: [PATCH 10/25] ts72xx_gpio_i2c
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
 ---
  arch/arm/mach-ep93xx/ts72xx.c |   21 +++++++++++++++++++++
  1 files changed, 21 insertions(+), 0 deletions(-)
@@ -54,5 +58,5 @@ index 37325c4..325b7af 100644
        /* PWM1 is DIO_6 on TS-72xx header */
        ep93xx_register_pwm(0, 1);
 -- 
-1.7.1
+1.7.0.4
 
index cced784..43b6edc 100644 (file)
@@ -1,9 +1,14 @@
-From c1515f196bfc70cad5f9a755bf0038f190fd8c22 Mon Sep 17 00:00:00 2001
+From 1c9a9e85890e1dd904f6e3a873d3c783a9b94228 Mon Sep 17 00:00:00 2001
 From: Matthieu Crapet <mcrapet@gmail.com>
 Date: Sat, 19 Jun 2010 14:44:32 +0200
-Subject: [PATCH 11/18] ts72xx_dio_keypad
+Subject: [PATCH 11/25] ts72xx_dio_keypad
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
 Depends of "matrix-keypad" driver.
+
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
 ---
  drivers/input/keyboard/Kconfig          |   30 ++++++++
  drivers/input/keyboard/Makefile         |    2 +
@@ -302,5 +307,5 @@ index 0000000..790abd5
 +MODULE_DESCRIPTION("Platform device 4x4 keypad");
 +MODULE_LICENSE("GPL");
 -- 
-1.7.1
+1.7.0.4
 
index 8a54f2c..ebbdc7f 100644 (file)
@@ -1,8 +1,12 @@
-From b663f02d95027d89b42f57072adf6ea83adb78dd Mon Sep 17 00:00:00 2001
+From 54dd4037caa8deed5848b8efd1e39fe67c3d9952 Mon Sep 17 00:00:00 2001
 From: Matthieu Crapet <mcrapet@gmail.com>
 Date: Sat, 19 Jun 2010 15:08:58 +0200
-Subject: [PATCH 12/18] ts72xx_sbcinfo
+Subject: [PATCH 12/25] ts72xx_sbcinfo
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
 ---
  arch/arm/mach-ep93xx/Kconfig          |    7 +
  arch/arm/mach-ep93xx/Makefile         |    1 +
@@ -259,5 +263,5 @@ index 0000000..cbb485f
 +MODULE_LICENSE("GPL");
 +MODULE_VERSION("1.04");
 -- 
-1.7.1
+1.7.0.4
 
index 86f52a3..71bfdc3 100644 (file)
@@ -1,8 +1,12 @@
-From 93aa4fc5d32534422e80bbb7d1929f533c4ce65f Mon Sep 17 00:00:00 2001
+From b1c198b48cc14958bec8dfc5a7fc56964acbcd47 Mon Sep 17 00:00:00 2001
 From: Matthieu Crapet <mcrapet@gmail.com>
 Date: Sat, 19 Jun 2010 15:49:34 +0200
-Subject: [PATCH 13/18] ts72xx_max197
+Subject: [PATCH 13/25] ts72xx_max197
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
 ---
  arch/arm/mach-ep93xx/ts72xx.c |   30 +++++
  drivers/misc/Kconfig          |   21 ++++
@@ -343,5 +347,5 @@ index 0000000..4121ae5
 +module_init(ts72xx_max197_init);
 +module_exit(ts72xx_max197_exit);
 -- 
-1.7.1
+1.7.0.4
 
index c76ad36..4e1155b 100644 (file)
@@ -1,9 +1,14 @@
-From 116d99d9f45c30d3b1c80b54fed8bf406aa590f7 Mon Sep 17 00:00:00 2001
+From 49be95acfe134c476ed8aaa1f57feebaabf5924b Mon Sep 17 00:00:00 2001
 From: Matthieu Crapet <mcrapet@gmail.com>
 Date: Sat, 19 Jun 2010 16:56:48 +0200
-Subject: [PATCH 14/18] ts7200_nor_flash
+Subject: [PATCH 14/25] ts7200_nor_flash
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
 Deal with 8mb or 16mb NOR Flash (TS-7200 only)
+
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
 ---
  drivers/mtd/maps/Kconfig        |   15 +++++
  drivers/mtd/maps/Makefile       |    1 +
@@ -172,5 +177,5 @@ index 0000000..94fb4f4
 +MODULE_DESCRIPTION("MTD map driver for TS-7200 board");
 +MODULE_VERSION("0.1");
 -- 
-1.7.1
+1.7.0.4
 
index 2b0fd19..692e848 100644 (file)
@@ -1,12 +1,17 @@
-From 3da21c5a4384f9853fd75cb9fed204402072d280 Mon Sep 17 00:00:00 2001
+From 7ac580b72363f51c008eee00b92c66e8bb113d14 Mon Sep 17 00:00:00 2001
 From: Matthieu Crapet <mcrapet@gmail.com>
 Date: Sun, 20 Jun 2010 10:46:15 +0200
-Subject: [PATCH 15/18] ts72xx_sdcard
+Subject: [PATCH 15/25] ts72xx_sdcard
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
 SD Card support for TS-7260. Device name is "tssda".
 Patch based on work of Breton Saunders:
 http://tech.groups.yahoo.com/group/ts-7000/message/15787
 http://tech.groups.yahoo.com/group/ts-7000/message/16028
+
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
 ---
  arch/arm/mach-ep93xx/ts72xx.c |   24 +
  drivers/block/Kconfig         |    7 +
@@ -19,11 +24,11 @@ http://tech.groups.yahoo.com/group/ts-7000/message/16028
  create mode 100644 drivers/block/sdcore2.h
  create mode 100644 drivers/block/tssdcard.c
 
-Index: linux-2.6.34/arch/arm/mach-ep93xx/ts72xx.c
-===================================================================
---- linux-2.6.34.orig/arch/arm/mach-ep93xx/ts72xx.c    2010-10-13 23:55:37.000000000 +0200
-+++ linux-2.6.34/arch/arm/mach-ep93xx/ts72xx.c 2010-10-16 11:17:20.000000000 +0200
-@@ -178,6 +178,29 @@
+diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c
+index ba27d9d..ec2ab8e 100644
+--- a/arch/arm/mach-ep93xx/ts72xx.c
++++ b/arch/arm/mach-ep93xx/ts72xx.c
+@@ -178,6 +178,29 @@ static void __init ts72xx_register_flash(void)
  }
  
  /*************************************************************************
@@ -45,7 +50,7 @@ Index: linux-2.6.34/arch/arm/mach-ep93xx/ts72xx.c
 +
 +static void __init ts72xx_register_sdcard(void)
 +{
-+      if (board_is_ts7260() || board_is_ts7400())
++      if (board_is_ts7260() || board_is_ts7400() || board_is_ts7300())
 +              platform_device_register(&ts72xx_sdcard);
 +}
 +
@@ -53,7 +58,7 @@ Index: linux-2.6.34/arch/arm/mach-ep93xx/ts72xx.c
   * RTC
   *************************************************************************/
  static unsigned char ts72xx_rtc_readbyte(unsigned long addr)
-@@ -278,6 +301,7 @@
+@@ -278,6 +301,7 @@ static void __init ts72xx_init_machine(void)
  {
        ep93xx_init_devices();
        ts72xx_register_flash();
@@ -61,11 +66,11 @@ Index: linux-2.6.34/arch/arm/mach-ep93xx/ts72xx.c
        platform_device_register(&ts72xx_rtc_device);
        platform_device_register(&ts72xx_wdt_device);
  
-Index: linux-2.6.34/drivers/block/Kconfig
-===================================================================
---- linux-2.6.34.orig/drivers/block/Kconfig    2010-05-16 23:17:36.000000000 +0200
-+++ linux-2.6.34/drivers/block/Kconfig 2010-10-13 23:55:37.000000000 +0200
-@@ -488,4 +488,11 @@
+diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
+index 77bfce5..fc8fae5 100644
+--- a/drivers/block/Kconfig
++++ b/drivers/block/Kconfig
+@@ -488,4 +488,11 @@ config BLK_DEV_HD
  
          If unsure, say N.
  
@@ -77,11 +82,11 @@ Index: linux-2.6.34/drivers/block/Kconfig
 +        TS-7260 SBC.
 +
  endif # BLK_DEV
-Index: linux-2.6.34/drivers/block/Makefile
-===================================================================
---- linux-2.6.34.orig/drivers/block/Makefile   2010-05-16 23:17:36.000000000 +0200
-+++ linux-2.6.34/drivers/block/Makefile        2010-10-13 23:55:37.000000000 +0200
-@@ -34,8 +34,10 @@
+diff --git a/drivers/block/Makefile b/drivers/block/Makefile
+index aff5ac9..a4d0579 100644
+--- a/drivers/block/Makefile
++++ b/drivers/block/Makefile
+@@ -34,8 +34,10 @@ obj-$(CONFIG_VIODASD)               += viodasd.o
  obj-$(CONFIG_BLK_DEV_SX8)     += sx8.o
  obj-$(CONFIG_BLK_DEV_UB)      += ub.o
  obj-$(CONFIG_BLK_DEV_HD)      += hd.o
@@ -92,10 +97,11 @@ Index: linux-2.6.34/drivers/block/Makefile
  
  swim_mod-objs := swim.o swim_asm.o
 +ts72xx_sdcard-objs    := tssdcard.o sdcore2.o
-Index: linux-2.6.34/drivers/block/sdcore2.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.34/drivers/block/sdcore2.c       2010-10-13 23:55:37.000000000 +0200
+diff --git a/drivers/block/sdcore2.c b/drivers/block/sdcore2.c
+new file mode 100644
+index 0000000..6dadee1
+--- /dev/null
++++ b/drivers/block/sdcore2.c
 @@ -0,0 +1,2391 @@
 +/*
 + * Copyright (c) 2006-2009, Technologic Systems
@@ -2488,10 +2494,11 @@ Index: linux-2.6.34/drivers/block/sdcore2.c
 +      return 0;
 +}
 +#endif
-Index: linux-2.6.34/drivers/block/sdcore2.h
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.34/drivers/block/sdcore2.h       2010-10-13 23:55:37.000000000 +0200
+diff --git a/drivers/block/sdcore2.h b/drivers/block/sdcore2.h
+new file mode 100644
+index 0000000..38d5b96
+--- /dev/null
++++ b/drivers/block/sdcore2.h
 @@ -0,0 +1,372 @@
 +/*
 + * Copyright (c) 2006-2008, Technologic Systems
@@ -2865,10 +2872,11 @@ Index: linux-2.6.34/drivers/block/sdcore2.h
 +            unsigned char *);
 +
 +#endif
-Index: linux-2.6.34/drivers/block/tssdcard.c
-===================================================================
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.34/drivers/block/tssdcard.c      2010-10-13 23:55:37.000000000 +0200
+diff --git a/drivers/block/tssdcard.c b/drivers/block/tssdcard.c
+new file mode 100644
+index 0000000..c76d9a7
+--- /dev/null
++++ b/drivers/block/tssdcard.c
 @@ -0,0 +1,415 @@
 +/*
 + * TS SD Card device driver
@@ -3285,3 +3293,6 @@ Index: linux-2.6.34/drivers/block/tssdcard.c
 +MODULE_LICENSE("GPL");
 +MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK0_MAJOR);
 +MODULE_ALIAS("tssd");
+-- 
+1.7.0.4
+
index ce73a86..aa4e4cd 100644 (file)
@@ -1,7 +1,10 @@
-From 45a115b858cf82a35e51a7541a3f83c4dd4e08ea Mon Sep 17 00:00:00 2001
+From 366781f33629fd2dff00c009a1519c7ccb1668f6 Mon Sep 17 00:00:00 2001
 From: Matthieu Crapet <mcrapet@gmail.com>
 Date: Sun, 20 Jun 2010 11:31:22 +0200
-Subject: [PATCH 16/18] ts72xx_nand_flash
+Subject: [PATCH 16/25] ts72xx_nand_flash
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
 This is Hartley Sweeten's patch:
 Update the ts72xx platform's nand driver support.
@@ -10,13 +13,15 @@ It's available since 2.6.35-rc1
 
 Only one concern here, it's the size of TS72XX_BOOTROM_PART_SIZE,
 defined here to SZ_16K but can be SZ_128K for boards with 128mb flash.
+
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
 ---
  arch/arm/mach-ep93xx/ts72xx.c |  186 ++++++++++++++++++++++++++++-------------
  drivers/mtd/nand/Kconfig      |    2 +-
  2 files changed, 129 insertions(+), 59 deletions(-)
 
 diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c
-index 7fd8f80..475559e 100644
+index ec2ab8e..1c7baba 100644
 --- a/arch/arm/mach-ep93xx/ts72xx.c
 +++ b/arch/arm/mach-ep93xx/ts72xx.c
 @@ -10,6 +10,8 @@
@@ -266,5 +271,5 @@ index 42e5ea4..952ae85 100644
        help
          Support for NAND flash on Technologic Systems TS-7250 platform.
 -- 
-1.7.1
+1.7.0.4
 
index bba5516..68b70ac 100644 (file)
@@ -1,7 +1,10 @@
-From be8b82a083b6df32a1016b327730ce16be7c2b24 Mon Sep 17 00:00:00 2001
+From 28193e416e604f321105637dde53e408b75fbcd8 Mon Sep 17 00:00:00 2001
 From: Matthieu Crapet <mcrapet@gmail.com>
 Date: Tue, 22 Jun 2010 11:21:05 +0200
-Subject: [PATCH 17/18] ep93xx_spi
+Subject: [PATCH 17/25] ep93xx_spi
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
 Include Mika Westerberg's driver:
 
@@ -13,6 +16,8 @@ http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=4fec
 
 spi/ep93xx: implemented driver for Cirrus EP93xx SPI controller:
 http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=011f23a3c2f20ae15b7664d3942493af107fe39b
+
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
 ---
  Documentation/spi/ep93xx_spi                   |   95 +++
  arch/arm/mach-ep93xx/clock.c                   |   13 +
@@ -1308,5 +1313,5 @@ index 0000000..0ba35df
 +MODULE_LICENSE("GPL");
 +MODULE_ALIAS("platform:ep93xx-spi");
 -- 
-1.7.1
+1.7.0.4
 
index cbc5a65..834176f 100644 (file)
@@ -1,9 +1,14 @@
-From 314f5d55f44d63c4ff418260580b93727eee00dc Mon Sep 17 00:00:00 2001
+From 42f34f87ef137187464b30f85953823ac445a47c Mon Sep 17 00:00:00 2001
 From: Matthieu Crapet <mcrapet@gmail.com>
 Date: Tue, 22 Jun 2010 15:48:27 +0200
-Subject: [PATCH 18/18] ts72xx_spi_tmp124
+Subject: [PATCH 18/25] ts72xx_spi_tmp124
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
 
 It's an option. A 3-wire spi temperature sensor can be populated on TS-72XX sbc.
+
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
 ---
  arch/arm/mach-ep93xx/ts72xx.c |   61 ++++++++++++++++
  drivers/spi/Kconfig           |    7 ++
@@ -13,7 +18,7 @@ It's an option. A 3-wire spi temperature sensor can be populated on TS-72XX sbc.
  create mode 100644 drivers/spi/tmp124.c
 
 diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c
-index 475559e..bf3a666 100644
+index 1c7baba..22e5e53 100644
 --- a/arch/arm/mach-ep93xx/ts72xx.c
 +++ b/arch/arm/mach-ep93xx/ts72xx.c
 @@ -23,7 +23,9 @@
@@ -100,7 +105,7 @@ index 475559e..bf3a666 100644
                platform_device_register(&ts72xx_max197_device);
        }
 diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
-index 2b2f4c3..9f40a43 100644
+index 2b2f4c3..3507bf1 100644
 --- a/drivers/spi/Kconfig
 +++ b/drivers/spi/Kconfig
 @@ -372,6 +372,13 @@ config SPI_TLE62X0
@@ -294,5 +299,5 @@ index 0000000..e41ec8c
 +MODULE_ALIAS("spi:tmp124");
 +MODULE_VERSION("0.2");
 -- 
-1.7.1
+1.7.0.4
 
diff --git a/recipes/linux/linux-2.6.34/ts72xx/0019-ts72xx-use-CPLD-watchdog-for-reset.patch b/recipes/linux/linux-2.6.34/ts72xx/0019-ts72xx-use-CPLD-watchdog-for-reset.patch
new file mode 100644 (file)
index 0000000..3fe3f67
--- /dev/null
@@ -0,0 +1,53 @@
+From 4d8e43e5ed0cda37031d889eff1ce3d4835df351 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
+Date: Thu, 21 Oct 2010 20:00:49 +0200
+Subject: [PATCH 19/25] ts72xx: use CPLD watchdog for reset
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
+---
+ arch/arm/mach-ep93xx/include/mach/system.h |   13 +++++++++++++
+ 1 files changed, 13 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-ep93xx/include/mach/system.h b/arch/arm/mach-ep93xx/include/mach/system.h
+index 6d661fe..b657a9a 100644
+--- a/arch/arm/mach-ep93xx/include/mach/system.h
++++ b/arch/arm/mach-ep93xx/include/mach/system.h
+@@ -3,6 +3,10 @@
+  */
+ #include <mach/hardware.h>
++#ifdef CONFIG_MACH_TS72XX
++#include <linux/io.h>
++#include <mach/ts72xx.h>
++#endif
+ static inline void arch_idle(void)
+ {
+@@ -13,11 +17,20 @@ static inline void arch_reset(char mode, const char *cmd)
+ {
+       local_irq_disable();
++#ifdef CONFIG_MACH_TS72XX
++      /* It's more reliable to use CPLD watchdog to perform reset */
++      if (board_is_ts7200() || board_is_ts7250() || board_is_ts7260() ||
++          board_is_ts7300() || board_is_ts7400()) {
++              __raw_writeb(0x5, TS72XX_WDT_FEED_PHYS_BASE);
++              __raw_writeb(0x1, TS72XX_WDT_CONTROL_PHYS_BASE);
++      }
++#else
+       /*
+        * Set then clear the SWRST bit to initiate a software reset
+        */
+       ep93xx_devcfg_set_bits(EP93XX_SYSCON_DEVCFG_SWRST);
+       ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_SWRST);
++#endif
+       while (1)
+               ;
+-- 
+1.7.0.4
+
diff --git a/recipes/linux/linux-2.6.34/ts72xx/0020-ethoc-ts7300-fixes.patch b/recipes/linux/linux-2.6.34/ts72xx/0020-ethoc-ts7300-fixes.patch
new file mode 100644 (file)
index 0000000..fdf11b8
--- /dev/null
@@ -0,0 +1,217 @@
+From f209c092df80c68231336072f0fc21f7f57a799d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
+Date: Thu, 21 Oct 2010 11:54:27 +0200
+Subject: [PATCH 20/25] ethoc: ts7300 fixes
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Ian Thompson <ian.thompson@pgs.com>
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
+---
+ drivers/net/ethoc.c |   73 +++++++++++++++++++++++++++-----------------------
+ 1 files changed, 39 insertions(+), 34 deletions(-)
+
+diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c
+index a8d9250..f84d95a 100644
+--- a/drivers/net/ethoc.c
++++ b/drivers/net/ethoc.c
+@@ -21,7 +21,11 @@
+ #include <linux/slab.h>
+ #include <net/ethoc.h>
++#ifndef CONFIG_MACH_TS72XX
+ static int buffer_size = 0x8000; /* 32 KBytes */
++#else
++static int buffer_size = 0x2000; /* 8 KBytes */
++#endif
+ module_param(buffer_size, int, 0);
+ MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size");
+@@ -495,6 +499,7 @@ static void ethoc_tx(struct net_device *dev)
+       ethoc_ack_irq(priv, INT_MASK_TX);
+       spin_unlock(&priv->lock);
++      return;
+ }
+ static irqreturn_t ethoc_interrupt(int irq, void *dev_id)
+@@ -512,11 +517,6 @@ static irqreturn_t ethoc_interrupt(int irq, void *dev_id)
+       ethoc_ack_irq(priv, pending);
+-      if (pending & INT_MASK_BUSY) {
+-              dev_err(&dev->dev, "packet dropped\n");
+-              priv->stats.rx_dropped++;
+-      }
+-
+       if (pending & INT_MASK_RX) {
+               if (napi_schedule_prep(&priv->napi))
+                       __napi_schedule(&priv->napi);
+@@ -580,10 +580,8 @@ static int ethoc_mdio_read(struct mii_bus *bus, int phy, int reg)
+                       ethoc_write(priv, MIICOMMAND, 0);
+                       return data;
+               }
+-
+               schedule();
+       }
+-
+       return -EBUSY;
+ }
+@@ -620,21 +618,12 @@ static int ethoc_mdio_probe(struct net_device *dev)
+ {
+       struct ethoc *priv = netdev_priv(dev);
+       struct phy_device *phy;
+-      int i;
++      int err;
+-      for (i = 0; i < PHY_MAX_ADDR; i++) {
+-              phy = priv->mdio->phy_map[i];
+-              if (phy) {
+-                      if (priv->phy_id != -1) {
+-                              /* attach to specified PHY */
+-                              if (priv->phy_id == phy->addr)
+-                                      break;
+-                      } else {
+-                              /* autoselect PHY if none was specified */
+-                              if (phy->addr != 0)
+-                                      break;
+-                      }
+-              }
++      if (priv->phy_id != -1) {
++              phy = priv->mdio->phy_map[priv->phy_id];
++      } else {
++              phy = phy_find_first(priv->mdio);
+       }
+       if (!phy) {
+@@ -642,14 +631,16 @@ static int ethoc_mdio_probe(struct net_device *dev)
+               return -ENXIO;
+       }
+-      phy = phy_connect(dev, dev_name(&phy->dev), ethoc_mdio_poll, 0,
++      err = phy_connect_direct(dev, phy, ethoc_mdio_poll, 0,
+                       PHY_INTERFACE_MODE_GMII);
+-      if (IS_ERR(phy)) {
++      if (err) {
+               dev_err(&dev->dev, "could not attach to PHY\n");
+-              return PTR_ERR(phy);
++              return err;
+       }
+       priv->phy = phy;
++      
++      
+       return 0;
+ }
+@@ -664,22 +655,21 @@ static int ethoc_open(struct net_device *dev)
+                       dev->name, dev);
+       if (ret)
+               return ret;
+-
+       /* calculate the number of TX/RX buffers, maximum 128 supported */
+       num_bd = min_t(unsigned int,
+               128, (dev->mem_end - dev->mem_start + 1) / ETHOC_BUFSIZ);
+       priv->num_tx = max(min_tx, num_bd / 4);
+       priv->num_rx = num_bd - priv->num_tx;
+       ethoc_write(priv, TX_BD_NUM, priv->num_tx);
+-
++      
+       ethoc_init_ring(priv);
+       ethoc_reset(priv);
+-
++      
+       if (netif_queue_stopped(dev)) {
+-              dev_dbg(&dev->dev, " resuming queue\n");
++              dev_err(&dev->dev, " resuming queue\n");
+               netif_wake_queue(dev);
+       } else {
+-              dev_dbg(&dev->dev, " starting queue\n");
++              dev_err(&dev->dev, " starting queue\n");
+               netif_start_queue(dev);
+       }
+@@ -690,7 +680,6 @@ static int ethoc_open(struct net_device *dev)
+               dev_info(&dev->dev, "I/O: %08lx Memory: %08lx-%08lx\n",
+                               dev->base_addr, dev->mem_start, dev->mem_end);
+       }
+-
+       return 0;
+ }
+@@ -804,6 +793,7 @@ static void ethoc_tx_timeout(struct net_device *dev)
+ {
+       struct ethoc *priv = netdev_priv(dev);
+       u32 pending = ethoc_read(priv, INT_SOURCE);
++      
+       if (likely(pending))
+               ethoc_interrupt(dev->irq, dev);
+ }
+@@ -837,10 +827,10 @@ static netdev_tx_t ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev)
+               bd.stat &= ~TX_BD_PAD;
+       dest = phys_to_virt(bd.addr);
+-      memcpy_toio(dest, skb->data, skb->len);
++      memcpy_toio(dest, skb->data, skb->len + 2);
+       bd.stat &= ~(TX_BD_STATS | TX_BD_LEN_MASK);
+-      bd.stat |= TX_BD_LEN(skb->len);
++      bd.stat |= TX_BD_LEN(skb->len + 2);
+       ethoc_write_bd(priv, entry, &bd);
+       bd.stat |= TX_BD_READY;
+@@ -980,9 +970,13 @@ static int ethoc_probe(struct platform_device *pdev)
+       if (pdev->dev.platform_data) {
+               struct ethoc_platform_data *pdata =
+                       (struct ethoc_platform_data *)pdev->dev.platform_data;
++              
+               memcpy(netdev->dev_addr, pdata->hwaddr, IFHWADDRLEN);
+               priv->phy_id = pdata->phy_id;
+       }
++      else {
++              priv->phy_id = 1;
++      }
+       /* Check that the given MAC address is valid. If it isn't, read the
+        * current MAC from the controller. */
+@@ -993,7 +987,17 @@ static int ethoc_probe(struct platform_device *pdev)
+        * program a random one. */
+       if (!is_valid_ether_addr(netdev->dev_addr))
+               random_ether_addr(netdev->dev_addr);
+-
++      /* take this out for more general usage */
++      netdev->dev_addr[0] = 0x00;
++      netdev->dev_addr[1] = 0x88;
++      netdev->dev_addr[2] = 0x88;
++      netdev->dev_addr[3] = 0x88;
++      netdev->dev_addr[4] = 0x88;
++      netdev->dev_addr[5] = 0x01;
++      
++      printk("ethoc: setting MAC address to %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",netdev->dev_addr[0],
++                      netdev->dev_addr[1],netdev->dev_addr[2],netdev->dev_addr[3],netdev->dev_addr[4],
++                      netdev->dev_addr[5]); 
+       ethoc_set_mac_address(netdev, netdev->dev_addr);
+       /* register MII bus */
+@@ -1028,7 +1032,7 @@ static int ethoc_probe(struct platform_device *pdev)
+       ret = ethoc_mdio_probe(netdev);
+       if (ret) {
+-              dev_err(&netdev->dev, "failed to probe MDIO bus\n");
++              dev_err(&netdev->dev, "MDIO bus probe failed\n");
+               goto error;
+       }
+@@ -1125,6 +1129,7 @@ static struct platform_driver ethoc_driver = {
+ static int __init ethoc_init(void)
+ {
++      printk("ethoc driver version 0.0.1\n");
+       return platform_driver_register(&ethoc_driver);
+ }
+-- 
+1.7.0.4
+
diff --git a/recipes/linux/linux-2.6.34/ts72xx/0021-ts7300-add-ethernet-support.patch b/recipes/linux/linux-2.6.34/ts72xx/0021-ts7300-add-ethernet-support.patch
new file mode 100644 (file)
index 0000000..75cfa78
--- /dev/null
@@ -0,0 +1,87 @@
+From 9aa429c0ee97d3a3c004ff9b94ea1126f58e3eec Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
+Date: Thu, 21 Oct 2010 11:51:44 +0200
+Subject: [PATCH 21/25] ts7300: add ethernet support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Ian Thompson <ian.thompson@pgs.com>
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
+---
+ arch/arm/mach-ep93xx/include/mach/ts72xx.h |    3 ++
+ arch/arm/mach-ep93xx/ts72xx.c              |   30 ++++++++++++++++++++++++++++
+ 2 files changed, 33 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-ep93xx/include/mach/ts72xx.h b/arch/arm/mach-ep93xx/include/mach/ts72xx.h
+index 71c80fd..a10c45a 100644
+--- a/arch/arm/mach-ep93xx/include/mach/ts72xx.h
++++ b/arch/arm/mach-ep93xx/include/mach/ts72xx.h
+@@ -152,6 +152,9 @@
+ #define TS7260_SDCARD_PHYS_BASE               0x13000000
++#define  TS7300_ETHOC_PHYS_BASE               0x72100000
++#define  TS7300_ETHOC_IO_BASE                         0x72102000
++
+ #ifndef __ASSEMBLY__
+ static inline int board_is_ts7200(void)
+diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c
+index 22e5e53..32fb84f 100644
+--- a/arch/arm/mach-ep93xx/ts72xx.c
++++ b/arch/arm/mach-ep93xx/ts72xx.c
+@@ -28,6 +28,7 @@
+ #include <mach/ep93xx_spi.h>
+ #include <mach/hardware.h>
+ #include <mach/ts72xx.h>
++#include <mach/irqs.h>
+ #include <asm/mach-types.h>
+ #include <asm/mach/map.h>
+@@ -354,6 +355,32 @@ static struct ep93xx_eth_data ts72xx_eth_data = {
+       .phy_id         = 1,
+ };
++static struct resource ts7300_ethoc_resources[] = {
++      [0] = {
++              .start  = TS7300_ETHOC_IO_BASE,
++              .end    = TS7300_ETHOC_IO_BASE + 0x3FF,
++              .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = TS7300_ETHOC_PHYS_BASE,
++              .end    = TS7300_ETHOC_PHYS_BASE + 0x1FFF,
++              .flags  = IORESOURCE_MEM,
++      },      
++      [2] = {
++              .start  = IRQ_EP93XX_EXT3,
++              .end    = IRQ_EP93XX_EXT3,
++              .flags  = IORESOURCE_IRQ,
++      },
++};
++
++static struct platform_device ts7300_ethoc_device = {
++      .name           = "ethoc",
++      .id             = 0,
++      .num_resources  = 3,
++      .resource       = ts7300_ethoc_resources,
++};
++
++
+ /*************************************************************************
+  * I2C (make access through TS-72XX "DIO" 2x8 header)
+  *************************************************************************/
+@@ -445,6 +472,9 @@ static void __init ts72xx_init_machine(void)
+               platform_device_register(&ts72xx_max197_device);
+       }
++      if (board_is_ts7300())
++              platform_device_register(&ts7300_ethoc_device);
++
+       /* PWM1 is DIO_6 on TS-72xx header */
+       ep93xx_register_pwm(0, 1);
+ }
+-- 
+1.7.0.4
+
@@ -1,7 +1,7 @@
-From 0e901bed4e053098f1c8411dcbf21324b7f61775 Mon Sep 17 00:00:00 2001
+From 6b9e31a908ff68610a2703dcb44f991a43fd9be5 Mon Sep 17 00:00:00 2001
 From: Mika Westerberg <mika.westerberg@iki.fi>
 Date: Sun, 29 Aug 2010 13:53:14 +0300
-Subject: [PATCH] watchdog: ts72xx_wdt: disable watchdog at probe
+Subject: [PATCH 22/25] watchdog: ts72xx_wdt: disable watchdog at probe
 MIME-Version: 1.0
 Content-Type: text/plain; charset=UTF-8
 Content-Transfer-Encoding: 8bit
diff --git a/recipes/linux/linux-2.6.34/ts72xx/0024-TS-72XX-LCD-console-driver.patch b/recipes/linux/linux-2.6.34/ts72xx/0024-TS-72XX-LCD-console-driver.patch
new file mode 100644 (file)
index 0000000..c371aa7
--- /dev/null
@@ -0,0 +1,528 @@
+From 13bd55a4dff8ad5cf4113e08258046ff9c647005 Mon Sep 17 00:00:00 2001
+From: Matthieu Crapet <mcrapet@gmail.com>
+Date: Sun, 4 Jan 2009 13:01:07 +0100
+Subject: [PATCH 24/25] TS-72XX LCD console driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
+---
+ arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |    4 +
+ drivers/video/console/Kconfig                   |   21 +
+ drivers/video/console/Makefile                  |    2 +
+ drivers/video/console/ts72xx_con.c              |  442 +++++++++++++++++++++++
+ 4 files changed, 469 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/video/console/ts72xx_con.c
+
+diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
+index f100f7f..a074f79 100644
+--- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
++++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
+@@ -110,6 +110,10 @@
+ #define EP93XX_GPIO_B_INT_DEBOUNCE    EP93XX_GPIO_REG(0xc4)
+ #define EP93XX_GPIO_EEDRIVE           EP93XX_GPIO_REG(0xc8)
++/* ts72xx lcd console driver quick "hack" */
++#define EP93XX_GPIO_A_DATA            EP93XX_GPIO_REG(0x00)
++#define EP93XX_GPIO_A_DIRECTION               EP93XX_GPIO_REG(0x10)
++
+ #define EP93XX_AAC_BASE                       EP93XX_APB_IOMEM(0x00080000)
+ #define EP93XX_SPI_PHYS_BASE          (EP93XX_APB_PHYS_BASE + 0x000a0000)
+diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
+index 8e8f18d..88149ee 100644
+--- a/drivers/video/console/Kconfig
++++ b/drivers/video/console/Kconfig
+@@ -89,6 +89,27 @@ config DUMMY_CONSOLE_ROWS
+           The default value is 64, which should fit a 1280x1024 monitor.
+           Select 25 if you use a 640x480 resolution by default.
++config TS72XX_CONSOLE
++      tristate "TS-72xx text LCD console"
++      depends on ARCH_EP93XX && MACH_TS72XX
++      help
++        Say Y to build a console driver for TS-72xx LCD (2x7) header.
++        LCD display must be compatible with HD44780 controller.
++
++config TS72XX_CONSOLE_COLUMNS
++        int "Initial number of console screen columns"
++        depends on TS72XX_CONSOLE
++        default "20"
++        help
++          Dependant to your text LCD, 16 or 20 are legacy values.
++
++config TS72XX_CONSOLE_ROWS
++        int "Initial number of console screen rows"
++        depends on TS72XX_CONSOLE
++        default "4"
++        help
++          Dependant to your text LCD, 2 or 4 are legacy values.
++
+ config FRAMEBUFFER_CONSOLE
+       tristate "Framebuffer Console support"
+       depends on FB
+diff --git a/drivers/video/console/Makefile b/drivers/video/console/Makefile
+index a862e91..e0f9269 100644
+--- a/drivers/video/console/Makefile
++++ b/drivers/video/console/Makefile
+@@ -25,6 +25,8 @@ obj-$(CONFIG_SGI_NEWPORT_CONSOLE) += newport_con.o font.o
+ obj-$(CONFIG_STI_CONSOLE)         += sticon.o sticore.o font.o
+ obj-$(CONFIG_VGA_CONSOLE)         += vgacon.o
+ obj-$(CONFIG_MDA_CONSOLE)         += mdacon.o
++obj-$(CONFIG_TS72XX_CONSOLE)      += ts72xx_con.o
++
+ obj-$(CONFIG_FRAMEBUFFER_CONSOLE) += fbcon.o bitblit.o font.o softcursor.o
+ ifeq ($(CONFIG_FB_TILEBLITTING),y)
+ obj-$(CONFIG_FRAMEBUFFER_CONSOLE)     += tileblit.o
+diff --git a/drivers/video/console/ts72xx_con.c b/drivers/video/console/ts72xx_con.c
+new file mode 100644
+index 0000000..a6ac61d
+--- /dev/null
++++ b/drivers/video/console/ts72xx_con.c
+@@ -0,0 +1,442 @@
++/*
++ *  TS-72XX lcd console driver for Technologic Systems boards.
++ *
++ * (c) Copyright 2008  Matthieu Crapet <mcrapet@gmail.com>
++ * Based on linux/drivers/video/console/dummycon.c
++ * Thanks to Jim Jackson (lcdd-0.2beta)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ *
++ * Note: Port H (LCD_EN, LCD_RS, LCD_WR) uses the new generic GPIO API.
++ *       Port A is used manually used. To fix in future.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/console.h>
++#include <linux/vt_kern.h>
++#include <linux/delay.h>
++#include <mach/hardware.h>
++#include <mach/gpio.h>
++#include <asm/io.h>
++
++#define DRV_VERSION "0.3"
++#define PFX "ts72xx_con: "
++
++#define LCD_COLUMNS  CONFIG_TS72XX_CONSOLE_COLUMNS
++#define LCD_ROWS     CONFIG_TS72XX_CONSOLE_ROWS
++
++/* HD44780 instruction set */
++#define CMD_CLEAR                                        (0x01)
++#define CMD_CURSOR_HOME                                  (0x02)
++#define CMD_ENTRY_MODE(cursor_dir, display_shift)        (0x04|(2*cursor_dir)|display_shift)
++#define CMD_DISPLAY_ONOFF(dis_on, cur_on, cur_blink_on)  (0x08|(4*dis_on)|(2*cur_on)|cur_blink_on)
++#define CMD_FUNCTION_SET(intf_8bit, n, f)                (0x20|(16*intf_8bit)|(8*n)|(4*f))
++#define CMD_DDRAM_ADDR(a)                                (0x80|(a))
++
++/* Port H, bit 3:5 */
++#define LCD_EN   EP93XX_GPIO_LINE_H(3)
++#define LCD_RS   EP93XX_GPIO_LINE_H(4)
++#define LCD_WR   EP93XX_GPIO_LINE_H(5)
++
++static struct gpio lcd_gpios[] = {
++      { LCD_EN, GPIOF_OUT_INIT_LOW, "LCD enable" },
++      { LCD_RS, GPIOF_OUT_INIT_LOW, "LCD data" },
++      { LCD_WR, GPIOF_OUT_INIT_LOW, "LCD r/w" },
++};
++
++/* Timings */
++#define SETUP_TIME   200
++#define ENABLE_TIME  800
++#define HOLD_TIME    200
++
++void hd44780_delay(int i)
++{
++      ndelay(i);
++}
++
++/* Prototypes */
++static void hd44780_wait(void);
++static void hd44780_send_data(unsigned char data);
++static void hd44780_send_command(unsigned char command);
++static void hd44780_init(void);
++static void hd44780_deinit(void);
++static int hd44780_gotoxy(int x, int y);
++
++
++/* HD44780 controller */
++
++static void hd44780_wait(void)
++{
++  int i;
++  int b = 0;
++  unsigned char c;
++
++  __raw_writeb(0x00, EP93XX_GPIO_A_DIRECTION);   // bus input
++  gpio_set_value(LCD_RS, 0);                     // low for control registers
++  gpio_set_value(LCD_WR, 1);                     // read command
++
++  do {
++    i = SETUP_TIME;
++    hd44780_delay(i);
++
++    gpio_set_value(LCD_EN, 1);
++
++    i = ENABLE_TIME;
++    hd44780_delay(i);
++
++    c = __raw_readb(EP93XX_GPIO_A_DATA);
++    gpio_set_value(LCD_EN, 0);
++
++    b++;
++  } while (c & 0x80); // busy flag
++
++  i = HOLD_TIME;
++  hd44780_delay(i);
++}
++
++
++static void hd44780_send_data(unsigned char data)
++{
++  int i;
++
++  __raw_writeb(0xFF, EP93XX_GPIO_A_DIRECTION);   // bus output
++  gpio_set_value(LCD_RS, 1);                     // high for data
++  gpio_set_value(LCD_WR, 0);                     // write data
++
++  i = SETUP_TIME;
++  hd44780_delay(i);
++
++  __raw_writeb(data, EP93XX_GPIO_A_DATA);
++  gpio_set_value(LCD_EN, 1);
++
++  i = ENABLE_TIME;
++  hd44780_delay(i);
++
++  gpio_set_value(LCD_EN, 0);
++
++  i = HOLD_TIME;
++  hd44780_delay(i);
++}
++
++
++static void hd44780_send_command(unsigned char command)
++{
++  int i;
++
++  __raw_writeb(0xFF, EP93XX_GPIO_A_DIRECTION);   // bus output
++  gpio_set_value(LCD_RS, 0);                     // low for control registers
++  gpio_set_value(LCD_WR, 0);                     // write command
++
++  i = SETUP_TIME;
++  hd44780_delay(i);
++
++  __raw_writeb(command, EP93XX_GPIO_A_DATA);
++  gpio_set_value(LCD_EN, 1);
++
++  i = ENABLE_TIME;
++  hd44780_delay(i);
++
++  gpio_set_value(LCD_EN, 0);
++
++  i = HOLD_TIME;
++  hd44780_delay(i);
++}
++
++static void hd44780_deinit()
++{
++      gpio_free_array(lcd_gpios, ARRAY_SIZE(lcd_gpios));
++}
++
++static void hd44780_init(void)
++{
++      int i;
++      int err;
++
++      err = gpio_request_array(lcd_gpios, ARRAY_SIZE(lcd_gpios));
++      if (err) {
++              printk(KERN_ERR PFX "error while requesting GPIO pins\n");
++              return;
++      }
++
++      /* Port A (8 bits) is data bus */
++      __raw_writeb(0x00, EP93XX_GPIO_A_DATA);
++      __raw_writeb(0x00, EP93XX_GPIO_A_DIRECTION);
++
++      /* 8-bit mode, double line, 5x7 dot character format */
++      hd44780_send_command(CMD_FUNCTION_SET(1,1,1));
++      i = 5000;
++      hd44780_delay(i);
++
++      /* Display on and blink cursor on */
++      hd44780_send_command(CMD_DISPLAY_ONOFF(1,1,1));
++      hd44780_wait();
++
++      /* Cursor in increment position and shift is invisible */
++      hd44780_send_command(CMD_ENTRY_MODE(0,0));
++      hd44780_wait();
++
++      /* Clean display and return cursor to home position */
++      hd44780_send_command(CMD_CLEAR);
++      hd44780_wait();
++}
++
++
++static int hd44780_gotoxy(int x, int y)
++{
++  const unsigned char lines[4] = { 0x00, 0x40, 0x14, 0x54 };
++
++  if ((x == 0) && (y == 0)) {
++    hd44780_send_command(CMD_CURSOR_HOME);
++    hd44780_wait();
++  } else if (y < 4) {
++    hd44780_send_command(CMD_DDRAM_ADDR(lines[y]+x));
++    hd44780_wait();
++  }
++
++  return 0;
++}
++
++
++/* Console operation functions */
++
++static const char *lcdcon_startup(void)
++{
++  return "ts72xx lcd console";
++}
++
++
++static void lcdcon_init(struct vc_data *vc, int init)
++{
++  hd44780_init();
++
++  vc->vc_can_do_color = 0;
++  vc->vc_video_erase_char = 0x20;
++
++  if (init) {
++    vc->vc_cols = LCD_COLUMNS;
++    vc->vc_rows = LCD_ROWS;
++  } else
++    vc_resize(vc, LCD_COLUMNS, LCD_ROWS);
++
++}
++
++
++static void lcdcon_deinit(struct vc_data *vc)
++{
++      hd44780_deinit();
++}
++
++
++static void lcdcon_clear(struct vc_data *vc, int sy, int sx,
++    int height, int width)
++{
++  int i, j;
++
++  if (!height || !width)
++    return;
++
++  for (i = 0; i < height; i++) {
++    hd44780_gotoxy(sx, sy + i);
++    for (j = 0; j < width; j++) {
++      hd44780_send_data((unsigned char)vc->vc_video_erase_char);
++      hd44780_wait();
++    }
++  }
++
++}
++
++
++static int lcdcon_blank(struct vc_data *vc, int blank, int mode_switch)
++{
++  unsigned char c;
++
++  if (blank == 0) {
++    c = CMD_DISPLAY_ONOFF(1,1,1);    /* Display on */
++  } else {
++    c = CMD_DISPLAY_ONOFF(0,1,1);    /* Display off */
++  }
++
++  hd44780_send_command(c);
++  hd44780_wait();
++
++  return 1;
++}
++
++
++static int lcdcon_set_palette(struct vc_data *vc, unsigned char *table)
++{
++  return -EINVAL;
++}
++
++
++static void lcdcon_putc(struct vc_data *vc, int c, int y, int x)
++{
++  if (vc->vc_mode != KD_TEXT)
++    return;
++
++  hd44780_gotoxy(x, y);
++  hd44780_send_data((unsigned char)c);
++  hd44780_wait();
++}
++
++
++static void lcdcon_putcs(struct vc_data *vc, const unsigned short *s,
++    int count, int y, int x)
++{
++  if (vc->vc_mode != KD_TEXT)
++    return;
++
++  hd44780_gotoxy(x, y);
++  while (count--) {
++    hd44780_send_data((unsigned char)(*s));
++    hd44780_wait();
++    s++;
++  }
++
++}
++
++
++static void lcdcon_cursor(struct vc_data *vc, int mode)
++{
++  hd44780_gotoxy(vc->vc_x, vc->vc_y);
++
++  switch (mode) {
++    case CM_ERASE:
++      hd44780_send_command(CMD_DISPLAY_ONOFF(1,0,0)); // Cursor off
++      hd44780_wait();
++      break;
++
++    case CM_DRAW:
++      hd44780_send_command(CMD_DISPLAY_ONOFF(1,1,1)); // Cursor on, Blinking on
++      hd44780_wait();
++      break;
++
++    case CM_MOVE:
++      printk(KERN_NOTICE PFX "lcdcon_cursor CM_MOVE not implemented\n");
++      break;
++  }
++
++}
++
++
++static int lcdcon_scroll(struct vc_data *vc, int t, int b, int dir, int count)
++{
++  int i;
++
++  if (!count)
++    return 0;
++
++  /* Special case */
++  //if (t || b != vc->vc_rows)
++  // scroll area
++
++  switch (dir) {
++    case SM_UP:
++      if (count > vc->vc_rows)
++        count = vc->vc_rows;
++
++      for (i = 0; i < (vc->vc_rows - count); i++) {
++        lcdcon_putcs(vc, vc->vc_screenbuf + (vc->vc_y - i)*vc->vc_cols,
++            vc->vc_cols, vc->vc_y - i -1, 0);
++      }
++
++      /* Clear last line */
++      hd44780_gotoxy(0, vc->vc_y);
++      for (i = 0; i < vc->vc_cols; i++) {
++        hd44780_send_data((unsigned char)vc->vc_video_erase_char);
++        hd44780_wait();
++      }
++      break;
++
++    case SM_DOWN:
++      printk(KERN_NOTICE PFX "lcdcon_scroll DOWN (t=%d b=%d count=%d) not implemtented\n", t,b,count);
++      break;
++  }
++
++  return 0;
++}
++
++
++static void lcdcon_bmove(struct vc_data *vc, int sy, int sx,
++    int dy, int dx, int height, int width)
++{
++  int i, j;
++
++  if (!height || !width)
++    return;
++
++  for (i = 0; i < height; i++) {
++    hd44780_gotoxy(dx, dy + i);
++    for (j = 0; j < width; j++) {
++      hd44780_send_data((unsigned char)(*(vc->vc_screenbuf +
++              (sy+i)*vc->vc_cols + (sx+j) )));
++      hd44780_wait();
++    }
++  }
++}
++
++
++static int lcdcon_dummy(void)
++{
++  return 0;
++}
++
++#define DUMMY (void *)lcdcon_dummy
++
++
++/* Main structure */
++const struct consw ts72xx_lcd_con = {
++  .owner =    THIS_MODULE,
++  .con_startup = lcdcon_startup,
++  .con_init    = lcdcon_init,
++  .con_deinit  = lcdcon_deinit,
++  .con_clear   = lcdcon_clear,
++  .con_putc    = lcdcon_putc,
++  .con_putcs   = lcdcon_putcs,
++  .con_cursor  = lcdcon_cursor,
++  .con_scroll  = lcdcon_scroll,
++  .con_bmove   = lcdcon_bmove,
++  .con_switch  = DUMMY,
++  .con_blank   = lcdcon_blank,
++
++  /* We cannot change color, fonts on character LCD */
++  .con_font_set     = DUMMY,
++  .con_font_get     = DUMMY,
++  .con_font_default = DUMMY,
++  .con_font_copy    = DUMMY,
++  .con_set_palette  = lcdcon_set_palette,
++
++  //.con_scrolldelta   = lcdcon_scrolldelta,
++  //.con_set_origin    = DUMMY,
++  //.con_save_screen   = lcdcon_save_screen,
++  //.con_build_attr    = lcdcon_build_attr,
++  //.con_invert_region = lcdcon_invert_region,
++  //.con_screen_pos    = lcdcon_screen_pos,
++  //.con_getxy         = lcdcon_getxy,
++};
++
++/* Module functions */
++
++static int __init ts72xx_lcd_init(void)
++{
++  printk(KERN_NOTICE "TS-72xx lcd console driver v" DRV_VERSION " loaded\n");
++  return take_over_console(&ts72xx_lcd_con, 0, MAX_NR_CONSOLES-1, 1);
++}
++
++static void __exit ts72xx_lcd_exit(void)
++{
++  printk(KERN_NOTICE "TS-72xx lcd console driver v" DRV_VERSION " unloaded\n");
++  unregister_con_driver(&ts72xx_lcd_con);
++}
++
++MODULE_AUTHOR("Matthieu Crapet <mcrapet@gmail.com>");
++MODULE_DESCRIPTION("TS-72xx lcd console driver");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
++
++module_init(ts72xx_lcd_init);
++module_exit(ts72xx_lcd_exit);
+-- 
+1.7.0.4
+
diff --git a/recipes/linux/linux-2.6.34/ts72xx/0025-ts72xx-add-lcd-linux-driver.patch b/recipes/linux/linux-2.6.34/ts72xx/0025-ts72xx-add-lcd-linux-driver.patch
new file mode 100644 (file)
index 0000000..5ce9ae3
--- /dev/null
@@ -0,0 +1,4569 @@
+From 87e2d5376d291d792ea1f53cd700114e66c90d7a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
+Date: Sun, 7 Nov 2010 14:41:41 +0100
+Subject: [PATCH 25/25] ts72xx: add lcd-linux driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+- based on LCD-Linux v0.13.9 (latest stable release)
+- supports only hd44780 compatible display
+- LCD in 8-bit mode operation only (D0-D7) connected to LCD connector
+
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
+---
+ arch/arm/Kconfig                  |    2 +
+ drivers/Makefile                  |    1 +
+ drivers/lcd-linux/Config.in       |    8 +
+ drivers/lcd-linux/Kconfig         |   33 +
+ drivers/lcd-linux/Makefile        |    8 +
+ drivers/lcd-linux/cgram/default.h |   37 +
+ drivers/lcd-linux/cgram/swedish.h |   33 +
+ drivers/lcd-linux/charmap.h       |   79 +
+ drivers/lcd-linux/commands.h      |   77 +
+ drivers/lcd-linux/config.h        |   73 +
+ drivers/lcd-linux/hd44780.c       |  854 +++++++++++
+ drivers/lcd-linux/lcd-linux.c     | 3023 +++++++++++++++++++++++++++++++++++++
+ include/linux/hd44780.h           |   47 +
+ include/linux/lcd-linux.h         |  158 ++
+ 14 files changed, 4433 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/lcd-linux/Config.in
+ create mode 100644 drivers/lcd-linux/Kconfig
+ create mode 100644 drivers/lcd-linux/Makefile
+ create mode 100644 drivers/lcd-linux/cgram/default.h
+ create mode 100644 drivers/lcd-linux/cgram/swedish.h
+ create mode 100644 drivers/lcd-linux/charmap.h
+ create mode 100644 drivers/lcd-linux/commands.h
+ create mode 100644 drivers/lcd-linux/config.h
+ create mode 100644 drivers/lcd-linux/hd44780.c
+ create mode 100644 drivers/lcd-linux/lcd-linux.c
+ create mode 100644 include/linux/hd44780.h
+ create mode 100644 include/linux/lcd-linux.h
+
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index 0675f74..feb6b70 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -1664,6 +1664,8 @@ source "net/Kconfig"
+ source "drivers/Kconfig"
++source "drivers/lcd-linux/Kconfig"
++
+ source "fs/Kconfig"
+ source "arch/arm/Kconfig.debug"
+diff --git a/drivers/Makefile b/drivers/Makefile
+index f42a030..0dc8d3f 100644
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -113,3 +113,4 @@ obj-$(CONFIG_VLYNQ)                += vlynq/
+ obj-$(CONFIG_STAGING)         += staging/
+ obj-y                         += platform/
+ obj-y                         += ieee802154/
++obj-$(CONFIG_LCD_LINUX)               += lcd-linux/
+diff --git a/drivers/lcd-linux/Config.in b/drivers/lcd-linux/Config.in
+new file mode 100644
+index 0000000..4a38801
+--- /dev/null
++++ b/drivers/lcd-linux/Config.in
+@@ -0,0 +1,8 @@
++if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
++   mainmenu_option next_comment
++   comment 'LCD support'
++
++   tristate 'LCD-Linux layer' CONFIG_LCD_LINUX
++   dep_tristate '  HD44780 controller' CONFIG_LCD_HD44780 $CONFIG_LCD_LINUX
++   endmenu
++fi
+diff --git a/drivers/lcd-linux/Kconfig b/drivers/lcd-linux/Kconfig
+new file mode 100644
+index 0000000..a102fc5
+--- /dev/null
++++ b/drivers/lcd-linux/Kconfig
+@@ -0,0 +1,33 @@
++menu "LCD support"
++      depends on EXPERIMENTAL
++
++config LCD_LINUX
++      tristate "LCD-Linux layer"
++      default n
++      help
++        LCD-Linux provides an easy way to drive LCD displays under
++        Linux by creating a character which can be read or written.
++        It features complete VT102 emulation and recognizes
++        many escape sequences. If you want to use it you must also
++        choose an appropriate driver, otherwise it will not be
++        very useful. For more information see
++        http://lcd-linux.sourceforge.net/
++
++        To compile LCD-Linux as a module, choose M here:
++        the module will be called lcd-linux.
++
++config LCD_HD44780
++      tristate "HD44780 controller"
++      depends on LCD_LINUX && MACH_TS72XX
++      default n
++      help
++        This is a LCD-Linux driver for LCD displays based on the
++        Hitachi HD44780 (and compatible) controllers connected
++        to LCD port on the TS72xx boards.
++
++        To compile this driver as a module, choose M here:
++        the module will be called hd44780.
++
++        If unsure, say N.
++
++endmenu
+diff --git a/drivers/lcd-linux/Makefile b/drivers/lcd-linux/Makefile
+new file mode 100644
+index 0000000..079aa79
+--- /dev/null
++++ b/drivers/lcd-linux/Makefile
+@@ -0,0 +1,8 @@
++# $Id: Makefile-2.6,v 1.3 2006/12/13 15:53:00 mjona Exp $
++#
++# Standard Makefile to statically compile LCD-Linux into the kernel
++# Linux 2.6
++
++obj-$(CONFIG_LCD_LINUX)               += lcd-linux.o
++obj-$(CONFIG_LCD_HD44780)     += hd44780.o
++
+diff --git a/drivers/lcd-linux/cgram/default.h b/drivers/lcd-linux/cgram/default.h
+new file mode 100644
+index 0000000..635146a
+--- /dev/null
++++ b/drivers/lcd-linux/cgram/default.h
+@@ -0,0 +1,37 @@
++/* default.h
++ *
++ * $Id: default.h,v 1.1.1.1 2005/08/23 13:30:14 mjona Exp $
++ *
++ * Default user defined characters for lcdmod.
++ *
++ * Copyright (C) by Michael McLellan (mikey@cs.auckland.ac.nz)
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ *
++ */
++
++static void init_charmap(void)
++{
++}
++
++static unsigned char cg0[] = { 0x1f, 0x1f, 0x11, 0x0f, 0x11, 0x1e, 0x01, 0x1f };
++static unsigned char cg1[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f };
++static unsigned char cg2[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f };
++static unsigned char cg3[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f };
++static unsigned char cg4[] = { 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f };
++static unsigned char cg5[] = { 0x00, 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f };
++static unsigned char cg6[] = { 0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f };
++static unsigned char cg7[] = { 0x00, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f };
+diff --git a/drivers/lcd-linux/cgram/swedish.h b/drivers/lcd-linux/cgram/swedish.h
+new file mode 100644
+index 0000000..a92c31c
+--- /dev/null
++++ b/drivers/lcd-linux/cgram/swedish.h
+@@ -0,0 +1,33 @@
++/* swedish.h
++ *
++ * $Id: swedish.h,v 1.2 2006/12/12 16:04:03 mjona Exp $
++ *
++ * Swedish characters for lcdmod
++ *
++ * Thanks to Erik Zetterberg <mr.z@linux.se>
++ *
++ * Description: Adds support for the last three last letters in the
++ * swedish alphabet (a/A with ring above, a/A with diaeresis and o/O
++ * with diaeresis). And maps the location of where they should be
++ * according to the ISO-8859-1 character set to their location in CGRAM.
++ *
++ */
++
++static void init_charmap(void)
++{
++      charmap[ 0xe5 ] = 0;
++      charmap[ 0xe4 ] = 1;
++      charmap[ 0xf6 ] = 2;
++      charmap[ 0xc5 ] = 3;
++      charmap[ 0xc4 ] = 4;
++      charmap[ 0xd6 ] = 5;
++}
++
++static unsigned char cg0[] = { 0x04, 0x00, 0x0e, 0x01, 0x0f, 0x11, 0x0f, 0x00 };
++static unsigned char cg1[] = { 0x0a, 0x00, 0x0e, 0x01, 0x0f, 0x11, 0x0f, 0x00 };
++static unsigned char cg2[] = { 0x0a, 0x00, 0x0e, 0x11, 0x11, 0x11, 0x0e, 0x00 };
++static unsigned char cg3[] = { 0x04, 0x00, 0x0e, 0x11, 0x1f, 0x11, 0x11, 0x00 };
++static unsigned char cg4[] = { 0x0a, 0x00, 0x0e, 0x11, 0x1f, 0x11, 0x11, 0x00 };
++static unsigned char cg5[] = { 0x0a, 0x00, 0x0e, 0x11, 0x11, 0x11, 0x0e, 0x00 };
++static unsigned char cg6[] = { 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f };
++static unsigned char cg7[] = { 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f };
+diff --git a/drivers/lcd-linux/charmap.h b/drivers/lcd-linux/charmap.h
+new file mode 100644
+index 0000000..376b04d
+--- /dev/null
++++ b/drivers/lcd-linux/charmap.h
+@@ -0,0 +1,79 @@
++/* charmap.h
++ *
++ * $Id: charmap.h,v 1.1.1.1 2005/08/23 13:30:14 mjona Exp $
++ *
++ * Character mapping for HD44780 devices by Mark Haemmerling <mail@markh.de>.
++ *
++ * Translates ISO 8859-1 to HD44780 charset.
++ * HD44780 charset reference: http://markh.de/hd44780-charset.png
++ *
++ * Initial table taken from lcd.o Linux kernel driver by
++ * Nils Faerber <nilsf@users.sourceforge.net>. Thanks!
++ *
++ * This file is released under the GNU General Public License. Refer to the
++ * COPYING file distributed with this package.
++ *
++ * Following translations are being performed:
++ * - maps umlaut accent characters to the corresponding umlaut characters
++ * - maps other accent characters to the characters without accents
++ * - maps beta (=ringel-S), micro and Yen
++ *
++ * Alternative mappings:
++ * - #112 ("p") -> #240 (large "p"), orig. mapped -> #112
++ * - #113 ("q") -> #241 (large "q"), orig. mapped -> #113
++ *
++ * HD44780 misses backslash
++ *
++ */
++
++static unsigned char charmap[] = {
++
++/* 0 - 31 */
++  0,   1,   2,   3,   4,   5,   6,   7,
++  8,   9,  10,  11,  12,  13,  14,  15,
++ 16,  17,  18,  19,  20,  21,  22,  23,
++ 24,  25,  26,  27,  28,  29,  30,  31,
++
++/* 32 - 63 */
++ 32,  33,  34,  35,  36,  37,  38,  39,
++ 40,  41,  42,  43,  44,  45,  46,  47,
++ 48,  49,  50,  51,  52,  53,  54,  55,
++ 56,  57,  58,  59,  60,  61,  62,  63,
++
++/* 64 - 95 */
++ 64,  65,  66,  67,  68,  69,  70,  71,
++ 72,  73,  74,  75,  76,  77,  78,  79,
++ 80,  81,  82,  83,  84,  85,  86,  87,
++ 88,  89,  90,  91,  47,  93,  94,  95,
++
++/* 96 - 127 */
++ 96,  97,  98,  99, 100, 101, 102, 103,
++104, 105, 106, 107, 108, 109, 110, 111,
++112, 113, 114, 115, 116, 117, 118, 119,
++120, 121, 122, 123, 124, 125, 126, 127,
++
++/* 128 - 159 */
++128, 129, 130, 131, 132, 133, 134, 135,
++136, 137, 138, 139, 140, 141, 142, 143,
++144, 145, 146, 147, 148, 149, 150, 151,
++152, 153, 154, 155, 156, 157, 158, 159,
++
++/* 160 - 191 */
++160,  33, 236, 237, 164,  92, 124, 167,
++ 34, 169, 170, 171, 172, 173, 174, 175,
++223, 177, 178, 179,  39, 249, 247, 165,
++ 44, 185, 186, 187, 188, 189, 190,  63,
++
++/* 192 - 223 */
++ 65,  65,  65,  65, 225,  65,  65,  67,
++ 69,  69,  69,  69,  73,  73,  73,  73,
++ 68,  78,  79,  79,  79,  79, 239, 120,
++ 48,  85,  85,  85, 245,  89, 240, 226,
++
++/* 224 - 255 */
++ 97,  97,  97,  97, 225,  97,  97,  99,
++101, 101, 101, 101, 105, 105, 105, 105,
++111, 110, 111, 111, 111, 111, 239, 253,
++ 48, 117, 117, 117, 245, 121, 240, 255
++
++};
+diff --git a/drivers/lcd-linux/commands.h b/drivers/lcd-linux/commands.h
+new file mode 100644
+index 0000000..6567836
+--- /dev/null
++++ b/drivers/lcd-linux/commands.h
+@@ -0,0 +1,77 @@
++/* commands.h
++ *
++ * $Id: commands.h,v 1.2 2009/03/09 17:59:22 mjona Exp $
++ *
++ * LCD-Linux:
++ * Driver for HD44780 compatible displays connected to the parallel port.
++ *
++ * HD44780 commands.
++ *
++ * Copyright (C) 2004 - 2009  Mattia Jona-Lasinio (mjona@users.sourceforge.net)
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++#ifndef HD44780_COMMANDS_H
++#define HD44780_COMMANDS_H
++
++/*** HD44780 Command Set ***/
++
++/* Clear Display*/
++#define CLR_DISP      0x01    /* Clear entire display; cursor at row 0, column 0 */
++
++/* Return Home */
++#define       RET_HOME        0x02    /* Cursor at row 0, column 0; display content doesn't change */
++
++/* Entry Mode Set */
++#define ENTRY_MODE_SET        0x04
++#define DISP_SHIFT_ON (ENTRY_MODE_SET | 0x01)         /* Shift display, not cursor after data write */
++#define DISP_SHIFT_OFF        (ENTRY_MODE_SET | 0x00)         /* Shift cursor, not display after data write */
++#define CURS_INC      (ENTRY_MODE_SET | 0x02)         /* Shift on the right after data read/write */
++#define CURS_DEC      (ENTRY_MODE_SET | 0x00)         /* Shift on the left after data read/write */
++
++/* Display on/off Control */
++#define DISP_ONOFF_CNTR       0x08
++#define BLINK_ON      (DISP_ONOFF_CNTR | 0x01)        /* Cursor blinking on */
++#define BLINK_OFF     (DISP_ONOFF_CNTR | 0x00)        /* Cursor blinking off */
++#define CURS_ON               (DISP_ONOFF_CNTR | 0x02)        /* Display Cursor */
++#define CURS_OFF      (DISP_ONOFF_CNTR | 0x00)        /* Hide Cursor */
++#define DISP_ON               (DISP_ONOFF_CNTR | 0x04)        /* Turn on display updating */
++#define DISP_OFF      (DISP_ONOFF_CNTR | 0x00)        /* Freeze display content */
++
++/* Cursor or Display Shift */
++#define CURS_DISP_SHIFT       0x10
++#define SHIFT_RIGHT   (CURS_DISP_SHIFT | 0x04)        /* Shift on the right */
++#define SHIFT_LEFT    (CURS_DISP_SHIFT | 0x00)        /* Shift on the left */
++#define SHIFT_DISP    (CURS_DISP_SHIFT | 0x08)        /* Shift display */
++#define SHIFT_CURS    (CURS_DISP_SHIFT | 0x00)        /* Shift cursor */
++
++/* Function Set */
++#define FUNC_SET      0x20
++#define FONT_5X10     (FUNC_SET | 0x04)       /* Select 5x10 dots font */
++#define FONT_5X8      (FUNC_SET | 0x00)       /* Select 5x8 dots font */
++#define DISP_2_LINES  (FUNC_SET | 0x08)       /* Select 2 lines display (only 5x8 font allowed) */
++#define DISP_1_LINE   (FUNC_SET | 0x00)       /* Select 1 line display */
++#define BUS_8_BITS    (FUNC_SET | 0x10)       /* Set 8 data bits */
++#define BUS_4_BITS    (FUNC_SET | 0x00)       /* Set 4 data bits */
++
++/* Set CGRAM Address */
++#define CGRAM_IO      0x40    /* Base CGRAM address */
++
++/* Set DDRAM Address */
++#define DDRAM_IO      0x80    /* Base DDRAM address */
++
++#endif /* commands included */
+diff --git a/drivers/lcd-linux/config.h b/drivers/lcd-linux/config.h
+new file mode 100644
+index 0000000..face191
+--- /dev/null
++++ b/drivers/lcd-linux/config.h
+@@ -0,0 +1,73 @@
++/* config.h
++ *
++ * $Id: config.h,v 1.16 2009/09/27 21:27:03 mjona Exp $
++ *
++ * Configure file for LCD-Linux. Here you must specify your hardware setup and
++ * timings constants. The default values will probably be right for you.
++ *
++ * Copyright (C) 2005 - 2009  Mattia Jona-Lasinio (mjona@users.sourceforge.net)
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ *
++ */
++
++/* Setup the default user defined characters in CGRAM */
++#include "cgram/default.h"
++/* #include "cgram/swedish.h" */
++/* #include "cgram/cgram.h" */
++
++/* Don't modify the default timing constants
++ * unless you know what you are doing.
++ */
++
++/* In case of a 4 bit bus, indicate your
++ * wiring configuration for the data bits
++ *
++ * 0 -> D3, D2, D1, D0
++ * 1 -> D4, D3, D2, D1
++ * 2 -> D5, D4, D3, D2
++ * 3 -> D6, D5, D4, D3
++ * 4 -> D7, D6, D5, D4
++ */
++#define SETUP                 4
++
++#define HIGH_NIBBLE_WRITE(x)  (((x) >> (4-SETUP)) & (0x0f << SETUP))
++#define LOW_NIBBLE_WRITE(x)   (((x) << SETUP) & (0x0f << SETUP))
++#define HIGH_NIBBLE_READ(x)   (((x) & (0x0f << SETUP)) << (4-SETUP))
++#define LOW_NIBBLE_READ(x)    (((x) & (0x0f << SETUP)) >> SETUP)
++
++/* Execution times (in microseconds) */
++#define T_READ                        60      /* Read execution time (min 43 us) */
++#define T_WRITE                       60      /* Write execution time (min 43 us) */
++#define T_BF                  4       /* Busy flag polling time (min 1 us) */
++
++/* Timings in nanoseconds */
++#define T_AS                  200     /* Address set-up time (min 140 ns) */
++#define T_EH                  500     /* Enable high time (min 450 ns) */
++#define T_EL                  800     /* Enable low time (min 500 ns) */
++
++/* Various constants */
++#define DFLT_NUM_CNTR         1       /* Default number of controllers the display has */
++#define DFLT_CNTR_ROWS                4       /* Default number of rows per controller */
++#define DFLT_CNTR_COLS                20      /* Default number of columns the display has */
++#define DFLT_VS_ROWS          25      /* Default number of rows for the virtual screen */
++#define DFLT_VS_COLS          80      /* Default number of columns for the virtual screen */
++#define DFLT_TABSTOP          4       /* Default length of tabs */
++#define DFLT_FLAGS            HD44780_CHECK_BF /* Default flags: check BF and 8 bit bus */
++
++#define MAX_NUM_CNTR          7       /* We support up to 7 controllers */
++#define MAX_CNTR_ROWS         4       /* The HD44780 supports up to 4 lines as a fake 2 lines mode */
++#define MAX_CNTR_COLS         80      /* The HD44780 supports up to 80 characters (1*80; 2*40; etc) */
+diff --git a/drivers/lcd-linux/hd44780.c b/drivers/lcd-linux/hd44780.c
+new file mode 100644
+index 0000000..0b1af6b
+--- /dev/null
++++ b/drivers/lcd-linux/hd44780.c
+@@ -0,0 +1,854 @@
++/* hd44780.c
++ *
++ * $Id: hd44780.c,v 1.181 2010/03/03 14:56:22 mjona Exp $
++ *
++ * LCD-Linux:
++ * Driver for HD44780 compatible displays connected to the parallel port.
++ *
++ * Copyright (C) 2005 - 2009  Mattia Jona-Lasinio (mjona@users.sourceforge.net)
++ * Based on the code for Sim.One Hardware by Nuccio Raciti (raciti.nuccio@gmail.com)
++ * Modified for ts72xx hardware by Petr Stetiar (ynezz@true.cz)
++ * (Only 8-bit mode supported for now.)
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++#ifdef CONFIG_PROC_FS
++#define USE_PROC
++#else
++#undef USE_PROC
++#endif
++
++#include <linux/bitops.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++#include <linux/delay.h>
++#include <linux/fs.h>
++
++#include <asm/uaccess.h>
++#include <asm/gpio.h>
++#include <asm/io.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++
++#ifdef USE_PROC
++#include <linux/proc_fs.h>
++#endif
++
++#define LCD_LINUX_MAIN
++#include <linux/hd44780.h>
++
++#include "charmap.h"
++#include "commands.h"
++#include "config.h"
++
++#define LCD_EN        EP93XX_GPIO_LINE_H(3)
++#define LCD_RS        EP93XX_GPIO_LINE_H(4)
++#define LCD_WR        EP93XX_GPIO_LINE_H(5)
++#define LCD_DATA0     EP93XX_GPIO_LINE_A(0)
++#define LCD_DATA1     EP93XX_GPIO_LINE_A(1)
++#define LCD_DATA2     EP93XX_GPIO_LINE_A(2)
++#define LCD_DATA3     EP93XX_GPIO_LINE_A(3)
++#define LCD_DATA4     EP93XX_GPIO_LINE_A(4)
++#define LCD_DATA5     EP93XX_GPIO_LINE_A(5)
++#define LCD_DATA6     EP93XX_GPIO_LINE_A(6)
++#define LCD_DATA7     EP93XX_GPIO_LINE_A(7)
++
++static struct gpio lcd_gpios[] = {
++      { LCD_EN, GPIOF_OUT_INIT_LOW, "LCD enable" },
++      { LCD_RS, GPIOF_OUT_INIT_LOW,  "LCD data" },
++      { LCD_WR, GPIOF_OUT_INIT_LOW,  "LCD r/w" },
++      { LCD_DATA0, GPIOF_OUT_INIT_LOW,  "LCD data0" },
++      { LCD_DATA1, GPIOF_OUT_INIT_LOW,  "LCD data1" },
++      { LCD_DATA2, GPIOF_OUT_INIT_LOW,  "LCD data2" },
++      { LCD_DATA3, GPIOF_OUT_INIT_LOW,  "LCD data3" },
++      { LCD_DATA4, GPIOF_OUT_INIT_LOW,  "LCD data4" },
++      { LCD_DATA5, GPIOF_OUT_INIT_LOW,  "LCD data5" },
++      { LCD_DATA6, GPIOF_OUT_INIT_LOW,  "LCD data6" },
++      { LCD_DATA7, GPIOF_OUT_INIT_LOW,  "LCD data7" },
++};
++
++/** Function prototypes **/
++static void read_display(unsigned char *byte, unsigned char bitmask);
++static void write_display(unsigned char byte, unsigned char bitmask);
++
++/* Initialization */
++static int hd44780_validate_driver(void);
++static int hd44780_init_port(void);
++static int hd44780_cleanup_port(void);
++static int hd44780_init_display(void);
++static int hd44780_cleanup_display(void);
++
++/* Write */
++static void hd44780_address_mode(int);
++static void hd44780_clear_display(void);
++static void hd44780_write_char(unsigned int, unsigned short);
++static void hd44780_write_cgram_char(unsigned char, unsigned char *);
++
++/* Read */
++static void check_bf(unsigned char);
++static void hd44780_read_char(unsigned int, unsigned short *);
++static void hd44780_read_cgram_char(unsigned char, unsigned char *);
++
++/* Input handling */
++static int hd44780_handle_custom_char(unsigned int);
++static int hd44780_handle_custom_ioctl(unsigned int, unsigned long, unsigned int);
++
++/* Proc operations */
++#ifdef USE_PROC
++static void create_proc_entries(void);
++static void remove_proc_entries(void);
++#endif
++
++/* hd44780_flags */
++#define _CHECK_BF     0       /* Do busy-flag checking */
++#define _4BITS_BUS    1       /* The bus is 4 bits long */
++#define _5X10_FONT    2       /* Use 5x10 font */
++#define CURSOR_BLINK  3       /* Make the cursor blinking */
++#define SHOW_CURSOR   4       /* Make the cursor visible */
++#define DISPLAY_ON    5       /* Display status: on or off */
++#define INC_ADDR      6       /* Increment address after data read/write */
++#define BACKLIGHT     7       /* Display backlight: on or off */
++#define CGRAM_STATE   9       /* Controller status bitmask (bits 9->15): DDRAM or CGRAM access */
++
++/* hd44780 access */
++#define ACCESS_TO_READ    0
++#define ACCESS_TO_WRITE   1
++#define ACCESS_TO_DATA    2
++
++#define ESC_MASK      0x00ff0000
++#define PROC_MASK     0x0f000000
++
++#define SET_STATE(state, mask)        (hd44780_flags = (hd44780_flags & ~(mask)) | ((state) & (mask)))
++#define SET_ESC_STATE(state)  SET_STATE((state) << 16, ESC_MASK)
++#define SET_PROC_LEVEL(level) SET_STATE((level) << 24, PROC_MASK)
++#define ESC_STATE             ((hd44780_flags & ESC_MASK) >> 16)
++#define PROC_LEVEL            ((hd44780_flags & PROC_MASK) >> 24)
++
++/* globals */
++static unsigned int disp_size;                        /* Display size (rows*columns) */
++static unsigned int disp_offset[1];           /* Physical cursor position on the display */
++static unsigned long hd44780_flags;           /* Driver flags for internal use only */
++
++static struct lcd_parameters par = {
++      .name           = HD44780_STRING,
++      .minor          = HD44780_MINOR,
++      .flags          = DFLT_FLAGS,
++      .tabstop        = DFLT_TABSTOP,
++      .num_cntr       = 1,
++      .cntr_rows      = DFLT_CNTR_ROWS,
++      .cntr_cols      = DFLT_CNTR_COLS,
++      .vs_rows        = DFLT_VS_ROWS,
++      .vs_cols        = DFLT_VS_COLS,
++      .cgram_chars    = 8,
++      .cgram_bytes    = 8,
++      .cgram_char0    = 0,
++};
++/* End of globals */
++
++#ifdef MODULE
++#include <linux/device.h>
++MODULE_ALIAS_CHARDEV(LCD_MAJOR, HD44780_MINOR);
++#include <linux/kmod.h>
++
++static unsigned short flags   = DFLT_FLAGS;
++static unsigned short tabstop = DFLT_TABSTOP;
++static unsigned short cntr_rows       = DFLT_CNTR_ROWS;
++static unsigned short cntr_cols       = DFLT_CNTR_COLS;
++static unsigned short vs_rows = DFLT_VS_ROWS;
++static unsigned short vs_cols = DFLT_VS_COLS;
++static unsigned short minor   = HD44780_MINOR;
++
++MODULE_DESCRIPTION("LCD ts72xx  driver for HD44780 compatible controllers.");
++MODULE_AUTHOR("Petr Stetiar <ynezz@true.cz>");
++#ifdef MODULE_LICENSE
++MODULE_LICENSE("GPL");
++#endif
++module_param(flags,   ushort, 0444);
++module_param(cntr_rows,       ushort, 0444);
++module_param(cntr_cols,       ushort, 0444);
++module_param(vs_rows, ushort, 0444);
++module_param(vs_cols, ushort, 0444);
++module_param(tabstop, ushort, 0444);
++module_param(minor,   ushort, 0444);
++MODULE_PARM_DESC(flags,               "Various flags (see Documentation)");
++MODULE_PARM_DESC(cntr_rows,   "Number of rows per controller on the LCD: 1, 2, 4 (default: " string(DFLT_CNTR_ROWS) ")");
++MODULE_PARM_DESC(cntr_cols,   "Number of columns on the LCD (default: " string(DFLT_CNTR_COLS) ", max: " string(MAX_CNTR_COLS) ")");
++MODULE_PARM_DESC(vs_rows,     "Number of rows of the virtual screen (default: " string(DFLT_VS_ROWS) ")");
++MODULE_PARM_DESC(vs_cols,     "Number of columns of the virtual screen (default: " string(DFLT_VS_COLS) ")");
++MODULE_PARM_DESC(tabstop,     "Tab character length (default: " string(DFLT_TABSTOP) ")");
++MODULE_PARM_DESC(minor,               "Assigned minor number (default: " string(HD44780_MINOR) ")");
++#else
++
++/*
++ * Parse boot command line
++ *
++ * hd44780=cntr_rows,cntr_cols,vs_rows,vs_cols,flags,minor,tabstop
++ */
++static int __init hd44780_boot_init(char *cmdline)
++{
++      char *str = cmdline;
++      int idx = 0;
++      unsigned short *args[] = {
++              &par.cntr_rows,
++              &par.cntr_cols,
++              &par.vs_rows,
++              &par.vs_cols,
++              (ushort *) &par.flags,
++              &par.num_cntr,
++              &par.minor,
++              &par.tabstop,
++      };
++
++      while (*cmdline && idx < (sizeof(args)/sizeof(unsigned short *))) {
++              switch (*str) {
++              case ',':
++                      *str++ = 0;
++              case 0:
++                      if (strlen(cmdline))
++                              *args[idx] = simple_strtoul(cmdline, NULL, 0);
++                      ++idx;
++                      cmdline = str;
++                      break;
++              default:
++                      ++str;
++                      break;
++              }
++      }
++
++      return (1);
++}
++
++__setup("hd44780=", hd44780_boot_init);
++#endif /* MODULE */
++
++/* Macros for iterator handling */
++static inline unsigned int iterator_inc_(unsigned int iterator, const unsigned int module)
++{
++      return ((++iterator)%module);
++}
++
++static inline unsigned int iterator_dec_(unsigned int iterator, const unsigned int module)
++{
++      return (iterator ? --iterator : module-1);
++}
++
++#define iterator_inc(iterator, module)                (iterator = iterator_inc_(iterator, module))
++#define iterator_dec(iterator, module)                (iterator = iterator_dec_(iterator, module))
++
++static inline void set_lines(unsigned char bitmask)
++{
++      gpio_set_value(LCD_EN, 0);              /* Disable */
++
++      if (bitmask & ACCESS_TO_WRITE ) {
++              gpio_direction_output(LCD_DATA0, 0);
++              gpio_direction_output(LCD_DATA1, 0);
++              gpio_direction_output(LCD_DATA2, 0);
++              gpio_direction_output(LCD_DATA3, 0);
++              gpio_direction_output(LCD_DATA4, 0);
++              gpio_direction_output(LCD_DATA5, 0);
++              gpio_direction_output(LCD_DATA6, 0);
++              gpio_direction_output(LCD_DATA7, 0);
++              gpio_set_value(LCD_WR, 0);      /* Write */
++      } else {
++              gpio_direction_input(LCD_DATA0);
++              gpio_direction_input(LCD_DATA1);
++              gpio_direction_input(LCD_DATA2);
++              gpio_direction_input(LCD_DATA3);
++              gpio_direction_input(LCD_DATA4);
++              gpio_direction_input(LCD_DATA5);
++              gpio_direction_input(LCD_DATA6);
++              gpio_direction_input(LCD_DATA7);
++              gpio_set_value(LCD_WR, 1);      /* Read */
++      }
++
++      if (bitmask & ACCESS_TO_DATA )
++              gpio_set_value(LCD_RS, 1);      /* Data */
++      else
++              gpio_set_value(LCD_RS, 0);      /* Cmds*/
++}
++
++static inline void read_display(unsigned char *byte, unsigned char bitmask)
++{
++      unsigned char ret;
++      if (bitmask)
++              check_bf(bitmask);
++
++      set_lines(bitmask);
++
++      ndelay(T_AS);                   /* Address set-up time */
++      gpio_set_value(LCD_EN, 1);      /* Enable */
++      ndelay(T_EH);                   /* Enable high time */
++
++      ret =  (gpio_get_value(LCD_DATA0) << 0);
++      ret |= (gpio_get_value(LCD_DATA1) << 1);
++      ret |= (gpio_get_value(LCD_DATA2) << 2);
++      ret |= (gpio_get_value(LCD_DATA3) << 3);
++      ret |= (gpio_get_value(LCD_DATA4) << 4);
++      ret |= (gpio_get_value(LCD_DATA5) << 5);
++      ret |= (gpio_get_value(LCD_DATA6) << 6);
++      ret |= (gpio_get_value(LCD_DATA7) << 7);
++ 
++      gpio_set_value(LCD_EN, 0);      /* Disable */
++      ndelay(T_EL);                   /* Enable low time */
++      *byte = ret;
++}
++
++/* Low level write to the display */
++static inline void write_display(unsigned char data, unsigned char bitmask)
++{
++      check_bf(bitmask);
++      set_lines(bitmask);
++
++      gpio_set_value(LCD_DATA0, (data >> 0) & 1);
++      gpio_set_value(LCD_DATA1, (data >> 1) & 1);
++      gpio_set_value(LCD_DATA2, (data >> 2) & 1);
++      gpio_set_value(LCD_DATA3, (data >> 3) & 1);
++      gpio_set_value(LCD_DATA4, (data >> 4) & 1);
++      gpio_set_value(LCD_DATA5, (data >> 5) & 1);
++      gpio_set_value(LCD_DATA6, (data >> 6) & 1);
++      gpio_set_value(LCD_DATA7, (data >> 7) & 1);
++
++      ndelay(T_AS);                           /* Address set-up time */
++      gpio_set_value(LCD_EN, 1);
++      ndelay(T_EH);                           /* Enable high time */
++
++      gpio_set_value(LCD_EN, 0);              /* Disable */
++      ndelay(T_EL);                           /* Enable low time */
++}
++
++/* Read Address Counter AC from the display */
++static unsigned char read_ac(unsigned char bitmask)
++{
++      unsigned char byte;
++
++      read_display(&byte, bitmask);
++
++      return (byte);
++}
++
++static void check_bf(unsigned char bitmask)
++{
++      unsigned int timeout = 20;
++      static unsigned char do_check_bf = 5;
++
++      gpio_set_value(LCD_EN, 0);              /* Disable */
++
++      gpio_direction_input(LCD_DATA0);
++      gpio_direction_input(LCD_DATA1);
++      gpio_direction_input(LCD_DATA2);
++      gpio_direction_input(LCD_DATA3);
++      gpio_direction_input(LCD_DATA4);
++      gpio_direction_input(LCD_DATA5);
++      gpio_direction_input(LCD_DATA6);
++      gpio_direction_input(LCD_DATA7);
++ 
++      gpio_set_value(LCD_WR, 1);              /* Read */
++      gpio_set_value(LCD_RS, 0);              /* Instru */
++
++      ndelay(T_AS);                           /* Address set-up time */
++      gpio_set_value(LCD_EN, 1);              /* Enable */
++      ndelay(T_EH);                           /* Enable high time */
++
++      do {
++              udelay(T_BF);
++      } while (gpio_get_value(LCD_DATA7) && --timeout);
++
++      if (!timeout) {
++              if (!--do_check_bf) {
++                      printk(KERN_NOTICE "hd44780 error: is LCD connected?\n");
++              }
++      }
++
++      gpio_set_value(LCD_EN, 0);              /* Disable */
++      ndelay(T_EL);                           /* Enable low time */
++}
++
++/* Send commands to the display */
++static void write_command(unsigned char command)
++{
++      write_display(command, ACCESS_TO_WRITE);
++
++      if (command <= 0x03)
++              mdelay(2);
++}
++
++static inline void set_cursor(unsigned int offset)
++{
++      unsigned int disp_number = offset/disp_size;
++      unsigned int local_offset = offset%disp_size;
++
++      if (disp_offset[disp_number] != local_offset || test_bit(CGRAM_STATE+disp_number, &hd44780_flags)) {
++              unsigned int disp_row = local_offset/par.cntr_cols;
++              unsigned int disp_column = local_offset%par.cntr_cols;
++
++              write_command(DDRAM_IO | ((disp_row%2)*0x40) | (((disp_row >= 2)*par.cntr_cols)+disp_column));
++              clear_bit(CGRAM_STATE+disp_number, &hd44780_flags);
++              disp_offset[disp_number] = local_offset;
++      }
++}
++
++/* HD44780 DDRAM addresses are consecutive only when
++ * the cursor moves on the same row of the display.
++ * Every time the row of the cursor changes we invalidate
++ * the cursor position to force hardware cursor repositioning.
++ */
++static inline void mov_cursor(unsigned int disp_number)
++{
++      if (test_bit(INC_ADDR, &hd44780_flags)) {
++              iterator_inc(disp_offset[disp_number], disp_size);
++              if (disp_offset[disp_number]%par.cntr_cols == 0)
++                      disp_offset[disp_number] = disp_size;
++      } else {
++              iterator_dec(disp_offset[disp_number], disp_size);
++              if (disp_offset[disp_number]%par.cntr_cols == par.cntr_cols-1)
++                      disp_offset[disp_number] = disp_size;
++      }
++}
++
++static struct lcd_driver hd44780 = {
++      .read_char              = hd44780_read_char,
++      .read_cgram_char        = hd44780_read_cgram_char,
++      .write_char             = hd44780_write_char,
++      .write_cgram_char       = hd44780_write_cgram_char,
++      .address_mode           = hd44780_address_mode,
++      .clear_display          = hd44780_clear_display,
++      .validate_driver        = hd44780_validate_driver,
++      .init_display           = hd44780_init_display,
++      .cleanup_display        = hd44780_cleanup_display,
++      .init_port              = hd44780_init_port,
++      .cleanup_port           = hd44780_cleanup_port,
++      .handle_custom_char     = hd44780_handle_custom_char,
++      .handle_custom_ioctl    = hd44780_handle_custom_ioctl,
++
++      .charmap                = charmap,
++};
++
++static void hd44780_read_char(unsigned int offset, unsigned short *data)
++{
++      unsigned int disp_number = offset/disp_size;
++      unsigned char tmp;
++
++      set_cursor(offset);
++      read_display(&tmp, ACCESS_TO_DATA);
++      *data = tmp;
++      mov_cursor(disp_number);
++}
++
++static void hd44780_read_cgram_char(unsigned char index, unsigned char *pixels)
++{
++      unsigned int i;
++
++      write_command(CGRAM_IO | (index << 3));
++      set_bit(CGRAM_STATE+0, &hd44780_flags);
++
++      for (i = 0; i < 8; ++i) {
++              read_display(pixels+i, ACCESS_TO_DATA);
++              pixels[i] &= 0x1f;
++      }
++
++}
++
++static void hd44780_write_char(unsigned int offset, unsigned short data)
++{
++      unsigned int disp_number = offset/disp_size;
++
++      set_cursor(offset);
++      write_display(data & 0xff, ACCESS_TO_WRITE | ACCESS_TO_DATA);
++      mov_cursor(disp_number);
++}
++
++static void hd44780_write_cgram_char(unsigned char index, unsigned char *pixels)
++{
++      unsigned int i;
++
++      /* Move address pointer to index in CGRAM */
++      write_command(CGRAM_IO | (index << 3));
++      set_bit(CGRAM_STATE+0, &hd44780_flags);
++
++      for (i = 0; i < 8; ++i) {
++              pixels[i] &= 0x1f;
++              write_display(pixels[i], ACCESS_TO_WRITE | ACCESS_TO_DATA );
++      }
++}
++
++/* Increment/decrement address mode after a data read/write */
++static void hd44780_address_mode(int mode)
++{
++      if (mode > 0 && ! test_bit(INC_ADDR, &hd44780_flags)) {
++              write_command(CURS_INC | DISP_SHIFT_OFF);
++              set_bit(INC_ADDR, &hd44780_flags);
++      } else if (mode < 0 && test_bit(INC_ADDR, &hd44780_flags)) {
++              write_command(CURS_DEC | DISP_SHIFT_OFF);
++              clear_bit(INC_ADDR, &hd44780_flags);
++      }
++}
++
++static void hd44780_clear_display(void)
++{
++      write_command(CLR_DISP);
++      if (! test_bit(INC_ADDR, &hd44780_flags))
++              write_command(CURS_DEC | DISP_SHIFT_OFF);
++      memset(disp_offset, 0, sizeof(disp_offset));
++}
++
++static int hd44780_validate_driver(void)
++{
++      if (par.cntr_rows != 1 && par.cntr_rows != 2 && par.cntr_rows != 4)
++              par.cntr_rows = DFLT_CNTR_ROWS;
++
++      if (par.cntr_rows != 1)
++              par.flags &= ~HD44780_5X10_FONT;
++
++      if (! par.cntr_cols || par.cntr_cols > MAX_CNTR_COLS/par.cntr_rows)
++              par.cntr_cols = MAX_CNTR_COLS/par.cntr_rows;
++
++      disp_size = par.cntr_rows*par.cntr_cols;
++
++      /* These parameters depend on the hardware and cannot be changed */
++      par.cgram_chars = 8;
++      par.cgram_bytes = 8;
++      par.cgram_char0 = 0;
++
++      return (0);
++}
++
++/* Send init commands to the display */
++static void write_init_command(void)
++{
++      unsigned char command;
++      command = BUS_8_BITS;
++      command |= ((par.cntr_rows == 1) ? DISP_1_LINE : DISP_2_LINES);
++      command |= (test_bit(_5X10_FONT, &hd44780_flags) ? FONT_5X10 : FONT_5X8);
++
++      write_display(command, ACCESS_TO_WRITE);
++      mdelay(20);     /* Wait more than 4.1 ms */
++
++      write_display(command, ACCESS_TO_WRITE);
++      udelay(200);    /* Wait more than 100 us */
++
++      write_display(command, ACCESS_TO_WRITE);
++      udelay(200);    /* Wait more than 100 us */
++
++      write_command(command);
++}
++
++static int hd44780_init_display(void)
++{
++      if (par.flags & HD44780_CHECK_BF)
++              set_bit(_CHECK_BF, &hd44780_flags);
++      else
++              clear_bit(_CHECK_BF, &hd44780_flags);
++
++      if (par.flags & HD44780_4BITS_BUS)
++              set_bit(_4BITS_BUS, &hd44780_flags);
++      else
++              clear_bit(_4BITS_BUS, &hd44780_flags);
++
++      if (par.flags & HD44780_5X10_FONT)
++              set_bit(_5X10_FONT, &hd44780_flags);
++      else
++              clear_bit(_5X10_FONT, &hd44780_flags);
++
++      write_init_command();
++      hd44780_address_mode(1);
++      hd44780_clear_display();
++      write_command(DISP_ON | CURS_OFF | BLINK_OFF);
++      set_bit(DISPLAY_ON, &hd44780_flags);
++      clear_bit(SHOW_CURSOR, &hd44780_flags);
++      clear_bit(CURSOR_BLINK, &hd44780_flags);
++
++      /* Set the CGRAM to default values */
++      hd44780_write_cgram_char(0, cg0);
++      hd44780_write_cgram_char(1, cg1);
++      hd44780_write_cgram_char(2, cg2);
++      hd44780_write_cgram_char(3, cg3);
++      hd44780_write_cgram_char(4, cg4);
++      hd44780_write_cgram_char(5, cg5);
++      hd44780_write_cgram_char(6, cg6);
++      hd44780_write_cgram_char(7, cg7);
++      init_charmap();
++
++      return (0);
++}
++
++static int hd44780_cleanup_display(void)
++{
++      hd44780_clear_display();
++
++      return (0);
++}
++
++static int hd44780_init_port(void)
++{
++      int err = gpio_request_array(lcd_gpios, ARRAY_SIZE(lcd_gpios));
++      if (err) {
++              printk(KERN_ERR "hd44780: error while requesting GPIO pins\n");
++              return 1;
++      }
++
++      return 0;
++}
++
++static int hd44780_cleanup_port(void)
++{
++      gpio_direction_input(LCD_RS);
++      gpio_direction_input(LCD_EN);
++      gpio_direction_input(LCD_DATA0);
++      gpio_direction_input(LCD_DATA1);
++      gpio_direction_input(LCD_DATA2);
++      gpio_direction_input(LCD_DATA3);
++      gpio_direction_input(LCD_DATA4);
++      gpio_direction_input(LCD_DATA5);
++      gpio_direction_input(LCD_DATA6);
++      gpio_direction_input(LCD_DATA7);
++
++      gpio_free_array(lcd_gpios, ARRAY_SIZE(lcd_gpios));
++
++      return 0;
++}
++
++static void display_attr(unsigned char input)
++{
++      unsigned char command;
++
++      switch (ESC_STATE) {
++      case 'a':       /* Turn on/off the display cursor */
++              if (input == '1')
++                      set_bit(SHOW_CURSOR, &hd44780_flags);
++              else if (input == '0')
++                      clear_bit(SHOW_CURSOR, &hd44780_flags);
++              break;
++      case 'b':       /* Turn on/off the display cursor blinking */
++              if (input == '1')
++                      set_bit(CURSOR_BLINK, &hd44780_flags);
++              else if (input == '0')
++                      clear_bit(CURSOR_BLINK, &hd44780_flags);
++              break;
++      case 'h':       /* Turn on/off the display */
++              if (input == '1')
++                      set_bit(DISPLAY_ON, &hd44780_flags);
++              else if (input == '0')
++                      clear_bit(DISPLAY_ON, &hd44780_flags);
++              break;
++      }
++
++      command = (test_bit(DISPLAY_ON, &hd44780_flags) ? DISP_ON : DISP_OFF);
++      command |= (test_bit(SHOW_CURSOR, &hd44780_flags) ? CURS_ON : CURS_OFF);
++      command |= (test_bit(CURSOR_BLINK, &hd44780_flags) ? BLINK_ON : BLINK_OFF);
++
++      if (ESC_STATE == 'h')
++              write_command(command);
++}
++
++static int hd44780_handle_custom_char(unsigned int _input)
++{
++      unsigned char input = _input & 0xff;
++
++      if (_input & (~0xff)) {
++              switch (ESC_STATE) {
++              case 'a':       /* Turn on/off the display cursor */
++              case 'b':       /* Turn on/off the display cursor blinking */
++              case 'h':       /* Turn on/off the the display */
++                      display_attr(input);
++                      return (0);
++              case 'l':       /* Turn on/off the backlight */
++                      if (input == '1')
++                              set_bit(BACKLIGHT, &hd44780_flags);
++                      else if (input == '0')
++                              clear_bit(BACKLIGHT, &hd44780_flags);
++                      read_ac(ACCESS_TO_READ);
++                      return (0);
++              }
++      }
++
++      switch (input) {
++      case 'a':       /* Turn on/off the display cursor */
++      case 'b':       /* Turn on/off the display cursor blinking */
++      case 'h':       /* Turn on/off the display */
++      case 'l':       /* Turn on/off the backlight */
++              SET_ESC_STATE(input);
++              return (1);
++      case 'd':       /* Shift display cursor Right */
++              write_command(SHIFT_CURS | SHIFT_RIGHT);
++              return (0);
++      case 'e':       /* Shift display cursor Left */
++              write_command(SHIFT_CURS | SHIFT_LEFT);
++              return (0);
++      case 'f':       /* Shift display Right */
++              write_command(SHIFT_DISP | SHIFT_RIGHT);
++              return (0);
++      case 'g':       /* Shift display Left */
++              write_command(SHIFT_DISP | SHIFT_LEFT);
++              return (0);
++      }
++
++      return (-1);
++}
++
++static int hd44780_handle_custom_ioctl(unsigned int num, unsigned long arg, unsigned int user_space)
++{
++      unsigned char *buffer = (unsigned char *)arg;
++
++      if (num != HD44780_READ_AC)
++              return (-ENOIOCTLCMD);
++
++      if (user_space)
++              put_user(read_ac(ACCESS_TO_READ), buffer);
++      else
++              buffer[0] = read_ac(ACCESS_TO_READ);
++
++      return (0);
++}
++
++#ifdef USE_PROC
++static int hd44780_proc_status(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
++{
++      char *temp = buffer;
++
++      /* Print display configuration */
++      temp += sprintf(temp,
++                      "Interface:\t%u bits\n"
++                      "Display rows:\t%d\n"
++                      "Display cols:\t%d\n"
++                      "Screen rows:\t%d\n"
++                      "Screen cols:\t%d\n"
++                      "Read:\t\t%sabled\n"
++                      "Busy flag chk:\t%sabled\n"
++                      "Assigned minor:\t%u\n",
++                      (test_bit(_4BITS_BUS, &hd44780_flags) ? 4 : 8),
++                      par.cntr_rows, par.cntr_cols,
++                      par.vs_rows, par.vs_cols,
++                      (hd44780.read_char ? "En" : "Dis"),
++                      (test_bit(_CHECK_BF, &hd44780_flags) ? "En" : "Dis"),
++                      par.minor);
++
++      return (temp-buffer);
++}
++
++static int hd44780_proc_cgram(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
++{
++      char *temp = buffer;
++      unsigned int i;
++
++      temp += sprintf(temp,   "static void init_charmap(void)\n{\n"
++                              "\t/*\n"
++                              "\t * charmap[char mapped to cg0] = 0;\n"
++                              "\t * charmap[char mapped to cg1] = 1;\n"
++                              "\t * charmap[char mapped to cg2] = 2;\n"
++                              "\t * charmap[char mapped to cg3] = 3;\n"
++                              "\t * charmap[char mapped to cg4] = 4;\n"
++                              "\t * charmap[char mapped to cg5] = 5;\n"
++                              "\t * charmap[char mapped to cg6] = 6;\n"
++                              "\t * charmap[char mapped to cg7] = 7;\n"
++                              "\t */\n"
++                              "}\n\n");
++
++      for (i = 0; i < 8; ++i) {
++              unsigned int j;
++              unsigned char cgram_buffer[8];
++
++              temp += sprintf(temp, "static unsigned char cg%u[] = { ", i);
++              hd44780_read_cgram_char(i, cgram_buffer);
++              for (j = 0; j < 8; ++j)
++                      temp += sprintf(temp, "0x%.2x%s", cgram_buffer[j], (j == 7 ? " };\n" : ", "));
++      }
++
++      return (temp-buffer);
++}
++
++static void create_proc_entries(void)
++{
++      SET_PROC_LEVEL(0);
++      if (create_proc_read_entry("status", 0, hd44780.driver_proc_root, hd44780_proc_status, NULL) == NULL) {
++              printk(KERN_ERR "hd44780: cannot create /proc/lcd/%s/status\n", par.name);
++              return;
++      }
++      SET_PROC_LEVEL(1);
++      if (create_proc_read_entry("cgram.h", 0, hd44780.driver_proc_root, hd44780_proc_cgram, NULL) == NULL) {
++              printk(KERN_ERR "hd44780: cannot create /proc/lcd/%s/cgram.h\n", par.name);
++              return;
++      }
++      SET_PROC_LEVEL(2);
++}
++
++static void remove_proc_entries(void)
++{
++      switch (PROC_LEVEL) {
++      case 2:
++              remove_proc_entry("cgram.h", hd44780.driver_proc_root);
++      case 1:
++              remove_proc_entry("status", hd44780.driver_proc_root);
++      }
++      SET_PROC_LEVEL(0);
++}
++#endif
++
++/* Initialization */
++static int __init hd44780_init_module(void)
++{
++      int ret;
++
++#ifdef MODULE
++      if ((ret = request_module("lcd-linux"))) {
++              printk(KERN_ERR "hd44780: request_module() returned %d\n", ret);
++              if (ret < 0) {
++                      if (ret != -ENOSYS) {
++                              printk(KERN_ERR "hd44780: failure while loading module lcd-linux\n");
++                              return (ret);
++                      }
++                      printk(KERN_ERR "hd44780: your kernel does not have kmod or kerneld support;\n");
++                      printk(KERN_ERR "hd44780: remember to load the lcd-linux module before\n");
++                      printk(KERN_ERR "hd44780: loading the hd44780 module\n");
++              }
++      }
++
++      if (flags       != DFLT_FLAGS)          par.flags       = flags;
++      if (tabstop     != DFLT_TABSTOP)        par.tabstop     = tabstop;
++      if (cntr_rows   != DFLT_CNTR_ROWS)      par.cntr_rows   = cntr_rows;
++      if (cntr_cols   != DFLT_CNTR_COLS)      par.cntr_cols   = cntr_cols;
++      if (vs_rows     != DFLT_VS_ROWS)        par.vs_rows     = vs_rows;
++      if (vs_cols     != DFLT_VS_COLS)        par.vs_cols     = vs_cols;
++      if (minor       != HD44780_MINOR)       par.minor       = minor;
++#endif
++
++      lcd_driver_setup(&hd44780);
++      if ((ret = lcd_register_driver(&hd44780, &par)))
++              return (ret);
++
++#ifdef USE_PROC
++      if (hd44780.driver_proc_root)
++              create_proc_entries();
++#endif
++
++      printk(KERN_INFO "hd44780: ts72xx driver loaded\n" );
++
++      return (0);
++}
++
++static void __exit hd44780_cleanup_module(void)
++{
++#ifdef USE_PROC
++      if (hd44780.driver_proc_root)
++              remove_proc_entries();
++#endif
++
++      lcd_unregister_driver(&hd44780, &par);
++}
++
++module_init(hd44780_init_module)
++module_exit(hd44780_cleanup_module)
+diff --git a/drivers/lcd-linux/lcd-linux.c b/drivers/lcd-linux/lcd-linux.c
+new file mode 100644
+index 0000000..f2d565b
+--- /dev/null
++++ b/drivers/lcd-linux/lcd-linux.c
+@@ -0,0 +1,3023 @@
++/* lcd-linux.c
++ *
++ * $Id: lcd-linux.c,v 1.308 2010/03/03 14:56:22 mjona Exp $
++ *
++ * Software layer to drive LCD displays under Linux.
++ *
++ * Copyright (C) 2005 - 2009  Mattia Jona-Lasinio (mjona@users.sourceforge.net)
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++#include <linux/version.h>
++
++#ifndef KERNEL_VERSION
++#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
++#endif
++
++#ifndef LINUX_VERSION_CODE
++#error - LINUX_VERSION_CODE undefined in 'linux/version.h'
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 33)
++#include <generated/autoconf.h>
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
++#include <linux/autoconf.h>
++#else
++#include <linux/config.h>
++#endif
++
++#ifdef CONFIG_PROC_FS
++#define USE_PROC
++#else
++#undef USE_PROC
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
++#include <linux/semaphore.h>
++#else
++#include <asm/semaphore.h>
++#endif
++
++#include <linux/bitops.h>
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++
++#include <linux/fs.h>
++
++#include <asm/uaccess.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
++#include <linux/device.h>
++#endif
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/selection.h>
++#include <linux/vmalloc.h>
++
++#ifdef USE_PROC
++#include <linux/proc_fs.h>
++#endif
++
++#define LCD_LINUX_MAIN
++#include <linux/lcd-linux.h>
++
++static inline void __set_br(unsigned long *x, unsigned long val, unsigned long start, unsigned long len)
++{
++      unsigned long mask = (1 << len)-1;
++
++      if (val <= mask) {
++              mask <<= start;
++              val <<= start;
++              *x = (*x & ~mask) | val;
++      }
++}
++
++static inline unsigned long __get_br(unsigned long x, unsigned long start, unsigned long len)
++{
++      return ((x >> start) & ((1 << len)-1));
++}
++
++/*** struct_flags ***/
++
++/* internal flags: bits [0:15] of struct_flags (16 flags allowed) */
++#define NEED_WRAP     0               /* Next char will trigger a newline */
++#define DECIM         1               /* Insert mode */
++#define DECOM         2               /* Row origin of cursor: absolute or relative to scrolling region */
++#define DECAWM                3               /* Autowrap */
++#define DECSCNM               4               /* Inverted screen */
++#define CRLF          5               /* Follow lf, vt, ff, with a cr */
++#define INC_CURS_POS  6               /* Increment cursor position after data read/write */
++#define QUES          7               /* CSI Esc sequence contains a question mark */
++#define USER_SPACE    8               /* If set, the buffer pointed by arg in do_lcd_ioctl() is
++                                       * assumed to be in user space otherwise it is in kernel space */
++#define NULL_CHARMAP  9               /* The driver doesn't provide a charmap so the
++                                       * lcd-linux layer provides one*/
++#define CAN_DO_COLOR  10              /* The display is color capable */
++#define WITH_ATTR     11              /* If set, the void * buffer in do_lcd_read/write() contains
++                                       * attributes and therefore is an unsigned short * otherwise it
++                                       * is an unsigned char *
++                                       */
++
++/* input states: bits [24:27] of struct_flags (16 states allowed) */
++#define NORMAL                0       /* Normal mode */
++#define RAW           1       /* Raw mode (console emulation disabled) */
++#define SYN           2       /* Synchronous Idle mode */
++#define ESC           3       /* Escape mode */
++#define CSI           4       /* CSI escape mode */
++#define ESC_G0                5       /* G0 character set */
++#define ESC_G1                6       /* G1 character set */
++#define ESC_HASH      7       /* ESC # escape sequence */
++#define ESC_PERCENT   8       /* ESC % escape sequence */
++#define ARG           9       /* Waiting for arguments for the lcd-linux layer */
++#define ARG_DRIVER    10      /* Waiting for arguments for the display driver */
++
++#define SET_ESC_STATE(p, x)   __set_br(&(p)->struct_flags, x, 16, 8)
++#define SET_INPUT_STATE(p, x) __set_br(&(p)->struct_flags, x, 24, 4)
++#define SET_INIT_LEVEL(p, x)  __set_br(&(p)->struct_flags, x, 28, 2)
++#define SET_PROC_LEVEL(p, x)  __set_br(&(p)->struct_flags, x, 30, 2)
++#define ESC_STATE(p)          __get_br((p)->struct_flags, 16, 8)
++#define INPUT_STATE(p)                __get_br((p)->struct_flags, 24, 4)
++#define INIT_LEVEL(p)         __get_br((p)->struct_flags, 28, 2)
++#define PROC_LEVEL(p)         __get_br((p)->struct_flags, 30, 2)
++
++/*** attributes ***/
++#define I_MASK                0x03            /* Intensity (0 = low, 1 = normal, 2 = bright) */
++#define ULINE         0x04            /* Underlined text */
++#define       REVERSE         0x08            /* Reversed video text */
++#define BLINK         0x80            /* Blinking text */
++
++/*** Color attributes ***/
++#define FG_COLOR      0x07                            /* Foreground color mask */
++#define FG_BRIGHT     0x08                            /* Foreground bright color */
++#define FG_MASK               (FG_BRIGHT | FG_COLOR)          /* Foreground mask */
++#define BG_COLOR      0x70                            /* Background color mask */
++#define BG_BRIGHT     0x80                            /* Background bright color */
++#define BG_MASK               (BG_BRIGHT | BG_COLOR)          /* Background mask */
++
++#define NPAR  16                      /* Max number of parameters in CSI escape sequence */
++#define FLIP_BUF_SIZE (1 << 6)        /* Flip buffer size (64 bytes) MUST be a power of 2 */
++
++struct lcd_struct {
++      struct list_head        lcd_list;               /* Doubly linked list */
++      struct semaphore        lcd_sem;                /* Locks this structure */
++      struct lcd_driver       *driver;                /* The driver associated to this struct */
++      struct lcd_parameters   *par;                   /* The parameters associated to this struct */
++      unsigned long           struct_flags;           /* Flags for internal use only */
++      unsigned int            refcount;               /* Number of references to this struct */
++
++      unsigned short          *display;               /* The display buffer */
++
++      unsigned short          *fb;                    /* The virtual screen framebuffer */
++      unsigned int            fb_size;                /* Size of the framebuffer */
++      unsigned int            frame_base;             /* Offset of row 0, column 0 of a frame in fb */
++      unsigned int            frame_size;             /* Size of the frame */
++
++      unsigned int            row;                    /* Current row in virtual screen */
++      unsigned int            col;                    /* Current column in virtual screen */
++      unsigned int            s_offset;               /* Saved cursor position in virtual screen */
++
++      unsigned int            top;                    /* Top scroll row in virtual screen */
++      unsigned int            bot;                    /* Bottom scroll row in virtual screen */
++
++      int                     esc_args;               /* Number of arguments for a normal escape sequence */
++      unsigned int            csi_args[NPAR];         /* CSI parameters */
++      unsigned int            index;                  /* Index in csi_args and counter for cgram characters generation */
++      unsigned char           cgram_index;            /* Index of the cgram character to be created */
++      unsigned char           *cgram_buffer;          /* Buffer for cgram operations in this driver */
++
++      unsigned short          erase_char;             /* Character to be used when erasing */
++      unsigned char           attr;                   /* Current attributes */
++      unsigned char           color;                  /* Color for normal intensity mode */
++      unsigned char           s_color;                /* Saved color for normal intensity mode */
++      unsigned char           defcolor;               /* Default color for normal intensity mode */
++      unsigned char           ulcolor;                /* Color for underline mode */
++      unsigned char           halfcolor;              /* Color for low intensity mode */
++      unsigned char           attributes;             /* Packed attributes */
++      unsigned char           s_attributes;           /* Saved packed attributes */
++
++      unsigned char           *s_charmap;             /* Saved character map for this driver */
++      unsigned char           *flip_buf;              /* High speed flip buffer */
++};
++
++/** Function prototypes **/
++
++/* Init/Cleanup the driver */
++static int init_driver(struct lcd_struct *);
++static int cleanup_driver(struct lcd_struct *);
++
++/* Read from/Write to the driver */
++static void read_data(struct lcd_struct *, unsigned short *);
++static void read_cgram(struct lcd_struct *, unsigned char, unsigned char *);
++static void write_data(struct lcd_struct *, unsigned short);
++static void write_cgram(struct lcd_struct *, unsigned char, unsigned char *);
++
++/* Input handlers */
++static void cr(struct lcd_struct *);
++static void lf(struct lcd_struct *);
++static void control_char(struct lcd_struct *, unsigned char);
++static void handle_csi(struct lcd_struct *, unsigned char);
++static int handle_custom_esc(struct lcd_struct *, unsigned int);
++static int handle_esc(struct lcd_struct *, unsigned char);
++static void handle_input(struct lcd_struct *, unsigned short);
++
++/* Low level file operations */
++static ssize_t do_lcd_read(struct lcd_struct *, void *, size_t);
++static ssize_t do_lcd_write(struct lcd_struct *, const void *, size_t);
++static int do_lcd_open(struct lcd_struct *);
++static int do_lcd_release(struct lcd_struct *);
++static int do_lcd_ioctl(struct lcd_struct *, unsigned int, unsigned long);
++
++/* Proc functions */
++#ifdef USE_PROC
++static void create_driver_proc_entries(struct lcd_struct *);
++static void remove_driver_proc_entries(struct lcd_struct *);
++#endif
++
++/* globals */
++static unsigned int major     = LCD_MAJOR;            /* Major number for LCD-Linux device */
++static unsigned short minors  = LCD_MINORS;           /* Minor numbers allocated for LCD-Linux */
++static LIST_HEAD(lcd_drivers);                                /* Registered lcd drivers */
++static struct semaphore drivers_sem;                  /* Locks the lcd_drivers list */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
++static struct class *lcd_linux_class;
++#endif
++#ifdef USE_PROC
++static struct proc_dir_entry *lcd_proc_root;
++#endif
++/* End of globals */
++
++#ifdef MODULE
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
++#include <linux/device.h>
++MODULE_ALIAS_CHARDEV_MAJOR(LCD_MAJOR);
++#endif
++MODULE_DESCRIPTION("Software layer to drive LCD displays under Linux.");
++MODULE_AUTHOR("Mattia Jona-Lasinio <mjona@users.sourceforge.net>");
++#ifdef MODULE_LICENSE
++MODULE_LICENSE("GPL");
++#endif
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
++module_param(minors, ushort, 0444);
++#else
++MODULE_PARM(minors, "h");
++#endif
++MODULE_PARM_DESC(minors, "Minor numbers allocated for LCD-Linux (default: " string(LCD_MINORS) ")");
++#else
++
++/*
++ * Parse boot command line
++ *
++ * lcd=minors
++ */
++static int __init lcd_linux_boot_init(char *cmdline)
++{
++      unsigned short args;
++
++      if ((args = simple_strtoul(cmdline, NULL, 0)))
++              minors = args;
++
++      return (1);
++}
++
++__setup("lcd=", lcd_linux_boot_init);
++#endif /* MODULE */
++
++/* Macros for iterator handling */
++static inline unsigned int iterator_inc_(unsigned int iterator, const unsigned int module)
++{
++      return ((++iterator)%module);
++}
++
++static inline unsigned int iterator_dec_(unsigned int iterator, const unsigned int module)
++{
++      return (iterator ? --iterator : module-1);
++}
++
++#define iterator_inc(iterator, module)                (iterator = iterator_inc_(iterator, module))
++#define iterator_dec(iterator, module)                (iterator = iterator_dec_(iterator, module))
++
++/* Uncomment the following two lines
++ * for non-atomic set_bit and clear_bit
++ */
++//#define set_bit     __set_bit
++//#define clear_bit   __clear_bit
++
++/************************************
++ * Low level routines and utilities *
++ ************************************/
++/*
++ * Set whether the address counter should be incremented
++ * or decremented after a Read/Write
++ */
++static void address_mode(struct lcd_struct *p, int mode)
++{
++      struct lcd_driver *driver = p->driver;
++
++      if (mode > 0 && ! test_bit(INC_CURS_POS, &p->struct_flags)) {
++              if (driver->address_mode)
++                      driver->address_mode(mode);
++              set_bit(INC_CURS_POS, &p->struct_flags);
++      } else if (mode < 0 && test_bit(INC_CURS_POS, &p->struct_flags)) {
++              if (driver->address_mode)
++                      driver->address_mode(mode);
++              clear_bit(INC_CURS_POS, &p->struct_flags);
++      }
++}
++
++/* WARNING!! This function returns an int because if iterator is not
++ * within the visible area of the frame it returns -1
++ */
++static inline int vs_to_frame_(struct lcd_struct *p, unsigned int iterator)
++{
++      unsigned int vs_rows = p->par->vs_rows;
++      unsigned int vs_cols = p->par->vs_cols;
++      unsigned int row = iterator/vs_cols;
++      unsigned int col = iterator%vs_cols;
++      unsigned int frame_base_row = p->frame_base/vs_cols;
++      unsigned int frame_base_col = p->frame_base%vs_cols;
++      unsigned int frame_rows = p->par->cntr_rows*p->par->num_cntr;
++      unsigned int frame_cols = p->par->cntr_cols;
++
++      if (vs_rows == frame_rows && vs_cols == frame_cols)
++              return (iterator);
++
++      if (row < frame_base_row || row >= frame_base_row+frame_rows)
++              return (-1);
++      if (col < frame_base_col || col >= frame_base_col+frame_cols)
++              return (-1);
++
++      return ((row-frame_base_row)*frame_cols+(col-frame_base_col));
++}
++
++/* Given 'iterator' in vs, returns the offset in vs corresponding to the nearest
++ * visible offset in vs, or returns 'iterator' if it is already visible.
++ */
++static unsigned int round_vs_(struct lcd_struct *p, unsigned int iterator)
++{
++      unsigned int vs_rows = p->par->vs_rows;
++      unsigned int vs_cols = p->par->vs_cols;
++      unsigned int row = iterator/vs_cols;
++      unsigned int col = iterator%vs_cols;
++      unsigned int frame_base_row = p->frame_base/vs_cols;
++      unsigned int frame_base_col = p->frame_base%vs_cols;
++      unsigned int frame_rows = p->par->cntr_rows*p->par->num_cntr;
++      unsigned int frame_cols = p->par->cntr_cols;
++
++      if (vs_rows == frame_rows && vs_cols == frame_cols)
++              return (iterator);
++
++      if (row < frame_base_row)
++              row = frame_base_row;
++      else if (row >= frame_base_row+frame_rows)
++              row = frame_base_row+(frame_rows-1);
++
++      if (col < frame_base_col)
++              col = frame_base_col;
++      else if (col >= frame_base_col+frame_cols)
++              col = frame_base_col+(frame_cols-1);
++
++      return ((row*vs_cols)+col);
++}
++
++#define round_vs(p, iterator)                 (iterator = round_vs_(p, iterator))
++
++/*
++ * Sync the frame area starting at offset s, ending at offset e with fb content.
++ */
++static void redraw_screen(struct lcd_struct *p, unsigned int s, unsigned int e)
++{
++      unsigned int len;
++      unsigned int row = p->row, col = p->col;
++      unsigned int inc_set = test_bit(INC_CURS_POS, &p->struct_flags);
++      unsigned int frame_cols = p->par->cntr_cols;
++      unsigned int vs_cols = p->par->vs_cols;
++      unsigned long flags;
++
++      if (s >= p->fb_size || e >= p->fb_size || e < s || e < p->frame_base)
++              return;
++
++      round_vs(p, s);
++      round_vs(p, e);
++
++      len = 1+e-s;
++
++      if (! inc_set)
++              s = e;
++
++      p->row = s/vs_cols;
++      p->col = s%vs_cols;
++
++      flags = p->struct_flags;
++      clear_bit(NEED_WRAP, &p->struct_flags);
++      clear_bit(DECIM, &p->struct_flags);
++      set_bit(DECAWM, &p->struct_flags);
++      SET_INPUT_STATE(p, RAW);
++      if (inc_set)
++              while (len--)
++                      if (vs_to_frame_(p, (p->row*vs_cols)+p->col) < 0) {
++                              s += vs_cols-frame_cols;
++                              len -= vs_cols-frame_cols-1;
++                              p->row = s/vs_cols;
++                              p->col = s%vs_cols;
++                      } else {
++                              write_data(p, p->fb[s++]);
++                              if (test_bit(NEED_WRAP, &p->struct_flags)) {
++                                      cr(p);
++                                      lf(p);
++                              }
++                      }
++      else
++              while (len--)
++                      if (vs_to_frame_(p, (p->row*vs_cols)+p->col) < 0) {
++                              s -= vs_cols-frame_cols;
++                              len -= vs_cols-frame_cols-1;
++                              p->row = s/vs_cols;
++                              p->col = s%vs_cols;
++                      } else {
++                              write_data(p, p->fb[s--]);
++                              if (test_bit(NEED_WRAP, &p->struct_flags)) {
++                                      cr(p);
++                                      lf(p);
++                              }
++                      }
++      p->struct_flags = flags;
++
++      p->row = row; p->col = col;
++}
++
++static int show_cursor(struct lcd_struct *p)
++{
++      unsigned int vs_rows = p->par->vs_rows;
++      unsigned int vs_cols = p->par->vs_cols;
++      unsigned int frame_base, frame_base_row, frame_base_col;
++      unsigned int frame_rows = p->par->cntr_rows*p->par->num_cntr;
++      unsigned int frame_cols = p->par->cntr_cols;
++      unsigned int tmp = frame_cols/2;
++
++      if (vs_rows == frame_rows && vs_cols == frame_cols)
++              return (0);
++
++      if (test_bit(INC_CURS_POS, &p->struct_flags)) {
++      /* cursor always on the lowest row of the display */
++              frame_base_row = 0;
++              frame_base_col = 0;
++              if (p->row >= frame_rows)
++                      frame_base_row = p->row-(frame_rows-1);
++              if (p->col >= frame_cols) {
++                      frame_base_col = p->col-(frame_cols-1);
++                      if (tmp) {
++                              tmp = (tmp-(frame_base_col%tmp))%tmp;
++                              if (frame_base_col+tmp <= vs_cols-frame_cols)
++                                      frame_base_col += tmp;
++                      }
++              }
++      } else {
++      /* cursor always on the uppermost row of the display */
++              frame_base_row = vs_rows-frame_rows;
++              frame_base_col = vs_cols-frame_cols;
++              if (p->row < vs_rows-frame_rows)
++                      frame_base_row = p->row;
++              if (p->col < vs_cols-frame_cols) {
++                      frame_base_col = p->col;
++                      if (tmp) {
++                              tmp = frame_base_col%tmp;
++                              if (frame_base_col >= tmp)
++                                      frame_base_col -= tmp;
++                      }
++              }
++      }
++
++      frame_base = p->frame_base;
++      p->frame_base = (frame_base_row*vs_cols)+frame_base_col;
++
++      return (frame_base != p->frame_base);
++}
++
++/*
++ * Move the visible screen area at user's wish
++ */
++static void browse_screen(struct lcd_struct *p, unsigned char dir)
++{
++      unsigned int vs_rows = p->par->vs_rows;
++      unsigned int vs_cols = p->par->vs_cols;
++      unsigned int frame_base_row = p->frame_base/vs_cols;
++      unsigned int frame_base_col = p->frame_base%vs_cols;
++      unsigned int frame_rows = p->par->cntr_rows*p->par->num_cntr;
++      unsigned int frame_cols = p->par->cntr_cols;
++
++      switch (dir) {
++      case '1':       /* Up */
++              if (! frame_base_row)
++                      return;
++              --frame_base_row;
++              break;
++      case '2':       /* Down */
++              if (frame_base_row >= vs_rows-frame_rows)
++                      return;
++              ++frame_base_row;
++              break;
++      case '3':       /* Left */
++              if (! frame_base_col)
++                      return;
++              --frame_base_col;
++              break;
++      case '4':       /* Right */
++              if (frame_base_col >= vs_cols-frame_cols)
++                      return;
++              ++frame_base_col;
++              break;
++      default:
++              return;
++      }
++
++      p->frame_base = (frame_base_row*vs_cols)+frame_base_col;
++      redraw_screen(p, 0, p->fb_size-1);
++}
++
++static inline void __memset_short(unsigned short *buf, unsigned short c, unsigned int len)
++{
++      while (len--)
++              *buf++ = c;
++}
++
++/*
++ * A memset implementation writing to LCD instead of memory locations.
++ */
++static void lcd_memset(struct lcd_struct *p, unsigned int d, unsigned short c, unsigned int len)
++{
++      unsigned int inc_set = test_bit(INC_CURS_POS, &p->struct_flags);
++
++      if (! len || d >= p->fb_size)
++              return;
++
++      if (inc_set && d+len > p->fb_size)
++              len = p->fb_size-d;
++      else if (! inc_set && len > d+1)
++              len = d+1;
++
++      if (! inc_set)
++              d -= len-1;
++      __memset_short(p->fb+d, c, len);
++
++      if (show_cursor(p))
++              redraw_screen(p, 0, p->fb_size-1);
++      else
++              redraw_screen(p, d, d+(len-1));
++}
++
++static inline void __memcpy_short(unsigned short *d, unsigned short *s, unsigned int len, int dir)
++{
++      if (dir > 0)
++              while (len--)
++                      *d++ = *s++;
++      else
++              while (len--)
++                      *d-- = *s--;
++}
++
++/*
++ * A memmove implementation writing to LCD instead of memory locations.
++ * Copy is done in a non destructive way. Display regions may overlap.
++ */
++static void lcd_memmove(struct lcd_struct *p, unsigned int d, unsigned int s, unsigned int len)
++{
++      if (! len || d == s || d >= p->fb_size || s >= p->fb_size)
++              return;
++
++      if (d < s) {
++              if (test_bit(INC_CURS_POS, &p->struct_flags)) {
++                      if (s+len > p->fb_size)
++                              len = p->fb_size-s;
++              } else {
++                      if (len > d+1)
++                              len = d+1;
++                      d -= len-1;
++                      s -= len-1;
++              }
++              __memcpy_short(p->fb+d, p->fb+s, len, 1);
++              if (show_cursor(p))
++                      redraw_screen(p, 0, p->fb_size-1);
++              else
++                      redraw_screen(p, d, d+(len-1));
++      } else {
++              if (test_bit(INC_CURS_POS, &p->struct_flags)) {
++                      if (d+len > p->fb_size)
++                              len = p->fb_size-d;
++                      d += len-1;
++                      s += len-1;
++              } else {
++                      if (len > s+1)
++                              len = s+1;
++              }
++              __memcpy_short(p->fb+d, p->fb+s, len, -1);
++              if (show_cursor(p))
++                      redraw_screen(p, 0, p->fb_size-1);
++              else
++                      redraw_screen(p, d-(len-1), d);
++      }
++}
++
++static void scrup(struct lcd_struct *p, unsigned int t, unsigned int b, unsigned int nr)
++{
++      unsigned int vs_rows = p->par->vs_rows;
++      unsigned int vs_cols = p->par->vs_cols;
++      unsigned int d, s;
++
++      if (t+nr >= b)
++              nr = b-t-1;
++      if (b > vs_rows || t >= b || nr < 1)
++              return;
++      d = t*vs_cols;
++      s = (t+nr)*vs_cols;
++      if (test_bit(INC_CURS_POS, &p->struct_flags)) {
++              lcd_memmove(p, d, s, (b-t-nr)*vs_cols);
++              lcd_memset(p, d+(b-t-nr)*vs_cols, p->erase_char, nr*vs_cols);
++      } else {
++              lcd_memmove(p, d+(b-t-nr)*vs_cols-1, s+(b-t-nr)*vs_cols-1, (b-t-nr)*vs_cols);
++              lcd_memset(p, d+(b-t)*vs_cols-1, p->erase_char, nr*vs_cols);
++      }
++}
++
++static void scrdown(struct lcd_struct *p, unsigned int t, unsigned int b, unsigned int nr)
++{
++      unsigned int vs_rows = p->par->vs_rows;
++      unsigned int vs_cols = p->par->vs_cols;
++      unsigned int d, s;
++
++      if (t+nr >= b)
++              nr = b-t-1;
++      if (b > vs_rows || t >= b || nr < 1)
++              return;
++      s = t*vs_cols;
++      d = (t+nr)*vs_cols;
++      if (test_bit(INC_CURS_POS, &p->struct_flags)) {
++              lcd_memmove(p, d, s, (b-t-nr)*vs_cols);
++              lcd_memset(p, s, p->erase_char, nr*vs_cols);
++      } else {
++              lcd_memmove(p, d+(b-t-nr)*vs_cols-1, s+(b-t-nr)*vs_cols-1, (b-t-nr)*vs_cols);
++              lcd_memset(p, s+nr*vs_cols-1, p->erase_char, nr*vs_cols);
++      }
++}
++
++static void lcd_insert_char(struct lcd_struct *p, unsigned int nr)
++{
++      unsigned int vs_cols = p->par->vs_cols;
++      unsigned int pos = (p->row*vs_cols)+p->col;
++
++      clear_bit(NEED_WRAP, &p->struct_flags);
++      if (test_bit(INC_CURS_POS, &p->struct_flags))
++              lcd_memmove(p, pos+nr, pos, vs_cols-p->col-nr);
++      else
++              lcd_memmove(p, pos-nr, pos, p->col-(nr-1));
++      lcd_memset(p, pos, p->erase_char, nr);
++}
++
++static void lcd_delete_char(struct lcd_struct *p, unsigned int nr)
++{
++      unsigned int vs_cols = p->par->vs_cols;
++      unsigned int pos = (p->row*vs_cols)+p->col;
++
++      clear_bit(NEED_WRAP, &p->struct_flags);
++      if (test_bit(INC_CURS_POS, &p->struct_flags)) {
++              lcd_memmove(p, pos, pos+nr, vs_cols-(p->col+nr));
++              lcd_memset(p, (p->row+1)*vs_cols-nr, p->erase_char, nr);
++      } else {
++              lcd_memmove(p, pos, pos-nr, p->col-(nr-1));
++              lcd_memset(p, (p->row*vs_cols)+(nr-1), p->erase_char, nr);
++      }
++}
++
++
++
++
++
++/******************************************************************************
++ *************************      VT 102 Emulation      *************************
++ ******************************************************************************/
++
++/**********************
++ * Control characters *
++ **********************/
++static void bs(struct lcd_struct *p)
++{
++      clear_bit(NEED_WRAP, &p->struct_flags);
++      if (test_bit(INC_CURS_POS, &p->struct_flags)) {
++              if (p->col)
++                      --p->col;
++      } else {
++              if (p->col+1 < p->par->vs_cols)
++                      ++p->col;
++      }
++}
++
++static void cr(struct lcd_struct *p)
++{
++      clear_bit(NEED_WRAP, &p->struct_flags);
++      p->col = (test_bit(INC_CURS_POS, &p->struct_flags) ? 0 : p->par->vs_cols-1);
++}
++
++static void lf(struct lcd_struct *p)
++{
++      clear_bit(NEED_WRAP, &p->struct_flags);
++      if (test_bit(INC_CURS_POS, &p->struct_flags)) {
++              if (p->row+1 < p->bot)
++                      ++p->row;
++              else if (INPUT_STATE(p) != RAW) {
++                      show_cursor(p);
++                      scrup(p, p->top, p->bot, 1);
++              }
++      } else {
++              if (p->row > p->top)
++                      --p->row;
++              else if (INPUT_STATE(p) != RAW) {
++                      show_cursor(p);
++                      scrdown(p, p->top, p->bot, 1);
++              }
++      }
++}
++
++static void ri(struct lcd_struct *p)
++{
++      clear_bit(NEED_WRAP, &p->struct_flags);
++      if (test_bit(INC_CURS_POS, &p->struct_flags)) {
++              if (p->row > p->top)
++                      --p->row;
++              else {
++                      show_cursor(p);
++                      scrdown(p, p->top, p->bot, 1);
++              }
++      } else {
++              if (p->row+1 < p->bot)
++                      ++p->row;
++              else {
++                      show_cursor(p);
++                      scrup(p, p->top, p->bot, 1);
++              }
++      }
++}
++
++static void ff(struct lcd_struct *p)
++{
++      unsigned int vs_rows = p->par->vs_rows;
++      unsigned int vs_cols = p->par->vs_cols;
++
++      clear_bit(NEED_WRAP, &p->struct_flags);
++      if (p->driver->clear_display) {
++              p->driver->clear_display();
++              __memset_short(p->fb, p->erase_char, p->fb_size);
++              __memset_short(p->display, p->erase_char, p->frame_size);
++              p->frame_base = 0;
++      } else if (test_bit(INC_CURS_POS, &p->struct_flags))
++              lcd_memset(p, 0, p->erase_char, p->fb_size);
++      else
++              lcd_memset(p, p->fb_size-1, p->erase_char, p->fb_size);
++
++      if (test_bit(INC_CURS_POS, &p->struct_flags))
++              p->row = p->col = 0;
++      else {
++              p->row = vs_rows-1;
++              p->col = vs_cols-1;
++      }
++}
++
++static void tab(struct lcd_struct *p)
++{
++      struct lcd_parameters *par = p->par;
++      unsigned int i, vs_cols = par->vs_cols;
++
++      clear_bit(NEED_WRAP, &p->struct_flags);
++
++      if (! par->tabstop)
++              return;
++
++      if (test_bit(INC_CURS_POS, &p->struct_flags)) {
++              i = par->tabstop-(p->col%par->tabstop);
++              if (p->col+i < vs_cols)
++                      p->col += i;
++      } else {
++              i = p->col%par->tabstop;
++              i = (i == 0 ? par->tabstop : i);
++              if (p->col >= i)
++                      p->col -= i;
++      }
++}
++
++/*
++ * Control character handler.
++ */
++static void control_char(struct lcd_struct *p, unsigned char val)
++{
++      switch (val) {
++      case 0x08:      /* BS: Back Space (^H) */
++      case 0x7f:      /* DEL: Delete */
++              bs(p);
++              return;
++
++      case 0x09:      /* HT: Horizontal Tab (^I) */
++              tab(p);
++              return;
++
++      case 0x0c:      /* FF: Form Feed (^L) */
++              ff(p);
++              return;
++
++      case 0x0a:      /* LF: Line Feed (^J) */
++      case 0x0b:      /* VT: Vertical Tab (^K) */
++              lf(p);
++              if (! test_bit(CRLF, &p->struct_flags))
++                      return;
++
++      case 0x0d:      /* CR: Carriage Return (^M) */
++              cr(p);
++              return;
++
++      case 0x16:      /* SYN: Synchronous Idle (^V) */
++              SET_INPUT_STATE(p, SYN);
++              return;
++
++      case 0x1b:      /* ESC: Start of escape sequence */
++              SET_INPUT_STATE(p, ESC);
++              return;
++
++      case 0x9b:      /* CSI: Start of CSI escape sequence */
++              memset(p->csi_args, 0, sizeof(p->csi_args));
++              p->index = 0;
++              SET_INPUT_STATE(p, CSI);
++              return;
++      }
++}
++
++static void gotoxy(struct lcd_struct *p, int new_col, int new_row)
++{
++      unsigned int vs_rows = p->par->vs_rows;
++      unsigned int vs_cols = p->par->vs_cols;
++      int min_row, max_row;
++
++      clear_bit(NEED_WRAP, &p->struct_flags);
++      if (test_bit(DECOM, &p->struct_flags)) {
++              min_row = p->top;
++              max_row = p->bot;
++      } else {
++              min_row = 0;
++              max_row = vs_rows;
++      }
++
++      if (new_row < min_row)
++              p->row = min_row;
++      else if (new_row >= max_row)
++              p->row = max_row-1;
++      else
++              p->row = new_row;
++
++      if (new_col < 0)
++              p->col = 0;
++      else if (new_col >= vs_cols)
++              p->col = vs_cols-1;
++      else
++              p->col = new_col;
++
++      if (show_cursor(p))
++              redraw_screen(p, 0, p->fb_size-1);
++}
++
++static void gotoxay(struct lcd_struct *p, int new_col, int new_row)
++{
++      gotoxy(p, new_col, test_bit(DECOM, &p->struct_flags) ? (p->top+new_row) : new_row);
++}
++
++
++/******************************
++ * ECMA-48 CSI ESC- sequences *
++ ******************************/
++static void csi_at(struct lcd_struct *p, unsigned int nr)
++{
++      unsigned int vs_cols = p->par->vs_cols;
++
++      if (p->col+nr > vs_cols)
++              nr = vs_cols-p->col;
++      else if (! nr)
++              ++nr;
++      lcd_insert_char(p, nr);
++}
++
++static void csi_J(struct lcd_struct *p, unsigned int action)
++{
++      unsigned int vs_cols = p->par->vs_cols;
++      unsigned int pos = (p->row*vs_cols)+p->col;
++
++      clear_bit(NEED_WRAP, &p->struct_flags);
++      switch (action) {
++      case 0:         /* From cursor to end of display */
++              lcd_memset(p, pos, p->erase_char, p->fb_size-pos);
++              return;
++
++      case 1:         /* From start of display to cursor */
++              lcd_memset(p, 0, p->erase_char, pos+1);
++              return;
++
++      case 2:         /* Whole display */
++              lcd_memset(p, 0, p->erase_char, p->fb_size);
++              return;
++      }
++}
++
++static void csi_K(struct lcd_struct *p, unsigned int action)
++{
++      unsigned int vs_cols = p->par->vs_cols;
++      unsigned int row_start = p->row*vs_cols;
++
++      clear_bit(NEED_WRAP, &p->struct_flags);
++      switch (action) {
++      case 0:         /* From cursor to end of line */
++              lcd_memset(p, row_start+p->col, p->erase_char, vs_cols-p->col);
++              return;
++
++      case 1:         /* From start of line to cursor */
++              lcd_memset(p, row_start, p->erase_char, p->col+1);
++              return;
++
++      case 2:         /* Whole line */
++              lcd_memset(p, row_start, p->erase_char, vs_cols);
++              return;
++      }
++}
++
++static void csi_L(struct lcd_struct *p, unsigned int nr)
++{
++      unsigned int vs_rows = p->par->vs_rows;
++      unsigned int vs_cols = p->par->vs_cols;
++
++      clear_bit(NEED_WRAP, &p->struct_flags);
++      if (p->row+nr > vs_rows)
++              nr = vs_rows-p->row;
++      else if (! nr)
++              ++nr;;
++      lcd_memmove(p, (p->row+nr)*vs_cols, p->row*vs_cols, (vs_rows-p->row-nr)*vs_cols);
++      lcd_memset(p, p->row*vs_cols, p->erase_char, nr*vs_cols);
++}
++
++static void csi_M(struct lcd_struct *p, unsigned int nr)
++{
++      unsigned int vs_rows = p->par->vs_rows;
++      unsigned int vs_cols = p->par->vs_cols;
++
++      clear_bit(NEED_WRAP, &p->struct_flags);
++      if (p->row+nr > vs_rows)
++              nr = vs_rows-p->row;
++      else if (! nr)
++              ++nr;;
++      lcd_memmove(p, p->row*vs_cols, (p->row+nr)*vs_cols, (vs_rows-p->row-nr)*vs_cols);
++      lcd_memset(p, (vs_rows-nr)*vs_cols, p->erase_char, nr*vs_cols);
++}
++
++static void csi_P(struct lcd_struct *p, unsigned int nr)
++{
++      unsigned int vs_cols = p->par->vs_cols;
++
++      if (p->col+nr > vs_cols)
++              nr = vs_cols-p->col;
++      else if (! nr)
++              ++nr;
++      lcd_delete_char(p, nr);
++}
++
++static void csi_X(struct lcd_struct *p, unsigned int nr)
++{
++      unsigned int vs_cols = p->par->vs_cols;
++
++      clear_bit(NEED_WRAP, &p->struct_flags);
++      if (p->col+nr > vs_cols)
++              nr = vs_cols-p->col;
++      else if (! nr)
++              ++nr;
++      lcd_memset(p, (p->row*vs_cols)+p->col, p->erase_char, nr);
++}
++
++static void csi_su(struct lcd_struct *p, unsigned char input)
++{
++      unsigned int vs_cols = p->par->vs_cols;
++
++      clear_bit(NEED_WRAP, &p->struct_flags);
++      if (input == 'u') {
++              p->row = p->s_offset/vs_cols;
++              p->col = p->s_offset%vs_cols;
++              p->color = p->s_color;
++              p->attributes = p->s_attributes;
++              return;
++      }
++      p->s_offset = (p->row*vs_cols)+p->col;
++      p->s_color = p->color;
++      p->s_attributes = p->attributes;
++}
++
++static inline unsigned char reverse_color_attr(unsigned char attr)
++{
++      return ((attr & (BG_BRIGHT | FG_BRIGHT)) | ((attr & BG_COLOR) >> 4) | ((attr & FG_COLOR) << 4));
++}
++
++static unsigned char build_attr(struct lcd_struct *p, unsigned char color, unsigned char intensity,
++                              unsigned char blink, unsigned char underline, unsigned char reverse)
++{
++      unsigned char attr;
++
++      if (test_bit(CAN_DO_COLOR, &p->struct_flags)) {
++              attr = color;
++              if (underline)
++                      attr = (attr & BG_MASK) | p->ulcolor;
++              else if (intensity == 0)
++                      attr = (attr & BG_MASK) | p->halfcolor;
++              if (reverse)
++                      attr = reverse_color_attr(attr);
++              if (blink)
++                      attr ^= BG_BRIGHT;
++              if (intensity == 2)
++                      attr ^= FG_BRIGHT;
++      } else {
++              attr = intensity;
++              attr |= (underline ? ULINE : 0x00);
++              attr |= (reverse ? REVERSE : 0x00);
++              attr |= (blink ? BLINK : 0x00);
++      }
++
++      return (attr);
++}
++
++static void update_attr(struct lcd_struct *p)
++{
++      unsigned char intensity = p->attributes & I_MASK;
++      unsigned char underline = (p->attributes & ULINE) ? 0x01 : 0x00;
++      unsigned char reverse = (p->attributes & REVERSE) ? 0x01 : 0x00;
++      unsigned char blink = (p->attributes & BLINK) ? 0x01 : 0x00;
++      unsigned char decscnm = test_bit(DECSCNM, &p->struct_flags) ? 0x01 : 0x00;
++
++      p->attr = build_attr(p, p->color, intensity, blink, underline, reverse ^ decscnm);
++      p->erase_char = (build_attr(p, p->color, 1, blink, 0, decscnm) << 8) | ' ';
++}
++
++static void default_attr(struct lcd_struct *p)
++{
++      p->attributes = 0x01;
++      p->color = p->defcolor;
++}
++
++static void lcd_invert_screen(struct lcd_struct *p, unsigned int s, unsigned int len)
++{
++      unsigned int l, inc_set = test_bit(INC_CURS_POS, &p->struct_flags);
++
++      if (! len || s >= p->fb_size)
++              return;
++      if (inc_set && s+len > p->fb_size)
++              len = p->fb_size-s;
++      else if (! inc_set && len > s+1)
++              len = s+1;
++
++      l = len;
++      if (test_bit(CAN_DO_COLOR, &p->struct_flags))
++              while (l--) {
++                      p->fb[s] = (reverse_color_attr(p->fb[s] >> 8) << 8) | (p->fb[s] & 0xff);
++                      ++s;
++              }
++      else
++              while (l--) {
++                      p->fb[s] ^= REVERSE << 8;
++                      ++s;
++              }
++
++      if (show_cursor(p))
++              redraw_screen(p, 0, p->fb_size-1);
++      else
++              redraw_screen(p, s, s+(len-1));
++}
++
++static void csi_m(struct lcd_struct *p, unsigned int n)
++{
++      int i, arg;
++
++      for (i = 0; i <= n; ++i)
++              switch ((arg = p->csi_args[i]))
++              {
++                      case 0:
++                              default_attr(p);
++                              break;
++
++                      case 1:
++                              p->attributes = (p->attributes & ~I_MASK) | 2;
++                              break;
++
++                      case 2:
++                              p->attributes = (p->attributes & ~I_MASK) | 0;
++                              break;
++
++                      case 4:
++                              p->attributes |= ULINE;
++                              break;
++
++                      case 5:
++                              p->attributes |= BLINK;
++                              break;
++
++                      case 7:
++                              p->attributes |= REVERSE;
++                              break;
++
++                      case 21: case 22:
++                              p->attributes = (p->attributes & ~I_MASK) | 1;
++                              break;
++
++                      case 24:
++                              p->attributes &= ~ULINE;
++                              break;
++
++                      case 25:
++                              p->attributes &= ~BLINK;
++                              break;
++
++                      case 27:
++                              p->attributes &= ~REVERSE;
++                              break;
++
++                      case 38:
++                              p->attributes |= ULINE;
++                              p->color = (p->color & BG_MASK) | (p->defcolor & FG_MASK);
++                              break;
++
++                      case 39:
++                              p->attributes &= ~ULINE;
++                              p->color = (p->color & BG_MASK) | (p->defcolor & FG_MASK);
++                              break;
++
++                      case 49:
++                              p->color = (p->defcolor & BG_MASK) | (p->color & FG_MASK);
++                              break;
++
++                      default:
++                              if (arg >= 30 && arg <= 37)
++                                      p->color = (p->color & BG_MASK) | color_table[arg-30];
++                              else if (arg >= 40 && arg <= 47)
++                                      p->color = (p->color & FG_MASK) | (color_table[arg-40] << 4);
++                              break;
++              }
++
++      update_attr(p);
++}
++
++static void csi_h(struct lcd_struct *p, unsigned char n)
++{
++      switch (n) {
++              case 4:         /* Set insert mode */
++                      set_bit(DECIM, &p->struct_flags);
++                      return;
++
++              case 5:         /* Inverted screen mode */
++                      if (test_bit(QUES, &p->struct_flags) && ! test_bit(DECSCNM, &p->struct_flags)) {
++                              lcd_invert_screen(p, 0, p->fb_size);
++                              set_bit(DECSCNM, &p->struct_flags);
++                              update_attr(p);
++                      }
++                      return;
++
++              case 6:         /* Cursor addressing origin: relative to scrolling region */
++                      if (test_bit(QUES, &p->struct_flags)) {
++                              set_bit(DECOM, &p->struct_flags);
++                              gotoxay(p, 0, 0);
++                      }
++                      return;
++
++              case 7:         /* Set autowrap */
++                      if (test_bit(QUES, &p->struct_flags))
++                              set_bit(DECAWM, &p->struct_flags);
++                      return;
++
++              case 20:        /* Set cr lf */
++                      set_bit(CRLF, &p->struct_flags);
++                      return;
++      }
++}
++
++static void csi_l(struct lcd_struct *p, unsigned char n)
++{
++      switch (n) {
++              case 4:         /* Reset insert mode */
++                      clear_bit(DECIM, &p->struct_flags);
++                      return;
++
++              case 5:         /* Normal screen mode */
++                      if (test_bit(QUES, &p->struct_flags) && test_bit(DECSCNM, &p->struct_flags)) {
++                              lcd_invert_screen(p, 0, p->fb_size);
++                              clear_bit(DECSCNM, &p->struct_flags);
++                              update_attr(p);
++                      }
++                      return;
++
++              case 6:         /* Cursor addressing origin: absolute origin */
++                      if (test_bit(QUES, &p->struct_flags)) {
++                              clear_bit(DECOM, &p->struct_flags);
++                              gotoxay(p, 0, 0);
++                      }
++                      return;
++
++              case 7:         /* Reset autowrap */
++                      if (test_bit(QUES, &p->struct_flags))
++                              clear_bit(DECAWM, &p->struct_flags);
++                      return;
++
++              case 20:        /* Reset cr lf */
++                      clear_bit(CRLF, &p->struct_flags);
++                      return;
++      }
++}
++
++static void csi_linux(struct lcd_struct *p)
++{
++      switch (p->csi_args[0]) {
++      case 1:
++              if (test_bit(CAN_DO_COLOR, &p->struct_flags) && p->csi_args[1] < 16) {
++                      p->ulcolor = color_table[p->csi_args[1]];
++                      if (p->attributes & ULINE)
++                              update_attr(p);
++              }
++              return;
++
++      case 2:
++              if (test_bit(CAN_DO_COLOR, &p->struct_flags) && p->csi_args[1] < 16) {
++                      p->halfcolor = color_table[p->csi_args[1]];
++                      if ((p->attributes & I_MASK) == 0)
++                              update_attr(p);
++              }
++              return;
++
++      case 8:
++              p->defcolor = p->color;
++              default_attr(p);
++              update_attr(p);
++              return;
++      }
++}
++
++static void csi_r(struct lcd_struct *p, unsigned int top, unsigned int bot)
++{
++      /* Minimum allowed region is 2 lines */
++      if (top < bot) {
++              p->top = top-1;
++              p->bot = bot;
++              gotoxay(p, 0, 0);
++      }
++}
++
++/*
++ * ECMA-48 CSI ESC- sequence handler.
++ */
++static void handle_csi(struct lcd_struct *p, unsigned char input)
++{
++      if (p->index >= NPAR) {
++              SET_INPUT_STATE(p, NORMAL);
++              printk(KERN_NOTICE "LCD: too many parameters in CSI escape sequence\n");
++      } else if (input == '?') {
++              set_bit(QUES, &p->struct_flags);
++      } else if (input == ';') {
++              ++p->index;
++      } else if (input >= '0' && input <= '9') {
++              p->csi_args[p->index] = (p->csi_args[p->index]*10)+(input-'0');
++      } else {
++              SET_INPUT_STATE(p, NORMAL);
++              if (! test_bit(INC_CURS_POS, &p->struct_flags))
++                      return;
++              switch (input) {
++              case 'h':               /* DECSET sequences and mode switches */
++                      csi_h(p, p->csi_args[0]);
++                      clear_bit(QUES, &p->struct_flags);
++                      return;
++
++              case 'l':               /* DECRST sequences and mode switches */
++                      csi_l(p, p->csi_args[0]);
++                      clear_bit(QUES, &p->struct_flags);
++                      return;
++              }
++              clear_bit(QUES, &p->struct_flags);
++              switch (input) {
++              case '@':               /* Insert # Blank character */
++                      csi_at(p, p->csi_args[0]);
++                      return;
++
++              case 'G': case '`':     /* Cursor to indicated column in current row */
++                      if (p->csi_args[0])
++                              --p->csi_args[0];
++                      gotoxy(p, p->csi_args[0], p->row);
++                      return;
++
++              case 'A':               /* Cursor # rows Up */
++                      if (! p->csi_args[0])
++                              ++p->csi_args[0];
++                      gotoxy(p, p->col, p->row-p->csi_args[0]);
++                      return;
++
++              case 'B': case 'e':     /* Cursor # rows Down */
++                      if (! p->csi_args[0])
++                              ++p->csi_args[0];
++                      gotoxy(p, p->col, p->row+p->csi_args[0]);
++                      return;
++
++              case 'C': case 'a':     /* Cursor # columns Right */
++                      if (! p->csi_args[0])
++                              ++p->csi_args[0];
++                      gotoxy(p, p->col+p->csi_args[0], p->row);
++                      return;
++
++              case 'D':               /* Cursor # columns Left */
++                      if (! p->csi_args[0])
++                              ++p->csi_args[0];
++                      gotoxy(p, p->col-p->csi_args[0], p->row);
++                      return;
++
++              case 'E':               /* Cursor # rows Down, column 1 */
++                      if (! p->csi_args[0])
++                              ++p->csi_args[0];
++                      gotoxy(p, 0, p->row+p->csi_args[0]);
++                      return;
++
++              case 'F':               /* Cursor # rows Up, column 1 */
++                      if (! p->csi_args[0])
++                              ++p->csi_args[0];
++                      gotoxy(p, 0, p->row-p->csi_args[0]);
++                      return;
++
++              case 'd':               /* Cursor to indicated row in current column */
++                      if (p->csi_args[0])
++                              --p->csi_args[0];
++                      gotoxay(p, p->col, p->csi_args[0]);
++                      return;
++
++              case 'H': case 'f':     /* Cursor to indicated row, column (origin 1, 1) */
++                      if (p->csi_args[0])
++                              --p->csi_args[0];
++                      if (p->csi_args[1])
++                              --p->csi_args[1];
++                      gotoxay(p, p->csi_args[1], p->csi_args[0]);
++                      return;
++
++              case 'J':               /* Erase display */
++                      csi_J(p, p->csi_args[0]);
++                      return;
++
++              case 'K':               /* Erase line */
++                      csi_K(p, p->csi_args[0]);
++                      return;
++
++              case 'L':               /* Insert # blank lines */
++                      csi_L(p, p->csi_args[0]);
++                      return;
++
++              case 'M':               /* Delete # blank lines */
++                      csi_M(p, p->csi_args[0]);
++                      return;
++
++              case 'P':               /* Delete # characters on the current line */
++                      csi_P(p, p->csi_args[0]);
++                      return;
++
++              case 'X':               /* Erase # characters on the current line */
++                      csi_X(p, p->csi_args[0]);
++                      return;
++
++              case 'm':               /* Set video attributes */
++                      csi_m(p, p->index);
++                      return;
++
++              case 's':               /* Save cursor position */
++              case 'u':               /* Restore cursor position */
++                      csi_su(p, input);
++                      return;
++
++              case ']':               /* Linux private ESC [ ] sequence */
++                      csi_linux(p);
++                      return;
++
++              case 'r':               /* Set the scrolling region */
++                      if (! p->csi_args[0])
++                              ++p->csi_args[0];
++                      if (! p->csi_args[1] || p->csi_args[1] > p->par->vs_rows)
++                              p->csi_args[1] = p->par->vs_rows;
++                      csi_r(p, p->csi_args[0], p->csi_args[1]);
++                      return;
++
++                                      /* Ignored escape sequences */
++              case 'c':
++              case 'g':
++              case 'n':
++              case 'q':
++                      return;
++
++              default:
++                      printk(KERN_NOTICE "LCD: unrecognized CSI escape sequence: ESC [ %u\n", input);
++                      return;
++              }
++      }
++}
++
++/*
++ * Custom ESC- sequence handler.
++ */
++static int handle_custom_esc(struct lcd_struct *p, unsigned int _input)
++{
++      unsigned char input = _input & 0xff;
++      struct lcd_parameters *par = p->par;
++
++      if (_input & (~0xff)) {
++              switch (ESC_STATE(p)) {
++              case 's':
++                      if (p->index++) {
++                              unsigned char *cgbuf = p->cgram_buffer-par->cgram_bytes;
++
++                              cgbuf[p->index-2] = input;
++                              if (p->index == par->cgram_bytes+1)
++                                      write_cgram(p, p->cgram_index, cgbuf);
++                      } else {
++                              if (! p->driver->write_cgram_char) {
++                                      printk(KERN_ERR "LCD: %s: missing function to write to CGRAM\n", p->par->name);
++                                      return (-1);
++                              }
++                              if (input >= par->cgram_char0 && input < par->cgram_char0+par->cgram_chars)
++                                      p->cgram_index = input;
++                              else {
++                                      printk(KERN_NOTICE "LCD: bad CGRAM index\n");
++                                      return (-1);
++                              }
++                      }
++                      return (0);
++
++              case 'G':
++                      if (input >= par->cgram_char0 && input < par->cgram_char0+par->cgram_chars)
++                              write_data(p, (p->attr << 8) | p->driver->charmap[input]);
++                      else {
++                              SET_INPUT_STATE(p, NORMAL);
++                              handle_input(p, (p->attr << 8) | input);
++                      }
++                      return (0);
++
++              case 'r':
++                      if (input == '1')
++                              address_mode(p, -1);
++                      else if (input == '0')
++                              address_mode(p, 1);
++                      return (0);
++
++              case 'A':
++                      scrup(p, p->top, p->bot, input);
++                      return (0);
++
++              case 'B':
++                      scrdown(p, p->top, p->bot, input);
++                      return (0);
++
++              case 'C':
++                      browse_screen(p, input);
++                      return (0);
++              }
++      }
++
++      /* These are the custom ESC- sequences */
++      switch (input) {
++      case 's':       /* CGRAM select */
++              if (p->cgram_buffer) {
++                      SET_ESC_STATE(p, input);
++                      p->index = 0;
++                      return (par->cgram_bytes+1);
++              } else {
++                      printk(KERN_NOTICE "LCD: driver %s does not support CGRAM chars\n", par->name);
++                      return (0);
++              }
++
++      case 'A':       /* Scroll up */
++      case 'B':       /* Scroll down */
++      case 'C':       /* Browse screen */
++      case 'G':       /* Enter cgram mode */
++      case 'r':       /* Decrement counter after data read/write */
++              SET_ESC_STATE(p, input);
++              return (1);
++      }
++
++      return (-1);
++}
++
++/*
++ * ESC- but not CSI sequence handler.
++ */
++static int handle_esc(struct lcd_struct *p, unsigned char input)
++{
++      int ret;
++
++      SET_INPUT_STATE(p, NORMAL);
++      switch (input) {
++      case 'c':       /* Reset */
++              set_bit(DECAWM, &p->struct_flags);
++              set_bit(INC_CURS_POS, &p->struct_flags);
++              ff(p);
++              return (0);
++
++      case 'D':       /* Line Feed */
++              lf(p);
++              return (0);
++
++      case 'E':       /* New Line */
++              cr(p);
++              lf(p);
++              return (0);
++
++      case 'M':       /* Reverse Line Feed */
++              ri(p);
++              return (0);
++
++      case '7':
++      case '8':
++              csi_su(p, (input == '7' ? 's' : 'u'));
++              return (0);
++
++      /* CSI: Start of CSI escape sequence */
++      case '[':
++              memset(p->csi_args, 0, sizeof(p->csi_args));
++              p->index = 0;
++              SET_INPUT_STATE(p, CSI);
++              return (0);
++
++      /* Ignored escape sequences */
++      case '(':
++              SET_INPUT_STATE(p, ESC_G0);
++              return (1);
++
++      case ')':
++              SET_INPUT_STATE(p, ESC_G1);
++              return (1);
++
++      case '#':
++              SET_INPUT_STATE(p, ESC_HASH);
++              return (1);
++
++      case '%':
++              SET_INPUT_STATE(p, ESC_PERCENT);
++              return (1);
++
++      case 'H':
++      case 'Z':
++      case '>':
++      case '=':
++      case ']':
++              return (0);
++      }
++
++      /* These are the custom ESC- sequences */
++      if ((ret = handle_custom_esc(p, input)) > 0) {
++              SET_INPUT_STATE(p, ARG);
++              return (ret);
++      }
++
++      if (ret < 0 && p->driver->handle_custom_char)
++              if ((ret = p->driver->handle_custom_char(input)) > 0) {
++                      SET_INPUT_STATE(p, ARG_DRIVER);
++                      return (ret);
++              }
++
++      if (ret < 0)
++              printk(KERN_NOTICE "LCD: unrecognized escape sequence: ESC %u\n", input);
++
++      return (0);
++}
++
++/*
++ * Main input handler.
++ */
++static void handle_input(struct lcd_struct *p, unsigned short _input)
++{
++      unsigned char input = _input & 0xff;
++      struct lcd_driver *driver = p->driver;
++
++      switch (INPUT_STATE(p)) {
++      case NORMAL:
++              if (input < 0x20 || input == 0x9b)
++                      control_char(p, input);
++              else
++                      write_data(p, (_input & 0xff00) | driver->charmap[input]);
++              return;
++
++      case RAW:
++              write_data(p, (_input & 0xff00) | driver->charmap[input]);
++              return;
++
++      case SYN:
++              write_data(p, _input);
++              SET_INPUT_STATE(p, NORMAL);
++              return;
++
++      case ESC:
++              p->esc_args = handle_esc(p, input);
++              return;
++
++      case ESC_G0:
++      case ESC_G1:
++      case ESC_HASH:
++      case ESC_PERCENT:
++              if (! --p->esc_args)
++                      SET_INPUT_STATE(p, NORMAL);
++              return;
++
++      case CSI:
++              handle_csi(p, input);
++              return;
++
++      case ARG:
++              if (handle_custom_esc(p, 0x100 | input) || ! --p->esc_args)
++                      SET_INPUT_STATE(p, NORMAL);
++              return;
++
++      case ARG_DRIVER:
++              if (driver->handle_custom_char(0x100 | input) || ! --p->esc_args)
++                      SET_INPUT_STATE(p, NORMAL);
++              return;
++      }
++}
++
++
++
++
++
++/***************************************
++ * Read from/Write to display routines *
++ ***************************************/
++
++/*
++ * Write character data to the display.
++ */
++static void write_data(struct lcd_struct *p, unsigned short data)
++{
++      unsigned int vs_cols = p->par->vs_cols;
++      unsigned int pos;
++      int frame_pos;
++
++      if (test_bit(NEED_WRAP, &p->struct_flags)) {
++              cr(p);
++              lf(p);
++      }
++
++      if (test_bit(DECIM, &p->struct_flags))
++              lcd_insert_char(p, 1);
++
++      pos = (p->row*vs_cols)+p->col;
++      if ((frame_pos = vs_to_frame_(p, pos)) < 0) {
++              show_cursor(p);
++              redraw_screen(p, 0, p->fb_size-1);
++              frame_pos = vs_to_frame_(p, pos);
++      }
++
++      if (p->display[frame_pos] != data) {
++              p->driver->write_char(frame_pos, data);
++              p->display[frame_pos] = data;
++      }
++
++      p->fb[pos] = data;
++
++      if (test_bit(INC_CURS_POS, &p->struct_flags)) {
++              if (p->col+1 < vs_cols)
++                      iterator_inc(p->col, vs_cols);
++              else if (test_bit(DECAWM, &p->struct_flags))
++                      set_bit(NEED_WRAP, &p->struct_flags);
++      } else {
++              if (p->col)
++                      iterator_dec(p->col, vs_cols);
++              else if (test_bit(DECAWM, &p->struct_flags))
++                      set_bit(NEED_WRAP, &p->struct_flags);
++      }
++}
++
++/*
++ * Write an entire CGRAM character to the display.
++ */
++static void write_cgram(struct lcd_struct *p, unsigned char index, unsigned char *pixels)
++{
++      struct lcd_parameters *par = p->par;
++      unsigned int inc_set = test_bit(INC_CURS_POS, &p->struct_flags);
++      unsigned char *cgbuf = p->cgram_buffer+(index-par->cgram_char0)*par->cgram_bytes;
++
++      if (! strncmp(cgbuf, pixels, par->cgram_bytes))
++              return;
++
++      if (! inc_set)
++              address_mode(p, 1);
++
++      p->driver->write_cgram_char(index, pixels);
++      memcpy(cgbuf, pixels, par->cgram_bytes);
++
++      if (! inc_set)
++              address_mode(p, -1);
++}
++
++/*
++ * Read character data from the display.
++ */
++static void read_data(struct lcd_struct *p, unsigned short *data)
++{
++      unsigned int vs_rows = p->par->vs_rows;
++      unsigned int vs_cols = p->par->vs_cols;
++      unsigned int pos = (p->row*vs_cols)+p->col;
++      int frame_pos;
++
++      if ((frame_pos = vs_to_frame_(p, pos)) < 0) {
++              show_cursor(p);
++              redraw_screen(p, 0, p->fb_size-1);
++              frame_pos = vs_to_frame_(p, pos);
++      }
++
++      if (p->driver->read_char)
++              p->driver->read_char(frame_pos, data);
++      else
++              *data = p->fb[pos];
++
++      if (test_bit(INC_CURS_POS, &p->struct_flags)) {
++              iterator_inc(p->col, vs_cols);
++              if (! p->col) {
++                      if (p->row+1 < vs_rows)
++                              ++p->row;
++              }
++      } else {
++              iterator_dec(p->col, vs_cols);
++              if (p->col+1 == vs_cols) {
++                      if (p->row)
++                              --p->row;
++              }
++      }
++}
++
++/*
++ * Read an entire CGRAM character from the display.
++ */
++static void read_cgram(struct lcd_struct *p, unsigned char index, unsigned char *pixels)
++{
++      struct lcd_parameters *par = p->par;
++      unsigned int inc_set = test_bit(INC_CURS_POS, &p->struct_flags);
++      unsigned char *cgbuf = p->cgram_buffer+(index-par->cgram_char0)*par->cgram_bytes;
++
++      if (! p->driver->read_cgram_char) {
++              memcpy(pixels, cgbuf, par->cgram_bytes);
++              return;
++      }
++
++      if (! inc_set)
++              address_mode(p, 1);
++
++      p->driver->read_cgram_char(index, pixels);
++
++      if (! inc_set)
++              address_mode(p, -1);
++}
++
++
++
++
++
++/****************************
++ * Proc filesystem routines *
++ ****************************/
++#ifdef USE_PROC
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
++/* create_proc_read_entry is missing in 2.2.x kernels */
++static struct proc_dir_entry *create_proc_read_entry(const char *name, mode_t mode,
++                      struct proc_dir_entry *parent, read_proc_t *read_proc, void *data)
++{
++      struct proc_dir_entry *res = create_proc_entry(name, mode, parent);
++
++      if (res) {
++              res->read_proc = read_proc;
++              res->data = data;
++      }
++
++      return (res);
++}
++#endif
++
++static int proc_fb_read(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
++{
++      char *temp = buffer;
++      struct lcd_struct *p = (struct lcd_struct *)data;
++      unsigned int vs_cols;
++      static unsigned int nr, need_wrap;
++      static off_t _offset;
++
++      down(&p->lcd_sem);
++      if (! offset)
++              _offset = 0;
++      if ((*eof = (_offset >= p->fb_size))) {
++              up(&p->lcd_sem);
++              return (0);
++      }
++      vs_cols = p->par->vs_cols;
++      if (size && need_wrap) {
++              need_wrap = 0;
++              temp += sprintf(temp, "\n");
++              --size;
++      }
++      if (! nr)
++              nr = vs_cols;
++      *start = (char *)0;
++      while (size && nr) {
++              unsigned char c = (p->fb[_offset] & 0xff);
++
++              temp += sprintf(temp, "%c", (c < 0x20 ? '?' : c));
++              --size;
++              --nr;
++              ++*start;
++              ++_offset;
++      }
++      if (! nr) {
++              if (size) {
++                      temp += sprintf(temp, "\n");
++                      --size;
++              } else
++                      need_wrap = 1;
++      }
++      up(&p->lcd_sem);
++
++      return (temp-buffer);
++}
++
++static int proc_display_read(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
++{
++      char *temp = buffer;
++      struct lcd_struct *p = (struct lcd_struct *)data;
++      unsigned int i, frame_cols;
++      int frame_pos;
++
++      down(&p->lcd_sem);
++      frame_cols = p->par->cntr_cols;
++      frame_pos = vs_to_frame_(p, (p->row*p->par->vs_cols)+p->col);
++      temp += sprintf(temp, "    ");
++      for (i = 2; i <= frame_cols; i += 2)
++              temp += sprintf(temp, " %d", i%10);
++      temp += sprintf(temp, "\n");
++
++      temp += sprintf(temp, "   +");
++      for (i = 0; i < frame_cols; ++i)
++              temp += sprintf(temp, "-");
++      temp += sprintf(temp, "+\n");
++
++      for (i = 0; i < p->frame_size; ++i) {
++              unsigned char c = (p->display[i] & 0xff);
++
++              if (! (i%frame_cols))
++                      temp += sprintf(temp, "%2d |", 1+i/frame_cols);
++              if (frame_pos--)
++                      temp += sprintf(temp, "%c", (c < 0x20 ? '?' : c));
++              else
++                      temp += sprintf(temp, "_");
++              if (! ((i+1)%frame_cols))
++                      temp += sprintf(temp, "|\n");
++      }
++
++      temp += sprintf(temp, "   +");
++      for (i = 0; i < frame_cols; ++i)
++              temp += sprintf(temp, "-");
++      temp += sprintf(temp, "+\n");
++      up(&p->lcd_sem);
++
++      return (temp-buffer);
++}
++
++static int proc_charmap_read(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
++{
++      char *temp = buffer;
++      struct lcd_struct *p = (struct lcd_struct *)data;
++      unsigned char *charmap;
++      unsigned int i;
++
++      down(&p->lcd_sem);
++      charmap = p->driver->charmap;
++      temp += sprintf(temp,   "static unsigned char charmap[] = {");
++      for (i = 0; i < 255; ++i) {
++              if (! (i & 7)) {
++                      temp += sprintf(temp, "\n");
++                      if (! (i & 31))
++                              temp += sprintf(temp, "\n/* %d - %d */\n", i, i+31);
++              }
++              temp += sprintf(temp, "0x%.2x, ", *charmap++);
++      }
++      temp += sprintf(temp, "0x%.2x\n\n};\n", *charmap);
++      up(&p->lcd_sem);
++
++      return (temp-buffer);
++}
++
++static int proc_registered_drivers(char *buffer, char **start, off_t offset, int size, int *eof, void *data)
++{
++      char *temp = buffer;
++      struct list_head *entry;
++
++      down(&drivers_sem);
++      temp += sprintf(temp, "Registered drivers:\n");
++      list_for_each(entry, &lcd_drivers) {
++              struct lcd_struct *p = list_entry(entry, struct lcd_struct, lcd_list);
++
++              down(&p->lcd_sem);
++              temp += sprintf(temp, "%3d %s\n", p->par->minor, p->par->name);
++              up(&p->lcd_sem);
++      }
++      up(&drivers_sem);
++
++      return (temp-buffer);
++}
++
++static void create_driver_proc_entries(struct lcd_struct *p)
++{
++      struct proc_dir_entry *driver_proc_root = p->driver->driver_proc_root;
++
++      SET_PROC_LEVEL(p, 0);
++      if (create_proc_read_entry("framebuffer", 0, driver_proc_root, proc_fb_read, p) == NULL) {
++              printk(KERN_ERR "LCD: cannot create /proc/lcd/%s/framebuffer\n", p->par->name);
++              return;
++      }
++      SET_PROC_LEVEL(p, 1);
++      if (create_proc_read_entry("display", 0, driver_proc_root, proc_display_read, p) == NULL) {
++              printk(KERN_ERR "LCD: cannot create /proc/lcd/%s/display\n", p->par->name);
++              return;
++      }
++      SET_PROC_LEVEL(p, 2);
++      if (create_proc_read_entry("charmap.h", 0, driver_proc_root, proc_charmap_read, p) == NULL) {
++              printk(KERN_ERR "LCD: cannot create /proc/lcd/%s/charmap.h\n", p->par->name);
++              return;
++      }
++      SET_PROC_LEVEL(p, 3);
++}
++
++static void remove_driver_proc_entries(struct lcd_struct *p)
++{
++      struct proc_dir_entry *driver_proc_root = p->driver->driver_proc_root;
++
++      switch (PROC_LEVEL(p)) {
++      case 3:
++              remove_proc_entry("charmap.h", driver_proc_root);
++      case 2:
++              remove_proc_entry("display", driver_proc_root);
++      case 1:
++              remove_proc_entry("framebuffer", driver_proc_root);
++      }
++      SET_PROC_LEVEL(p, 0);
++}
++#endif
++
++
++
++
++
++/*****************************
++ * Low level file operations *
++ *****************************/
++static ssize_t do_lcd_read(struct lcd_struct *p, void *buffer, size_t length)
++{
++      unsigned int i;
++      unsigned short tmp;
++
++      if (! p->refcount)
++              return (-ENXIO);
++
++      if (test_bit(WITH_ATTR, &p->struct_flags))
++              for (i = 0; i < length; ++i) {
++                      read_data(p, &tmp);
++                      ((unsigned short *)buffer)[i] = tmp;
++              }
++      else
++              for (i = 0; i < length; ++i) {
++                      read_data(p, &tmp);
++                      ((unsigned char *)buffer)[i] = tmp & 0xff;
++              }
++
++      return (length);
++}
++
++static ssize_t do_lcd_write(struct lcd_struct *p, const void *buffer, size_t length)
++{
++      unsigned int i;
++
++      if (! p->refcount)
++              return (-ENXIO);
++
++      if (test_bit(WITH_ATTR, &p->struct_flags))
++              for (i = 0; i < length; ++i)
++                      handle_input(p, ((const unsigned short *)buffer)[i]);
++      else
++              for (i = 0; i < length; ++i)
++                      handle_input(p, (p->attr << 8) | ((const unsigned char *)buffer)[i]);
++
++      return (length);
++}
++
++static int do_lcd_open(struct lcd_struct *p)
++{
++      if (! p->refcount) {
++              if (p->driver->driver_module) {
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
++                      if (! try_module_get(p->driver->driver_module))
++                              return (-EBUSY);
++#else
++                      if (__MOD_IN_USE(p->driver->driver_module))
++                              return (-EBUSY);
++
++                      __MOD_INC_USE_COUNT(p->driver->driver_module);
++#endif
++              }
++      }
++
++      ++p->refcount;
++
++      return (0);
++}
++
++static int do_lcd_release(struct lcd_struct *p)
++{
++      if (! p->refcount)
++              return (0);
++
++      if (p->refcount == 1) {
++              if (p->driver->driver_module)
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
++                      module_put(p->driver->driver_module);
++#else
++                      __MOD_DEC_USE_COUNT(p->driver->driver_module);
++#endif
++      }
++
++      --p->refcount;
++
++      return (0);
++}
++
++static int cgram_ioctl(struct lcd_struct *p, unsigned int cmd, unsigned char *argp)
++{
++      struct lcd_parameters *par = p->par;
++      unsigned int length = par->cgram_bytes;
++      unsigned char index = argp[0];
++      unsigned char *buffer = argp+1;
++      unsigned char *cgbuf = p->cgram_buffer-length;
++
++      if (index < par->cgram_char0 || index >= par->cgram_char0+par->cgram_chars)
++              return (-EINVAL);
++
++      if (! p->driver->write_cgram_char) {
++              printk(KERN_ERR "LCD: %s: missing function to write to CGRAM\n", p->par->name);
++              return (-ENOSYS);
++      }
++
++      if (cmd == LCDL_SET_CGRAM_CHAR) {
++              if (test_bit(USER_SPACE, &p->struct_flags)) {
++                      if (copy_from_user(cgbuf, buffer, length))
++                              return (-EFAULT);
++              } else
++                      memcpy(cgbuf, buffer, length);
++              write_cgram(p, index, cgbuf);
++      } else {
++              read_cgram(p, index, cgbuf);
++              if (test_bit(USER_SPACE, &p->struct_flags)) {
++                      if (copy_to_user(buffer, cgbuf, length))
++                              return (-EFAULT);
++              } else
++                      memcpy(buffer, cgbuf, length);
++      }
++
++      return (0);
++}
++
++static int do_lcd_ioctl(struct lcd_struct *p, unsigned int cmd, unsigned long arg)
++{
++      int i;
++      struct lcd_driver *driver = p->driver;
++      struct lcd_parameters *par = p->par;
++      unsigned char *argp = (unsigned char *)arg;
++
++      if (! p->refcount)
++              return (-ENXIO);
++
++      switch (cmd) {
++      case LCDL_SET_PARAM:
++              if (argp == NULL)
++                      return (-EFAULT);
++              if ((i = cleanup_driver(p)))
++                      return (i);
++              i = par->minor;
++              if (test_bit(USER_SPACE, &p->struct_flags)) {
++                      if (copy_from_user(par, argp, sizeof(struct lcd_parameters)))
++                              return (-EFAULT);
++              } else
++                      memcpy(par, argp, sizeof(struct lcd_parameters));
++              par->minor = i;
++              return (init_driver(p));
++
++      case LCDL_GET_PARAM:
++              if (argp == NULL)
++                      return (-EFAULT);
++              if (test_bit(USER_SPACE, &p->struct_flags)) {
++                      if (copy_to_user(argp, par, sizeof(struct lcd_parameters)))
++                              return (-EFAULT);
++              } else
++                      memcpy(argp, par, sizeof(struct lcd_parameters));
++              return (0);
++
++      case LCDL_RESET_CHARMAP:
++              for (i = 0; i < 256; ++i)
++                      driver->charmap[i] = i;
++              return (0);
++
++      case LCDL_CHARSUBST:
++              if (argp == NULL)
++                      return (-EFAULT);
++              if (test_bit(USER_SPACE, &p->struct_flags)) {
++                      get_user(i, argp);
++                      get_user(driver->charmap[i], argp+1);
++              } else {
++                      i = argp[0];
++                      driver->charmap[i] = argp[1];
++              }
++              return (0);
++
++      case LCDL_SAVE_CHARMAP:
++              memcpy(p->s_charmap, driver->charmap, 256);
++              return (0);
++
++      case LCDL_RESTORE_CHARMAP:
++              memcpy(driver->charmap, p->s_charmap, 256);
++              return (0);
++
++      case LCDL_SWAP_CHARMAP:
++              {
++                      unsigned char *tmp;
++
++                      tmp = driver->charmap;
++                      driver->charmap = p->s_charmap;
++                      p->s_charmap = tmp;
++              }
++              return (0);
++
++      case LCDL_RAW_MODE:
++              if (arg) {
++                      clear_bit(NEED_WRAP, &p->struct_flags);
++                      clear_bit(DECIM, &p->struct_flags);
++                      clear_bit(DECAWM, &p->struct_flags);
++                      SET_INPUT_STATE(p, RAW);
++              } else {
++                      set_bit(DECAWM, &p->struct_flags);
++                      SET_INPUT_STATE(p, NORMAL);
++              }
++              return (0);
++
++      case LCDL_IOATTR:
++              if (arg)
++                      set_bit(WITH_ATTR, &p->struct_flags);
++              else
++                      clear_bit(WITH_ATTR, &p->struct_flags);
++              return (0);
++
++      case LCDL_CLEAR_DISP:
++              ff(p);
++              return (0);
++
++      case LCDL_SET_CGRAM_CHAR:
++      case LCDL_GET_CGRAM_CHAR:
++              if (argp == NULL)
++                      return (-EFAULT);
++              if (p->cgram_buffer)
++                      return (cgram_ioctl(p, cmd, argp));
++              else
++                      printk(KERN_NOTICE "LCD: driver %s does not support CGRAM chars\n", par->name);
++              return (0);
++
++      case LCDL_SET_CHARMAP:
++              if (argp == NULL)
++                      return (-EFAULT);
++              if (test_bit(USER_SPACE, &p->struct_flags)) {
++                      if (copy_from_user(driver->charmap, argp, 256))
++                              return (-EFAULT);
++              } else
++                      memcpy(driver->charmap, argp, 256);
++              return (0);
++
++      case LCDL_GET_CHARMAP:
++              if (argp == NULL)
++                      return (-EFAULT);
++              if (test_bit(USER_SPACE, &p->struct_flags)) {
++                      if (copy_to_user(argp, driver->charmap, 256))
++                              return (-EFAULT);
++              } else
++                      memcpy(argp, driver->charmap, 256);
++              return (0);
++
++      case LCDL_MEMSET:
++      case LCDL_MEMMOVE:
++      {
++              int buf[3];
++
++              if (argp == NULL)
++                      return (-EFAULT);
++              if (test_bit(USER_SPACE, &p->struct_flags)) {
++                      if (copy_from_user(buf, argp, sizeof(buf)))
++                              return (-EFAULT);
++              } else
++                      memcpy(buf, argp, sizeof(buf));
++
++              if (cmd == LCDL_MEMSET)
++                      lcd_memset(p, buf[0], buf[1], buf[2]);
++              else
++                      lcd_memmove(p, buf[0], buf[1], buf[2]);
++
++              return (0);
++      }
++
++      default:
++              if (driver->handle_custom_ioctl)
++                      return (driver->handle_custom_ioctl(cmd, arg, test_bit(USER_SPACE, &p->struct_flags)));
++      }
++
++      return (-ENOIOCTLCMD);
++}
++
++
++
++
++
++/**************************************************
++ * Kernel register/unregister lcd driver routines *
++ **************************************************/
++/*
++ * Find a driver in lcd_drivers linked list
++ */
++static struct lcd_struct *find_lcd_struct(unsigned short minor)
++{
++      struct list_head *entry;
++
++      list_for_each(entry, &lcd_drivers) {
++              struct lcd_struct *p = list_entry(entry, struct lcd_struct, lcd_list);
++
++              if (p->par->minor == minor)
++                      return (p);
++      }
++
++      return (NULL);
++}
++
++static void list_add_sorted(struct list_head *new)
++{
++      struct list_head *entry;
++      unsigned short new_minor = (list_entry(new, struct lcd_struct, lcd_list))->par->minor;
++
++      list_for_each(entry, &lcd_drivers) {
++              struct lcd_struct *p = list_entry(entry, struct lcd_struct, lcd_list);
++
++              if (p->par->minor > new_minor)
++                      break;
++      }
++      list_add_tail(new, entry);
++}
++
++/* Exported function */
++int lcd_register_driver(struct lcd_driver *driver, struct lcd_parameters *par)
++{
++      int ret;
++      struct lcd_struct *p;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
++      struct device *lcd_device;
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
++      struct class_device *lcd_device;
++#endif
++
++      if (! driver || ! par || par->minor >= minors)
++              return (-EINVAL);
++      if (! driver->write_char || ! driver->init_port || ! driver->cleanup_port) {
++              printk(KERN_ERR "LCD: missing functions\n");
++              return (-EINVAL);
++      }
++
++      down(&drivers_sem);
++
++      if (find_lcd_struct(par->minor)) {
++              up(&drivers_sem);
++              return (-EBUSY);
++      }
++
++      if ((p = (struct lcd_struct *)kmalloc(sizeof(struct lcd_struct), GFP_KERNEL)) == NULL) {
++              printk(KERN_ERR "LCD: memory allocation failed (kmalloc)\n");
++              up(&drivers_sem);
++              return (-ENOMEM);
++      }
++      memset(p, 0, sizeof(struct lcd_struct));
++
++      p->driver = driver;
++      p->par = par;
++      p->refcount = 0;
++      SET_INIT_LEVEL(p, 0);
++      SET_INPUT_STATE(p, NORMAL);
++      set_bit(DECAWM, &p->struct_flags);
++      set_bit(INC_CURS_POS, &p->struct_flags);
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)
++      lcd_device = device_create(lcd_linux_class, NULL, MKDEV(major, par->minor), NULL, "%s", par->name);
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
++      lcd_device = device_create(lcd_linux_class, NULL, MKDEV(major, par->minor), "%s", par->name);
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 15)
++      lcd_device = class_device_create(lcd_linux_class, NULL, MKDEV(major, par->minor), NULL, "%s", par->name);
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
++      lcd_device = class_device_create(lcd_linux_class, MKDEV(major, par->minor), NULL, "%s", par->name);
++#endif
++      if (IS_ERR(lcd_device)) {
++              kfree(p);
++              up(&drivers_sem);
++              return (PTR_ERR(lcd_device));
++      }
++#endif
++
++#ifdef USE_PROC
++      if (lcd_proc_root && (driver->driver_proc_root = proc_mkdir(par->name, lcd_proc_root)) == NULL)
++              printk(KERN_ERR "LCD: cannot create /proc/lcd/%s/\n", par->name);
++#endif
++
++      if ((ret = init_driver(p))) {
++#ifdef USE_PROC
++              if (driver->driver_proc_root)
++                      remove_proc_entry(p->par->name, lcd_proc_root);
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
++              device_destroy(lcd_linux_class, MKDEV(major, par->minor));
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
++              class_device_destroy(lcd_linux_class, MKDEV(major, par->minor));
++#endif
++
++              kfree(p);
++              up(&drivers_sem);
++              return (ret);
++      }
++
++      init_MUTEX(&p->lcd_sem);
++
++      list_add_sorted(&p->lcd_list);
++
++      up(&drivers_sem);
++
++#ifdef MODULE
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
++      try_module_get(THIS_MODULE);
++#else
++      MOD_INC_USE_COUNT;
++#endif
++#endif
++
++      return (0);
++}
++EXPORT_SYMBOL(lcd_register_driver);
++
++/* Exported function */
++int lcd_unregister_driver(struct lcd_driver *driver, struct lcd_parameters *par)
++{
++      int ret;
++      struct lcd_struct *p;
++
++      if (! driver || ! par || par->minor >= minors)
++              return (-EINVAL);
++
++      down(&drivers_sem);
++
++      if ((p = find_lcd_struct(par->minor)) == NULL || p->driver != driver) {
++              printk(KERN_ERR "LCD: driver not found; lcd_unregister_driver failed\n");
++              up(&drivers_sem);
++              return (-ENODEV);
++      }
++
++      down(&p->lcd_sem);
++
++      if (p->refcount) {
++              printk(KERN_ERR "LCD: driver busy; lcd_unregister_driver failed\n");
++              up(&p->lcd_sem);
++              up(&drivers_sem);
++              return (-EBUSY);
++      }
++
++      if ((ret = cleanup_driver(p))) {
++              up(&p->lcd_sem);
++              up(&drivers_sem);
++              return (ret);
++      }
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
++      device_destroy(lcd_linux_class, MKDEV(major, par->minor));
++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
++      class_device_destroy(lcd_linux_class, MKDEV(major, par->minor));
++#endif
++
++#ifdef USE_PROC
++      if (p->driver->driver_proc_root)
++              remove_proc_entry(p->par->name, lcd_proc_root);
++#endif
++
++      list_del(&p->lcd_list);
++      kfree(p);
++
++      up(&drivers_sem);
++
++#ifdef MODULE
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
++      module_put(THIS_MODULE);
++#else
++      MOD_DEC_USE_COUNT;
++#endif
++#endif
++
++      return (0);
++}
++EXPORT_SYMBOL(lcd_unregister_driver);
++
++
++
++
++
++/************************
++ * Kernel I/O interface *
++ ************************/
++/* Exported function */
++int lcd_open(unsigned short minor, struct lcd_struct **pp)
++{
++      int ret;
++      struct lcd_struct *p;
++
++      down(&drivers_sem);
++
++      if (minor >= minors || (*pp = p = find_lcd_struct(minor)) == NULL) {
++              printk(KERN_ERR "LCD: lcd_open failed. Device not found.\n");
++              up(&drivers_sem);
++              return (-ENODEV);
++      }
++
++      down(&p->lcd_sem);
++      up(&drivers_sem);
++
++      ret = do_lcd_open(p);
++
++      up(&p->lcd_sem);
++
++      return (ret);
++}
++EXPORT_SYMBOL(lcd_open);
++
++/* Exported function */
++int lcd_close(struct lcd_struct **pp)
++{
++      int ret;
++      struct lcd_struct *p;
++
++      if (! pp || ! (p = *pp)) {
++              printk(KERN_ERR "LCD: NULL pointer in lcd_close\n");
++              return (-ENODEV);
++      }
++
++      down(&p->lcd_sem);
++
++      if (! (ret = do_lcd_release(p)))
++              *pp = NULL;
++
++      up(&p->lcd_sem);
++
++      return (ret);
++}
++EXPORT_SYMBOL(lcd_close);
++
++static inline loff_t offset_to_row_col(struct lcd_struct *p, loff_t offset)
++{
++      unsigned long _offset = offset;
++      unsigned int vs_cols = p->par->vs_cols;
++
++      gotoxy(p, _offset%vs_cols, _offset/vs_cols);
++
++      return ((p->row*vs_cols)+p->col);
++}
++
++/* Exported function */
++ssize_t lcd_read(struct lcd_struct *p, void *bufp, size_t length, loff_t offset, unsigned int with_attr)
++{
++      ssize_t ret = 0;
++
++      if (! p) {
++              printk(KERN_ERR "LCD: NULL pointer in lcd_read\n");
++              return (-ENODEV);
++      }
++      if (! bufp)
++              return (-EFAULT);
++      if (offset < 0 || offset >= p->fb_size)
++              return (-EINVAL);
++
++      if (length+offset > p->fb_size)
++              length = p->fb_size-offset;
++
++      if (with_attr)
++              set_bit(WITH_ATTR, &p->struct_flags);
++
++      offset_to_row_col(p, offset);
++      ret = do_lcd_read(p, bufp, length);
++
++      if (with_attr)
++              clear_bit(WITH_ATTR, &p->struct_flags);
++
++      return (ret);
++}
++EXPORT_SYMBOL(lcd_read);
++
++/* Exported function */
++ssize_t lcd_write(struct lcd_struct *p, const void *bufp, size_t length, loff_t offset, unsigned int with_attr)
++{
++      ssize_t ret;
++
++      if (! p) {
++              printk(KERN_ERR "LCD: NULL pointer in lcd_write\n");
++              return (-ENODEV);
++      }
++      if (! bufp)
++              return (-EFAULT);
++      if (offset < 0 || offset >= p->fb_size)
++              return (-EINVAL);
++
++      if (with_attr)
++              set_bit(WITH_ATTR, &p->struct_flags);
++
++      offset_to_row_col(p, offset);
++      ret = do_lcd_write(p, bufp, length);
++
++      if (with_attr)
++              clear_bit(WITH_ATTR, &p->struct_flags);
++
++      return (ret);
++}
++EXPORT_SYMBOL(lcd_write);
++
++/* Exported function */
++int lcd_ioctl(struct lcd_struct *p, unsigned int cmd, ...)
++{
++      int ret;
++      unsigned long arg;
++      va_list ap;
++
++      if (! p) {
++              printk(KERN_ERR "LCD: NULL pointer in lcd_ioctl\n");
++              return (-ENODEV);
++      }
++
++      down(&p->lcd_sem);
++      va_start(ap, cmd);
++      arg = va_arg(ap, unsigned long);
++      ret = do_lcd_ioctl(p, cmd, arg);
++      va_end(ap);
++      up(&p->lcd_sem);
++
++      return (ret);
++}
++EXPORT_SYMBOL(lcd_ioctl);
++
++
++
++
++
++/*******************
++ * File operations *
++ *******************/
++static loff_t lcd_fops_llseek(struct file *filp, loff_t offset, int orig)
++{
++      struct lcd_struct *p;
++
++      if (! (p = filp->private_data))
++              return (-ENODEV);
++
++      down(&p->lcd_sem);
++
++      switch (orig) {
++      case 0:
++              break;
++
++      case 1:
++              offset += filp->f_pos;
++              break;
++
++      default:
++              up(&p->lcd_sem);
++              return (-EINVAL);     /* SEEK_END not supported */
++      }
++
++      if (offset >= 0 && offset < p->fb_size)
++              filp->f_pos = offset_to_row_col(p, offset);
++      else
++              offset = -EINVAL;
++
++      up(&p->lcd_sem);
++
++      return (offset);
++}
++
++static ssize_t lcd_fops_read(struct file *filp, char *buffer, size_t length, loff_t *offp)
++{
++      ssize_t ret = 0;
++      char *bufp = buffer;
++      struct lcd_struct *p;
++
++      if (! bufp)
++              return (-EFAULT);
++      if (! (p = filp->private_data))
++              return (-ENODEV);
++
++      down(&p->lcd_sem);
++
++      if (*offp < 0 || *offp >= p->fb_size) {
++              up(&p->lcd_sem);
++              return (-EINVAL);
++      }
++
++      if (test_bit(WITH_ATTR, &p->struct_flags) && (length & 0x01))
++              length &= ~0x01;
++
++      if (length+(*offp) > p->fb_size)
++              length = p->fb_size-(*offp);
++
++      while (length) {
++              ret = (length > FLIP_BUF_SIZE ? FLIP_BUF_SIZE : length);
++              if (test_bit(WITH_ATTR, &p->struct_flags))
++                      ret /= sizeof(unsigned short);
++              if ((ret = do_lcd_read(p, p->flip_buf, ret)) < 0)
++                      break;
++              if (test_bit(WITH_ATTR, &p->struct_flags))
++                      ret *= sizeof(unsigned short);
++              *offp = (p->row*p->par->vs_cols)+p->col;
++              if (copy_to_user(bufp, p->flip_buf, ret)) {
++                      ret = -EFAULT;
++                      break;
++              }
++              length -= ret;
++              bufp += ret;
++              ret = bufp-buffer;
++              if (length)
++                      schedule();
++      }
++
++      up(&p->lcd_sem);
++
++      return (ret);
++}
++
++static ssize_t lcd_fops_write(struct file *filp, const char *buffer, size_t length, loff_t *offp)
++{
++      ssize_t ret = 0;
++      const char *bufp = buffer;
++      struct lcd_struct *p;
++
++      if (! bufp)
++              return (-EFAULT);
++      if (! (p = filp->private_data))
++              return (-ENODEV);
++
++      down(&p->lcd_sem);
++
++      if (*offp < 0 || *offp >= p->fb_size) {
++              up(&p->lcd_sem);
++              return (-EINVAL);
++      }
++
++      if (test_bit(WITH_ATTR, &p->struct_flags) && (length & 0x01))
++              length &= ~0x01;
++
++      while (length) {
++              ret = (length > FLIP_BUF_SIZE ? FLIP_BUF_SIZE : length);
++              if (copy_from_user(p->flip_buf, bufp, ret)) {
++                      ret = -EFAULT;
++                      break;
++              }
++              if (test_bit(WITH_ATTR, &p->struct_flags))
++                      ret /= sizeof(unsigned short);
++              if ((ret = do_lcd_write(p, p->flip_buf, ret)) < 0)
++                      break;
++              if (test_bit(WITH_ATTR, &p->struct_flags))
++                      ret *= sizeof(unsigned short);
++              *offp = (p->row*p->par->vs_cols)+p->col;
++              length -= ret;
++              bufp += ret;
++              ret = bufp-buffer;
++              if (length)
++                      schedule();
++      }
++
++      up(&p->lcd_sem);
++
++      return (ret);
++}
++
++static int lcd_fops_open(struct inode *inop, struct file *filp)
++{
++      unsigned short minor;
++      int ret;
++      struct lcd_struct *p;
++
++      down(&drivers_sem);
++
++      if ((minor = MINOR(inop->i_rdev)) >= minors || (filp->private_data = p = find_lcd_struct(minor)) == NULL) {
++              up(&drivers_sem);
++              return (-ENODEV);
++      }
++
++      down(&p->lcd_sem);
++      up(&drivers_sem);
++
++      ret = do_lcd_open(p);
++
++      up(&p->lcd_sem);
++
++      return (ret);
++}
++
++static int lcd_fops_release(struct inode *inop, struct file *filp)
++{
++      struct lcd_struct *p;
++      int ret;
++
++      if (! (p = filp->private_data))
++              return (-ENODEV);
++
++      down(&p->lcd_sem);
++
++      if (! (ret = do_lcd_release(p)))
++              filp->private_data = NULL;
++
++      up(&p->lcd_sem);
++
++      return (ret);
++}
++
++static int lcd_fops_ioctl(struct inode *inop, struct file *filp, unsigned int cmd, unsigned long arg)
++{
++      struct lcd_struct *p;
++      int ret;
++
++      if (! (p = filp->private_data))
++              return (-ENODEV);
++
++      down(&p->lcd_sem);
++
++      set_bit(USER_SPACE, &p->struct_flags);
++      ret = do_lcd_ioctl(p, cmd, arg);
++      clear_bit(USER_SPACE, &p->struct_flags);
++
++      up(&p->lcd_sem);
++
++      return (ret);
++}
++
++static struct file_operations lcd_linux_fops = {
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
++      .owner          = THIS_MODULE,
++#endif
++      .llseek         = lcd_fops_llseek,
++      .read           = lcd_fops_read,
++      .write          = lcd_fops_write,
++      .open           = lcd_fops_open,
++      .release        = lcd_fops_release,
++      .ioctl          = lcd_fops_ioctl,
++};
++
++
++
++
++
++/********************************
++ * Init/Cleanup driver routines *
++ ********************************/
++static int do_init_driver(struct lcd_struct *p)
++{
++      int ret;
++      struct lcd_driver *driver = p->driver;
++      struct lcd_parameters *par = p->par;
++      unsigned int frame_rows = par->cntr_rows*par->num_cntr;
++      unsigned int frame_cols = par->cntr_cols;
++
++      switch (INIT_LEVEL(p)) {
++      case 0:
++              if (frame_rows == 0 || frame_cols == 0 || ! par->name) {
++                      printk(KERN_ERR "LCD: wrong lcd parameters\n");
++                      return (-EINVAL);
++              }
++              if (driver->validate_driver) {
++                      if ((ret = driver->validate_driver()) < 0) {
++                              printk(KERN_ERR "LCD: validate_driver failed\n");
++                              return (-EINVAL);
++                      } else if (ret > 0) {
++                              set_bit(CAN_DO_COLOR, &p->struct_flags);
++                              p->defcolor = 0x07;
++                              p->ulcolor = 0x0f;
++                              p->halfcolor = 0x08;
++                      }
++              }
++              default_attr(p);
++              update_attr(p);
++              p->frame_size = frame_rows*frame_cols;
++              if (par->vs_rows < frame_rows)
++                      par->vs_rows = frame_rows;
++              if (par->vs_cols < frame_cols)
++                      par->vs_cols = frame_cols;
++              p->fb_size = par->vs_rows*par->vs_cols;
++
++              ret = sizeof(short)*p->fb_size;
++              ret += sizeof(short)*p->frame_size;
++              ret += FLIP_BUF_SIZE;
++              ret += (p->driver->charmap ? 256 : 512);
++              if (par->cgram_chars*par->cgram_bytes)
++                      ret += (1+par->cgram_chars)*par->cgram_bytes;
++              if ((p->fb = (unsigned short *)vmalloc(ret)) == NULL) {
++                      printk(KERN_ERR "LCD: memory allocation failed (vmalloc)\n");
++                      return (-ENOMEM);
++              }
++              __memset_short(p->fb, p->erase_char, p->fb_size+p->frame_size);
++
++              p->display = p->fb+p->fb_size;
++              p->flip_buf = (unsigned char *)(p->display+p->frame_size);
++
++              if (! p->driver->charmap) {
++                      set_bit(NULL_CHARMAP, &p->struct_flags);
++                      p->driver->charmap = p->flip_buf+FLIP_BUF_SIZE;
++                      for (ret = 0; ret < 256; ++ret)
++                              p->driver->charmap[ret] = ret;
++                      p->s_charmap = p->driver->charmap+256;
++              } else
++                      p->s_charmap = p->flip_buf+FLIP_BUF_SIZE;
++              memset(p->s_charmap, 0, 256);
++
++              if (par->cgram_chars*par->cgram_bytes) {
++                      p->cgram_buffer = p->s_charmap+256+par->cgram_bytes;
++                      memset(p->cgram_buffer, 0xff, par->cgram_chars*par->cgram_bytes);
++              } else
++                      p->cgram_buffer = NULL;
++              p->driver->cgram_buffer = p->cgram_buffer;
++
++              p->frame_base = 0;
++              p->row = p->col = 0;
++              p->top = 0;
++              p->bot = par->vs_rows;
++              SET_INIT_LEVEL(p, 1);
++
++      case 1:
++              /* Initialize the communication port */
++              if ((ret = driver->init_port())) {
++                      printk(KERN_ERR "LCD: failure while initializing the communication port\n");
++                      return (ret);
++              }
++              SET_INIT_LEVEL(p, 2);
++
++      case 2:
++              /* Initialize LCD display */
++              if (driver->init_display && (ret = driver->init_display())) {
++                      printk(KERN_ERR "LCD: failure while initializing the display\n");
++                      return (ret);
++              }
++
++#ifdef USE_PROC
++              /* Create entries in /proc/lcd/"driver" */
++              if (driver->driver_proc_root)
++                      create_driver_proc_entries(p);
++#endif
++              SET_INIT_LEVEL(p, 3);
++      }
++
++      return (0);
++}
++
++static int do_cleanup_driver(struct lcd_struct *p)
++{
++      int ret;
++      struct lcd_driver *driver = p->driver;
++
++      switch (INIT_LEVEL(p)) {
++      case 3:
++#ifdef USE_PROC
++              if (driver->driver_proc_root)
++                      remove_driver_proc_entries(p);
++#endif
++              if (driver->cleanup_display && (ret = driver->cleanup_display())) {
++                      printk(KERN_ERR "LCD: failure while cleaning the display\n");
++                      return (ret);
++              }
++              SET_INIT_LEVEL(p, 2);
++
++      case 2:
++              if ((ret = driver->cleanup_port())) {
++                      printk(KERN_ERR "LCD: failure while cleaning the communication port\n");
++                      return (ret);
++              }
++              SET_INIT_LEVEL(p, 1);
++
++      case 1:
++              if (test_bit(NULL_CHARMAP, &p->struct_flags)) {
++                      p->driver->charmap = NULL;
++                      clear_bit(NULL_CHARMAP, &p->struct_flags);
++              }
++              vfree(p->fb);
++              p->fb = NULL;
++              SET_INIT_LEVEL(p, 0);
++      }
++
++      return (0);
++}
++
++static int init_driver(struct lcd_struct *p)
++{
++      int ret;
++
++      if ((ret = do_init_driver(p))) {
++              do_cleanup_driver(p);
++              printk(KERN_ERR "LCD: init_driver failed\n");
++      }
++
++      return (ret);
++}
++
++static int cleanup_driver(struct lcd_struct *p)
++{
++      int ret;
++
++      if ((ret = do_cleanup_driver(p))) {
++              do_init_driver(p);
++              printk(KERN_ERR "LCD: cleanup_driver failed\n");
++      }
++
++      return (ret);
++}
++
++
++
++
++
++/********************************
++ * Init/Cleanup module routines *
++ ********************************/
++static int __init lcd_linux_init_module(void)
++{
++      int ret;
++
++      if (! minors || minors > 256)
++              minors = LCD_MINORS;
++
++      init_MUTEX(&drivers_sem);
++
++      if ((ret = register_chrdev(major, LCD_LINUX_STRING, &lcd_linux_fops)) < 0) {
++              printk(KERN_ERR "LCD: register_chrdev failed\n");
++              return (ret);
++      }
++      if (major == 0)
++              major = ret;
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
++      if (IS_ERR((lcd_linux_class = class_create(THIS_MODULE, "lcd")))) {
++              ret = PTR_ERR(lcd_linux_class);
++              unregister_chrdev(major, LCD_LINUX_STRING);
++              return (ret);
++      }
++#endif
++
++#ifdef USE_PROC
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
++      if ((lcd_proc_root = proc_mkdir("lcd", NULL)) == NULL)
++#else
++      if ((lcd_proc_root = proc_mkdir("lcd", &proc_root)) == NULL)
++#endif
++              printk(KERN_ERR "LCD: cannot create /proc/lcd/\n");
++      else if (create_proc_read_entry("drivers", 0, lcd_proc_root, proc_registered_drivers, NULL) == NULL)
++              printk(KERN_ERR "LCD: cannot create /proc/lcd/drivers\n");
++#endif
++
++      printk(KERN_INFO "LCD: --> LCD-Linux " LCD_LINUX_VERSION " <--\n");
++      printk(KERN_INFO "LCD: --> Mattia Jona-Lasinio <mjona@users.sourceforge.net> <--\n" );
++
++
++      return (0);
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0)
++static void __exit lcd_linux_cleanup_module(void)
++#else
++/* __exit is not defined in 2.2.x kernels */
++static void lcd_linux_cleanup_module(void)
++#endif
++{
++#ifdef USE_PROC
++      if (lcd_proc_root) {
++              remove_proc_entry("drivers", lcd_proc_root);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
++              remove_proc_entry("lcd", NULL);
++#else
++              remove_proc_entry("lcd", &proc_root);
++#endif
++      }
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13)
++      class_destroy(lcd_linux_class);
++#endif
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
++      unregister_chrdev(major, LCD_LINUX_STRING);
++#else
++      if (unregister_chrdev(major, LCD_LINUX_STRING))
++              printk(KERN_ERR "LCD: unregister_chrdev failed\n");
++#endif
++}
++
++module_init(lcd_linux_init_module)
++module_exit(lcd_linux_cleanup_module)
+diff --git a/include/linux/hd44780.h b/include/linux/hd44780.h
+new file mode 100644
+index 0000000..9033d44
+--- /dev/null
++++ b/include/linux/hd44780.h
+@@ -0,0 +1,47 @@
++/* hd44780.h
++ *
++ * $Id: hd44780.h,v 1.15 2009/03/09 17:59:23 mjona Exp $
++ *
++ * LCD-Linux:
++ * Driver for HD44780 compatible displays connected to the parallel port.
++ *
++ * HD44780 header file.
++ *
++ * Copyright (C) 2004 - 2009  Mattia Jona-Lasinio (mjona@users.sourceforge.net)
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++#ifndef HD44780_H
++#define HD44780_H
++
++#include <linux/lcd-linux.h>
++
++#define HD44780_VERSION               LCD_LINUX_VERSION       /* Version number */
++#define HD44780_STRING                "hd44780"
++
++#define HD44780_MINOR         0       /* Minor number for the hd44780 driver */
++
++
++/* flags */
++#define HD44780_CHECK_BF      0x00000001      /* Do busy flag checking */
++#define HD44780_4BITS_BUS     0x00000002      /* Set the bus length to 4 bits */
++#define HD44780_5X10_FONT     0x00000004      /* Use 5x10 dots fonts */
++
++/* IOCTLs */
++#define HD44780_READ_AC               _IOR(LCD_MAJOR, 0x00, unsigned char *)
++
++#endif /* HD44780 included */
+diff --git a/include/linux/lcd-linux.h b/include/linux/lcd-linux.h
+new file mode 100644
+index 0000000..1756107
+--- /dev/null
++++ b/include/linux/lcd-linux.h
+@@ -0,0 +1,158 @@
++/* lcd-linux.h
++ *
++ * $Id: lcd-linux.h,v 1.68 2010/07/04 16:02:02 mjona Exp $
++ *
++ * Software layer to drive LCD displays under Linux.
++ *
++ * External interface header file.
++ *
++ * Copyright (C) 2005 - 2009  Mattia Jona-Lasinio (mjona@users.sourceforge.net)
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or
++ *  (at your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful,
++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ *  GNU General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License
++ *  along with this program; if not, write to the Free Software
++ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++#ifndef LCD_LINUX_H
++#define LCD_LINUX_H
++
++#ifndef LCD_LINUX_MAIN
++#warning
++#warning LCD-Linux is still in development stage and
++#warning aims at speed and optimization. For these
++#warning reasons there is no guarantee of backward
++#warning compatibility between different LCD-Linux
++#warning versions. Be sure to use the lcd-linux.h
++#warning file of the same version as the module.
++#warning "http://lcd-linux.sourceforge.net/"
++#warning
++#endif
++
++#define LCD_LINUX_VERSION     "0.13.9"        /* Version number */
++#define LCD_LINUX_STRING      "lcd"
++
++#define LCD_MAJOR             120     /* Major number for this device
++                                       * Set this to 0 for dynamic allocation
++                                       */
++#define LCD_MINORS            8       /* Minors allocated for LCD-Linux*/
++
++#include <linux/types.h>
++
++#define       str(s) #s
++#define       string(s) str(s)
++
++struct lcd_parameters {
++      const char      *name;          /* Driver's name */
++      unsigned long   flags;          /* Flags (see documentation) */
++      unsigned short  minor;          /* Minor number of the char device */
++      unsigned short  tabstop;        /* Tab character length */
++      unsigned short  num_cntr;       /* Controllers to drive */
++      unsigned short  cntr_rows;      /* Rows per controller */
++      unsigned short  cntr_cols;      /* Display columns */
++      unsigned short  vs_rows;        /* Virtual screen rows */
++      unsigned short  vs_cols;        /* Virtual screen columns */
++      unsigned short  cgram_chars;    /* Number of user definable characters */
++      unsigned short  cgram_bytes;    /* Number of bytes required to define a
++                                       * user definable character */
++      unsigned char   cgram_char0;    /* Ascii of first user definable character */
++};
++
++/* IOCTLs */
++#include <asm/ioctl.h>
++#define LCDL_SET_PARAM                _IOW(LCD_MAJOR, 0x80, struct lcd_parameters *)
++#define LCDL_GET_PARAM                _IOR(LCD_MAJOR, 0x81, struct lcd_parameters *)
++#define LCDL_CHARSUBST                _IOW(LCD_MAJOR, 0x82, unsigned char *)
++#define LCDL_RAW_MODE         _IOW(LCD_MAJOR, 0x83, unsigned int)
++#define LCDL_RESET_CHARMAP    _IO(LCD_MAJOR, 0x84)
++#define LCDL_SAVE_CHARMAP     _IO(LCD_MAJOR, 0x85)
++#define LCDL_RESTORE_CHARMAP  _IO(LCD_MAJOR, 0x86)
++#define LCDL_SWAP_CHARMAP     _IO(LCD_MAJOR, 0x87)
++#define LCDL_CLEAR_DISP               _IO(LCD_MAJOR, 0x88)
++#define LCDL_SET_CGRAM_CHAR   _IOW(LCD_MAJOR, 0x89, unsigned char *)
++#define LCDL_GET_CGRAM_CHAR   _IOR(LCD_MAJOR, 0x8a, unsigned char *)
++#define LCDL_SET_CHARMAP      _IOW(LCD_MAJOR, 0x8b, unsigned char *)
++#define LCDL_GET_CHARMAP      _IOR(LCD_MAJOR, 0x8c, unsigned char *)
++#define LCDL_MEMSET           _IOW(LCD_MAJOR, 0x8d, unsigned int *)
++#define LCDL_MEMMOVE          _IOW(LCD_MAJOR, 0x8e, unsigned int *)
++#define LCDL_IOATTR           _IOW(LCD_MAJOR, 0x8f, unsigned int)
++
++
++
++#ifdef __KERNEL__ /* The rest is for kernel only */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++
++struct lcd_driver {
++      void    (*read_char)(unsigned int offset, unsigned short *data);
++      void    (*read_cgram_char)(unsigned char index, unsigned char *pixmap);
++      void    (*write_char)(unsigned int offset, unsigned short data);
++      void    (*write_cgram_char)(unsigned char index, unsigned char *pixmap);
++      void    (*clear_display)(void);
++      void    (*address_mode)(int mode);
++      int     (*validate_driver)(void);
++      int     (*init_display)(void);
++      int     (*cleanup_display)(void);
++      int     (*init_port)(void);
++      int     (*cleanup_port)(void);
++      int     (*handle_custom_char)(unsigned int data);
++      int     (*handle_custom_ioctl)(unsigned int cmd, unsigned long arg, unsigned int arg_in_userspace);
++
++      /* The character map to be used */
++      unsigned char *charmap;
++
++      /* Buffer for CGRAM operations.
++       * Will be filled by the lcd-linux layer.
++       */
++      unsigned char *cgram_buffer;
++
++      /* The root where the driver can create its own proc files.
++       * Will be filled by the lcd-linux layer.
++       */
++      struct proc_dir_entry *driver_proc_root;
++
++      /* Set this field to 'driver_module_init' or call lcd_driver_setup
++       * just before registering the driver with lcd_register_driver.
++       */
++      struct module *driver_module;
++};
++
++#ifdef MODULE
++#define driver_module_init    THIS_MODULE
++#else
++#define driver_module_init    NULL
++#endif
++
++/* Always call lcd_driver_setup just before registering the driver
++ * with lcd_register_driver.
++ */
++static inline void lcd_driver_setup(struct lcd_driver *p)
++{
++      p->driver_module = driver_module_init;
++}
++
++/* External interface */
++struct lcd_struct;
++int lcd_register_driver(struct lcd_driver *drv, struct lcd_parameters *par);
++int lcd_unregister_driver(struct lcd_driver *drv, struct lcd_parameters *par);
++int lcd_open(unsigned short minor, struct lcd_struct **lcd);
++int lcd_close(struct lcd_struct **lcd);
++int lcd_ioctl(struct lcd_struct *lcd, unsigned int cmd, ...);
++ssize_t lcd_write(struct lcd_struct *lcd, const void *buffer, size_t length, loff_t offset, unsigned int with_attr);
++ssize_t lcd_read(struct lcd_struct *lcd, void *buffer, size_t length, loff_t offset, unsigned int with_attr);
++
++#endif /* __KERNEL__ */
++
++#endif /* External interface included */
+-- 
+1.7.0.4
+
index aae5496..939cd36 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.34.7
-# Mon Oct 18 19:22:11 2010
+# Sat Nov  6 17:01:20 2010
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -330,7 +330,7 @@ CONFIG_ALIGNMENT_TRAP=y
 #
 CONFIG_ZBOOT_ROM_TEXT=0
 CONFIG_ZBOOT_ROM_BSS=0
-CONFIG_CMDLINE="console=ttyAM0,115200 ubi.mtd=1 root=ubi0:ts72xx-rootfs rootfstype=ubifs"
+CONFIG_CMDLINE=" debug "
 # CONFIG_XIP_KERNEL is not set
 CONFIG_KEXEC=y
 CONFIG_ATAGS_PROC=y
@@ -679,7 +679,6 @@ CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLKDEVS=y
 CONFIG_MTD_BLOCK=y
-# CONFIG_MTD_BLOCK_RO is not set
 # CONFIG_FTL is not set
 # CONFIG_NFTL is not set
 # CONFIG_INFTL is not set
@@ -886,7 +885,7 @@ CONFIG_AX88796_TS_ETH100=m
 # CONFIG_SMC91X is not set
 # CONFIG_DM9000 is not set
 # CONFIG_ENC28J60 is not set
-# CONFIG_ETHOC is not set
+CONFIG_ETHOC=m
 # CONFIG_SMC911X is not set
 # CONFIG_SMSC911X is not set
 # CONFIG_DNET is not set
@@ -1300,6 +1299,7 @@ CONFIG_SSB_SDIOHOST_POSSIBLE=y
 #
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
+# CONFIG_TS72XX_CONSOLE is not set
 # CONFIG_SOUND is not set
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
@@ -1676,6 +1676,12 @@ CONFIG_UIO_PDRV_GENIRQ=m
 #
 # CONFIG_STAGING is not set
 
+#
+# LCD support
+#
+CONFIG_LCD_LINUX=y
+CONFIG_LCD_HD44780=y
+
 #
 # File systems
 #
@@ -1711,6 +1717,7 @@ CONFIG_INOTIFY_USER=y
 CONFIG_AUTOFS4_FS=m
 CONFIG_FUSE_FS=m
 # CONFIG_CUSE is not set
+CONFIG_GENERIC_ACL=y
 
 #
 # Caches
@@ -1746,7 +1753,7 @@ CONFIG_PROC_SYSCTL=y
 CONFIG_PROC_PAGE_MONITOR=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
-# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_TMPFS_POSIX_ACL=y
 # CONFIG_HUGETLB_PAGE is not set
 CONFIG_CONFIGFS_FS=m
 CONFIG_MISC_FILESYSTEMS=y
index 442fb96..6b50590 100644 (file)
@@ -1,6 +1,6 @@
 require linux.inc
 
-PR = "r4"
+PR = "r5"
 
 module_autoload_ohci-hcd_omap5912osk = "ohci-hcd"
 
@@ -45,7 +45,12 @@ SRC_URI_append_ts72xx = " \
            file://0016-ts72xx_nand_flash.patch \
            file://0017-ep93xx_spi.patch \
            file://0018-ts72xx_spi_tmp124.patch \
-           file://0019-watchdog-ts72xx_wdt-disable-watchdog-at-probe.patch \
+           file://0019-ts72xx-use-CPLD-watchdog-for-reset.patch \
+           file://0020-ethoc-ts7300-fixes.patch \
+           file://0021-ts7300-add-ethernet-support.patch \
+           file://0022-watchdog-ts72xx_wdt-disable-watchdog-at-probe.patch \
+           file://0024-TS-72XX-LCD-console-driver.patch \
+           file://0025-ts72xx-add-lcd-linux-driver.patch \
            "
 
 SRC_URI_append_om-gta01 = " \