From 7777313c43f20f3a5f3315eab7c75cc21f7cee51 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Petr=20=C5=A0tetiar?= Date: Thu, 21 Oct 2010 21:48:28 +0200 Subject: [PATCH] linux-2.6.34: update kernel patchset MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit - 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 Tested-by: Ian Thompson Signed-off-by: Petr Å tetiar --- .../ts72xx/0001-ts72xx_base.patch | 29 +- .../ts72xx/0002-ts72xx_force_machine-id.patch | 10 +- .../ts72xx/0003-ep93xx_cpuinfo.patch | 10 +- .../linux-2.6.34/ts72xx/0004-ep93xx_eth.patch | 10 +- .../ts72xx/0005-ep93xx-m2m-DMA-support.patch | 10 +- .../ts72xx/0006-ts72xx_rs485.patch | 11 +- .../ts72xx/0007-ts72xx_ts_ser1.patch | 11 +- .../ts72xx/0008-ts72xx_ts_eth100.patch | 11 +- .../ts72xx/0009-ts72xx_pata.patch | 11 +- .../ts72xx/0010-ts72xx_gpio_i2c.patch | 10 +- .../ts72xx/0011-ts72xx_dio_keypad.patch | 11 +- .../ts72xx/0012-ts72xx_sbcinfo.patch | 10 +- .../ts72xx/0013-ts72xx_max197.patch | 10 +- .../ts72xx/0014-ts7200_nor_flash.patch | 11 +- .../ts72xx/0015-ts72xx_sdcard.patch | 73 +- .../ts72xx/0016-ts72xx_nand_flash.patch | 13 +- .../linux-2.6.34/ts72xx/0017-ep93xx_spi.patch | 11 +- .../ts72xx/0018-ts72xx_spi_tmp124.patch | 15 +- ...9-ts72xx-use-CPLD-watchdog-for-reset.patch | 53 + .../ts72xx/0020-ethoc-ts7300-fixes.patch | 217 + .../0021-ts7300-add-ethernet-support.patch | 87 + ...s72xx_wdt-disable-watchdog-at-probe.patch} | 4 +- .../0024-TS-72XX-LCD-console-driver.patch | 528 ++ .../0025-ts72xx-add-lcd-linux-driver.patch | 4569 +++++++++++++++++ recipes/linux/linux-2.6.34/ts72xx/defconfig | 17 +- recipes/linux/linux_2.6.34.bb | 9 +- 26 files changed, 5661 insertions(+), 100 deletions(-) create mode 100644 recipes/linux/linux-2.6.34/ts72xx/0019-ts72xx-use-CPLD-watchdog-for-reset.patch create mode 100644 recipes/linux/linux-2.6.34/ts72xx/0020-ethoc-ts7300-fixes.patch create mode 100644 recipes/linux/linux-2.6.34/ts72xx/0021-ts7300-add-ethernet-support.patch rename recipes/linux/linux-2.6.34/ts72xx/{0019-watchdog-ts72xx_wdt-disable-watchdog-at-probe.patch => 0022-watchdog-ts72xx_wdt-disable-watchdog-at-probe.patch} (89%) create mode 100644 recipes/linux/linux-2.6.34/ts72xx/0024-TS-72XX-LCD-console-driver.patch create mode 100644 recipes/linux/linux-2.6.34/ts72xx/0025-ts72xx-add-lcd-linux-driver.patch diff --git a/recipes/linux/linux-2.6.34/ts72xx/0001-ts72xx_base.patch b/recipes/linux/linux-2.6.34/ts72xx/0001-ts72xx_base.patch index 247601b527..456469d0fb 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/0001-ts72xx_base.patch +++ b/recipes/linux/linux-2.6.34/ts72xx/0001-ts72xx_base.patch @@ -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 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 --- 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 diff --git a/recipes/linux/linux-2.6.34/ts72xx/0002-ts72xx_force_machine-id.patch b/recipes/linux/linux-2.6.34/ts72xx/0002-ts72xx_force_machine-id.patch index e59bb4e122..900998dc69 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/0002-ts72xx_force_machine-id.patch +++ b/recipes/linux/linux-2.6.34/ts72xx/0002-ts72xx_force_machine-id.patch @@ -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 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 --- 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 diff --git a/recipes/linux/linux-2.6.34/ts72xx/0003-ep93xx_cpuinfo.patch b/recipes/linux/linux-2.6.34/ts72xx/0003-ep93xx_cpuinfo.patch index 83519d6336..c7f1560c73 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/0003-ep93xx_cpuinfo.patch +++ b/recipes/linux/linux-2.6.34/ts72xx/0003-ep93xx_cpuinfo.patch @@ -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 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 --- 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 diff --git a/recipes/linux/linux-2.6.34/ts72xx/0004-ep93xx_eth.patch b/recipes/linux/linux-2.6.34/ts72xx/0004-ep93xx_eth.patch index 4e3caf4de2..a945793d4c 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/0004-ep93xx_eth.patch +++ b/recipes/linux/linux-2.6.34/ts72xx/0004-ep93xx_eth.patch @@ -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 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 --- 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 diff --git a/recipes/linux/linux-2.6.34/ts72xx/0005-ep93xx-m2m-DMA-support.patch b/recipes/linux/linux-2.6.34/ts72xx/0005-ep93xx-m2m-DMA-support.patch index 5adc450a85..7e7ab0df48 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/0005-ep93xx-m2m-DMA-support.patch +++ b/recipes/linux/linux-2.6.34/ts72xx/0005-ep93xx-m2m-DMA-support.patch @@ -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 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 --- 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 diff --git a/recipes/linux/linux-2.6.34/ts72xx/0006-ts72xx_rs485.patch b/recipes/linux/linux-2.6.34/ts72xx/0006-ts72xx_rs485.patch index ae7fefe1ad..bb65acd8ea 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/0006-ts72xx_rs485.patch +++ b/recipes/linux/linux-2.6.34/ts72xx/0006-ts72xx_rs485.patch @@ -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 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 --- 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 diff --git a/recipes/linux/linux-2.6.34/ts72xx/0007-ts72xx_ts_ser1.patch b/recipes/linux/linux-2.6.34/ts72xx/0007-ts72xx_ts_ser1.patch index a6fab759c7..1d5966b5a5 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/0007-ts72xx_ts_ser1.patch +++ b/recipes/linux/linux-2.6.34/ts72xx/0007-ts72xx_ts_ser1.patch @@ -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 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 --- 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 diff --git a/recipes/linux/linux-2.6.34/ts72xx/0008-ts72xx_ts_eth100.patch b/recipes/linux/linux-2.6.34/ts72xx/0008-ts72xx_ts_eth100.patch index 75d53039da..a526674fb6 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/0008-ts72xx_ts_eth100.patch +++ b/recipes/linux/linux-2.6.34/ts72xx/0008-ts72xx_ts_eth100.patch @@ -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 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 --- 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 diff --git a/recipes/linux/linux-2.6.34/ts72xx/0009-ts72xx_pata.patch b/recipes/linux/linux-2.6.34/ts72xx/0009-ts72xx_pata.patch index 1575e0e96c..5169a3ba37 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/0009-ts72xx_pata.patch +++ b/recipes/linux/linux-2.6.34/ts72xx/0009-ts72xx_pata.patch @@ -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 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 --- 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 diff --git a/recipes/linux/linux-2.6.34/ts72xx/0010-ts72xx_gpio_i2c.patch b/recipes/linux/linux-2.6.34/ts72xx/0010-ts72xx_gpio_i2c.patch index b984736ffc..f38dc193fd 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/0010-ts72xx_gpio_i2c.patch +++ b/recipes/linux/linux-2.6.34/ts72xx/0010-ts72xx_gpio_i2c.patch @@ -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 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 --- 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 diff --git a/recipes/linux/linux-2.6.34/ts72xx/0011-ts72xx_dio_keypad.patch b/recipes/linux/linux-2.6.34/ts72xx/0011-ts72xx_dio_keypad.patch index cced7842bc..43b6edc673 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/0011-ts72xx_dio_keypad.patch +++ b/recipes/linux/linux-2.6.34/ts72xx/0011-ts72xx_dio_keypad.patch @@ -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 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 --- 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 diff --git a/recipes/linux/linux-2.6.34/ts72xx/0012-ts72xx_sbcinfo.patch b/recipes/linux/linux-2.6.34/ts72xx/0012-ts72xx_sbcinfo.patch index 8a54f2c0c3..ebbdc7faec 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/0012-ts72xx_sbcinfo.patch +++ b/recipes/linux/linux-2.6.34/ts72xx/0012-ts72xx_sbcinfo.patch @@ -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 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 --- 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 diff --git a/recipes/linux/linux-2.6.34/ts72xx/0013-ts72xx_max197.patch b/recipes/linux/linux-2.6.34/ts72xx/0013-ts72xx_max197.patch index 86f52a3fbb..71bfdc3adb 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/0013-ts72xx_max197.patch +++ b/recipes/linux/linux-2.6.34/ts72xx/0013-ts72xx_max197.patch @@ -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 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 --- 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 diff --git a/recipes/linux/linux-2.6.34/ts72xx/0014-ts7200_nor_flash.patch b/recipes/linux/linux-2.6.34/ts72xx/0014-ts7200_nor_flash.patch index c76ad361ce..4e1155bca4 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/0014-ts7200_nor_flash.patch +++ b/recipes/linux/linux-2.6.34/ts72xx/0014-ts7200_nor_flash.patch @@ -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 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 --- 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 diff --git a/recipes/linux/linux-2.6.34/ts72xx/0015-ts72xx_sdcard.patch b/recipes/linux/linux-2.6.34/ts72xx/0015-ts72xx_sdcard.patch index 2b0fd19813..692e84880e 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/0015-ts72xx_sdcard.patch +++ b/recipes/linux/linux-2.6.34/ts72xx/0015-ts72xx_sdcard.patch @@ -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 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 --- 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 + diff --git a/recipes/linux/linux-2.6.34/ts72xx/0016-ts72xx_nand_flash.patch b/recipes/linux/linux-2.6.34/ts72xx/0016-ts72xx_nand_flash.patch index ce73a860bc..aa4e4cdf65 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/0016-ts72xx_nand_flash.patch +++ b/recipes/linux/linux-2.6.34/ts72xx/0016-ts72xx_nand_flash.patch @@ -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 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 --- 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 diff --git a/recipes/linux/linux-2.6.34/ts72xx/0017-ep93xx_spi.patch b/recipes/linux/linux-2.6.34/ts72xx/0017-ep93xx_spi.patch index bba5516434..68b70ac21a 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/0017-ep93xx_spi.patch +++ b/recipes/linux/linux-2.6.34/ts72xx/0017-ep93xx_spi.patch @@ -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 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 --- 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 diff --git a/recipes/linux/linux-2.6.34/ts72xx/0018-ts72xx_spi_tmp124.patch b/recipes/linux/linux-2.6.34/ts72xx/0018-ts72xx_spi_tmp124.patch index cbc5a65965..834176f54b 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/0018-ts72xx_spi_tmp124.patch +++ b/recipes/linux/linux-2.6.34/ts72xx/0018-ts72xx_spi_tmp124.patch @@ -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 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 --- 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 index 0000000000..3fe3f67b3d --- /dev/null +++ b/recipes/linux/linux-2.6.34/ts72xx/0019-ts72xx-use-CPLD-watchdog-for-reset.patch @@ -0,0 +1,53 @@ +From 4d8e43e5ed0cda37031d889eff1ce3d4835df351 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C5=A0tetiar?= +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 +--- + 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 ++#ifdef CONFIG_MACH_TS72XX ++#include ++#include ++#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 index 0000000000..fdf11b8d0b --- /dev/null +++ b/recipes/linux/linux-2.6.34/ts72xx/0020-ethoc-ts7300-fixes.patch @@ -0,0 +1,217 @@ +From f209c092df80c68231336072f0fc21f7f57a799d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C5=A0tetiar?= +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 +Signed-off-by: Petr Å tetiar +--- + 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 + #include + ++#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(ðoc_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 index 0000000000..75cfa78a4c --- /dev/null +++ b/recipes/linux/linux-2.6.34/ts72xx/0021-ts7300-add-ethernet-support.patch @@ -0,0 +1,87 @@ +From 9aa429c0ee97d3a3c004ff9b94ea1126f58e3eec Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C5=A0tetiar?= +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 +Signed-off-by: Petr Å tetiar +--- + 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 + #include + #include ++#include + + #include + #include +@@ -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 + diff --git a/recipes/linux/linux-2.6.34/ts72xx/0019-watchdog-ts72xx_wdt-disable-watchdog-at-probe.patch b/recipes/linux/linux-2.6.34/ts72xx/0022-watchdog-ts72xx_wdt-disable-watchdog-at-probe.patch similarity index 89% rename from recipes/linux/linux-2.6.34/ts72xx/0019-watchdog-ts72xx_wdt-disable-watchdog-at-probe.patch rename to recipes/linux/linux-2.6.34/ts72xx/0022-watchdog-ts72xx_wdt-disable-watchdog-at-probe.patch index 3f702073a2..6083781da8 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/0019-watchdog-ts72xx_wdt-disable-watchdog-at-probe.patch +++ b/recipes/linux/linux-2.6.34/ts72xx/0022-watchdog-ts72xx_wdt-disable-watchdog-at-probe.patch @@ -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 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 index 0000000000..c371aa7d35 --- /dev/null +++ b/recipes/linux/linux-2.6.34/ts72xx/0024-TS-72XX-LCD-console-driver.patch @@ -0,0 +1,528 @@ +From 13bd55a4dff8ad5cf4113e08258046ff9c647005 Mon Sep 17 00:00:00 2001 +From: Matthieu Crapet +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 +--- + 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 ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 "); ++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 index 0000000000..5ce9ae37d7 --- /dev/null +++ b/recipes/linux/linux-2.6.34/ts72xx/0025-ts72xx-add-lcd-linux-driver.patch @@ -0,0 +1,4569 @@ +From 87e2d5376d291d792ea1f53cd700114e66c90d7a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20=C5=A0tetiar?= +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 +--- + 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 ++ * ++ * 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 . ++ * ++ * 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 . 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 ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef USE_PROC ++#include ++#endif ++ ++#define LCD_LINUX_MAIN ++#include ++ ++#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 ++MODULE_ALIAS_CHARDEV(LCD_MAJOR, HD44780_MINOR); ++#include ++ ++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 "); ++#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 ++ ++#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 ++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ++#include ++#else ++#include ++#endif ++ ++#ifdef CONFIG_PROC_FS ++#define USE_PROC ++#else ++#undef USE_PROC ++#endif ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) ++#include ++#else ++#include ++#endif ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++#include ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) ++#include ++#endif ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef USE_PROC ++#include ++#endif ++ ++#define LCD_LINUX_MAIN ++#include ++ ++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 ++MODULE_ALIAS_CHARDEV_MAJOR(LCD_MAJOR); ++#endif ++MODULE_DESCRIPTION("Software layer to drive LCD displays under Linux."); ++MODULE_AUTHOR("Mattia Jona-Lasinio "); ++#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 <--\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 ++ ++#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 ++ ++#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 ++#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 ++#include ++ ++ ++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 + diff --git a/recipes/linux/linux-2.6.34/ts72xx/defconfig b/recipes/linux/linux-2.6.34/ts72xx/defconfig index aae549645e..939cd3656a 100644 --- a/recipes/linux/linux-2.6.34/ts72xx/defconfig +++ b/recipes/linux/linux-2.6.34/ts72xx/defconfig @@ -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 diff --git a/recipes/linux/linux_2.6.34.bb b/recipes/linux/linux_2.6.34.bb index 442fb96757..6b50590bb7 100644 --- a/recipes/linux/linux_2.6.34.bb +++ b/recipes/linux/linux_2.6.34.bb @@ -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 = " \ -- 2.39.5