From f52c927a6514b572f9c91b0ce3e62ea125095929 Mon Sep 17 00:00:00 2001 From: juhosg Date: Wed, 8 Feb 2012 16:39:20 +0000 Subject: [PATCH] package/lcd4linux: add driver for the LCD of the TEW-673GRU board git-svn-id: svn://svn.openwrt.org/openwrt/packages@30381 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- utils/lcd4linux/Config.in | 6 + utils/lcd4linux/Makefile | 5 +- .../170-add-generic-spidev-driver.patch | 289 +++++++++ ...ecify-drv_generic_graphic_real_clear.patch | 45 ++ .../patches/172-add-TEW673GRU-driver.patch | 553 ++++++++++++++++++ 5 files changed, 896 insertions(+), 2 deletions(-) create mode 100644 utils/lcd4linux/patches/170-add-generic-spidev-driver.patch create mode 100644 utils/lcd4linux/patches/171-allow-to-specify-drv_generic_graphic_real_clear.patch create mode 100644 utils/lcd4linux/patches/172-add-TEW673GRU-driver.patch diff --git a/utils/lcd4linux/Config.in b/utils/lcd4linux/Config.in index 94fa25435..621a5d39b 100644 --- a/utils/lcd4linux/Config.in +++ b/utils/lcd4linux/Config.in @@ -240,6 +240,12 @@ config LCD4LINUX_CUSTOM_DRIVER_T6963 prompt "T6963" select LCD4LINUX_CUSTOM_NEEDS_libgd +config LCD4LINUX_CUSTOM_DRIVER_TEW673GRU + bool + select LCD4LINUX_CUSTOM_NEEDS_libgd + depends on TARGET_ar71xx + default TARGET_ar71xx + config LCD4LINUX_CUSTOM_DRIVER_Trefon bool prompt "Trefon" diff --git a/utils/lcd4linux/Makefile b/utils/lcd4linux/Makefile index e0aa272ef..52bf057f1 100644 --- a/utils/lcd4linux/Makefile +++ b/utils/lcd4linux/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2007-2011 OpenWrt.org +# Copyright (C) 2007-2012 OpenWrt.org # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. @@ -10,7 +10,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=lcd4linux PKG_REV:=1159 PKG_VERSION:=r$(PKG_REV) -PKG_RELEASE:=4 +PKG_RELEASE:=5 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 PKG_SOURCE_URL:=https://ssl.bulix.org/svn/lcd4linux/trunk/ @@ -58,6 +58,7 @@ LCD4LINUX_DRIVERS:= \ SimpleLCD \ st2205 \ T6963 \ + $(if $(CONFIG_TARGET_ar71xx),TEW673GRU) \ Trefon \ USBHUB \ USBLCD \ diff --git a/utils/lcd4linux/patches/170-add-generic-spidev-driver.patch b/utils/lcd4linux/patches/170-add-generic-spidev-driver.patch new file mode 100644 index 000000000..5b5741b05 --- /dev/null +++ b/utils/lcd4linux/patches/170-add-generic-spidev-driver.patch @@ -0,0 +1,289 @@ +--- a/Makefile.am ++++ b/Makefile.am +@@ -71,6 +71,8 @@ drv_generic_i2c.c \ + drv_generic_i2c.h \ + drv_generic_keypad.c \ + drv_generic_keypad.h \ ++drv_generic_spidev.c \ ++drv_generic_spidev.h \ + drv_ASTUSB.c \ + drv_BeckmannEgle.c \ + drv_BWCT.c \ +--- /dev/null ++++ b/drv_generic_spidev.c +@@ -0,0 +1,89 @@ ++/* $Id$ ++ * $URL$ ++ * ++ * generic driver helper for displays connected via SPI bus ++ * ++ * Copyright (C) 2012 Gabor Juhos ++ * ++ * This file is part of LCD4Linux. ++ * ++ * LCD4Linux 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, or (at your option) ++ * any later version. ++ * ++ * LCD4Linux 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "debug.h" ++#include "qprintf.h" ++#include "cfg.h" ++#include "drv_generic_spidev.h" ++ ++static char *generic_spidev_section = ""; ++static char *generic_spidev_driver = ""; ++static int generic_spidev_fd; ++ ++int drv_generic_spidev_open(const char *section, const char *driver) ++{ ++ char *spidev; ++ ++ udelay_init(); ++ ++ generic_spidev_section = (char *) section; ++ generic_spidev_driver = (char *) driver; ++ ++ spidev = cfg_get(generic_spidev_section, "Port", NULL); ++ ++ info("%s: initializing SPI device %s", generic_spidev_driver, spidev); ++ generic_spidev_fd = open(spidev, O_WRONLY); ++ if (generic_spidev_fd < 0) { ++ error("%s: unable to open SPI device %s!\n", generic_spidev_driver, spidev); ++ goto exit_error; ++ } ++ ++ return 0; ++ ++ exit_error: ++ free(spidev); ++ return -1; ++} ++ ++int drv_generic_spidev_close(void) ++{ ++ close(generic_spidev_fd); ++ return 0; ++} ++ ++int drv_generic_spidev_transfer(const int count, struct spi_ioc_transfer *tr) ++{ ++ int ret; ++ ++ ret = ioctl(generic_spidev_fd, SPI_IOC_MESSAGE(count), tr); ++ if (ret < count) { ++ error("%s: can't send SPI message! (%s)\n", ++ generic_spidev_driver, strerror(errno)); ++ return -1; ++ } ++ ++ return 0; ++} +--- /dev/null ++++ b/drv_generic_spidev.h +@@ -0,0 +1,54 @@ ++/* $Id$ ++ * $URL$ ++ * ++ * generic driver helper for displays connected via SPI bus ++ * ++ * Copyright (C) 2012 Gabor Juhos ++ * Copyright (C) 2012 The LCD4Linux Team ++ * ++ * This file is part of LCD4Linux. ++ * ++ * LCD4Linux 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, or (at your option) ++ * any later version. ++ * ++ * LCD4Linux 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++/* ++ * ++ * exported fuctions: ++ * ++ * int drv_generic_spidev_open (const char *section, const char *driver) ++ * reads 'Port' entry from config and opens ++ * the SPI device ++ * returns 0 if ok, -1 on failure ++ * ++ * int drv_generic_spidev_close (void) ++ * closes SPI device ++ * returns 0 if ok, -1 on failure ++ * ++ * void drv_generic_spidev_transfer (int count, struct spi_ioc_transfer *tr) ++ * transfer data to/from the SPI device ++ * ++ */ ++ ++#ifndef _DRV_GENERIC_SPIDEV_H_ ++#define _DRV_GENERIC_SPIDEV_H_ ++ ++#include ++ ++int drv_generic_spidev_open(const char *section, const char *driver); ++int drv_generic_spidev_close(void); ++int drv_generic_spidev_transfer(const int count, struct spi_ioc_transfer *tr); ++ ++#endif /* _DRV_GENERIC_SPIDEV_H_ */ +--- a/drivers.m4 ++++ b/drivers.m4 +@@ -232,9 +232,9 @@ for driver in $drivers; do + serdisplib) + SERDISPLIB=$val; + ;; +- ShuttleVFD) ++ ShuttleVFD) + SHUTTLEVFD=$val +- ;; ++ ;; + SimpleLCD) + SIMPLELCD=$val + ;; +@@ -285,6 +285,7 @@ PARPORT="no" + SERIAL="no" + I2C="no" + KEYPAD="no" ++SPIDEV="no" + + # generic libraries + LIBUSB="no" +@@ -544,17 +545,17 @@ if test "$MATRIXORBITALGX" = "yes"; then + fi + fi + +-if test "$MDM166A" = "yes"; then +- if test "$has_usb10" = "true"; then ++if test "$MDM166A" = "yes"; then ++ if test "$has_usb10" = "true"; then + GRAPHIC="yes" +- DRIVERS="$DRIVERS drv_mdm166a.o" +- GPIO="yes" ++ DRIVERS="$DRIVERS drv_mdm166a.o" ++ GPIO="yes" + LIBUSB10="yes" +- AC_DEFINE(WITH_MDM166A,1,[MDM166A driver]) +- else +- AC_MSG_WARN(libusb-1.0/libusb.h not found: MDM166A driver disabled) +- fi +-fi ++ AC_DEFINE(WITH_MDM166A,1,[MDM166A driver]) ++ else ++ AC_MSG_WARN(libusb-1.0/libusb.h not found: MDM166A driver disabled) ++ fi ++fi + + if test "$MILINST" = "yes"; then + TEXT="yes" +@@ -630,7 +631,7 @@ if test "$PICOLCDGRAPHIC" = "yes"; then + if test "$has_usb" = "true"; then + TEXT="yes" + GRAPHIC="yes" +- KEYPAD="yes" ++ KEYPAD="yes" + GPIO="yes" + SERIAL="yes" + LIBUSB="yes" +@@ -698,17 +699,17 @@ if test "$SERDISPLIB" = "yes"; then + fi + fi + +-if test "$SHUTTLEVFD" = "yes"; then +- if test "$has_usb" = "true"; then +- TEXT="yes" +- GPIO="yes" +- DRIVERS="$DRIVERS drv_ShuttleVFD.o" +- LIBUSB="yes" +- AC_DEFINE(WITH_SHUTTLEVFD,1,[ShuttleVFD driver]) +- else +- AC_MSG_WARN(usb.h not found: ShuttleVFD driver disabled) +- fi +-fi ++if test "$SHUTTLEVFD" = "yes"; then ++ if test "$has_usb" = "true"; then ++ TEXT="yes" ++ GPIO="yes" ++ DRIVERS="$DRIVERS drv_ShuttleVFD.o" ++ LIBUSB="yes" ++ AC_DEFINE(WITH_SHUTTLEVFD,1,[ShuttleVFD driver]) ++ else ++ AC_MSG_WARN(usb.h not found: ShuttleVFD driver disabled) ++ fi ++fi + + if test "$SIMPLELCD" = "yes"; then + TEXT="yes" +@@ -786,7 +787,7 @@ fi + if test "$VNC" = "yes"; then + if test "$has_vncserverlib" = "true"; then + GRAPHIC="yes" +- KEYPAD="yes" ++ KEYPAD="yes" + DRIVERS="$DRIVERS drv_vnc.o" + DRVLIBS="$DRVLIBS -L/usr/local/lib -lvncserver -lz" + AC_DEFINE(WITH_VNC,1,[vnc driver]) +@@ -874,6 +875,12 @@ if test "$KEYPAD" = "yes"; then + DRIVERS="$DRIVERS drv_generic_keypad.o" + fi + ++# generic spidev driver ++if test "$SPIDEV" = "yes"; then ++ DRIVERS="$DRIVERS drv_generic_spidev.o" ++ AC_DEFINE(WITH_SPIDEV, 1, [SPIDEV driver]) ++fi ++ + # libusb + if test "$LIBUSB" = "yes"; then + DRVLIBS="$DRVLIBS -lusb" +@@ -892,6 +899,6 @@ fi + if test "$DRIVERS" = ""; then + AC_MSG_ERROR([You should include at least one driver...]) + fi +- ++ + AC_SUBST(DRIVERS) + AC_SUBST(DRVLIBS) +--- a/configure.in ++++ b/configure.in +@@ -108,6 +108,9 @@ fi + #AC_CHECK_HEADERS(asm/io.h) + AC_CHECK_HEADERS([asm/io.h] [linux/parport.h linux/ppdev.h], [has_parport="true"], [has_parport="false"]) + ++# check for spidev ++AC_CHECK_HEADERS([linux/spi/spidev.h], [has_spidev="true"], [has_spidev="false"]) ++ + # drivers + sinclude(drivers.m4) + diff --git a/utils/lcd4linux/patches/171-allow-to-specify-drv_generic_graphic_real_clear.patch b/utils/lcd4linux/patches/171-allow-to-specify-drv_generic_graphic_real_clear.patch new file mode 100644 index 000000000..5a2664307 --- /dev/null +++ b/utils/lcd4linux/patches/171-allow-to-specify-drv_generic_graphic_real_clear.patch @@ -0,0 +1,45 @@ +--- a/drv_generic_graphic.c ++++ b/drv_generic_graphic.c +@@ -24,7 +24,7 @@ + * + */ + +-/* ++/* + * + * exported functions: + * +@@ -98,6 +98,9 @@ static int INVERTED = 0; + /* must be implemented by the real driver */ + void (*drv_generic_graphic_real_blit) () = NULL; + ++/* can be implemented by the real driver */ ++void (*drv_generic_graphic_real_clear) () = NULL; ++ + + /****************************************/ + /*** generic Framebuffer stuff ***/ +@@ -691,7 +694,10 @@ int drv_generic_graphic_clear(void) + for (i = 0; i < LCOLS * LROWS; i++) + drv_generic_graphic_FB[l][i] = NO_COL; + +- drv_generic_graphic_blit(0, 0, LROWS, LCOLS); ++ if (drv_generic_graphic_real_clear) ++ drv_generic_graphic_real_clear(NO_COL); ++ else ++ drv_generic_graphic_blit(0, 0, LROWS, LCOLS); + + return 0; + } +--- a/drv_generic_graphic.h ++++ b/drv_generic_graphic.h +@@ -40,6 +40,9 @@ extern RGBA NO_COL; /* no color (comple + /* these functions must be implemented by the real driver */ + extern void (*drv_generic_graphic_real_blit) (const int row, const int col, const int height, const int width); + ++/* these functions can be implemented by the real driver */ ++void (*drv_generic_graphic_real_clear) (const RGBA rgba); ++ + /* helper function to get pixel color or gray value */ + extern RGBA drv_generic_graphic_rgb(const int row, const int col); + extern unsigned char drv_generic_graphic_gray(const int row, const int col); diff --git a/utils/lcd4linux/patches/172-add-TEW673GRU-driver.patch b/utils/lcd4linux/patches/172-add-TEW673GRU-driver.patch new file mode 100644 index 000000000..40a569a96 --- /dev/null +++ b/utils/lcd4linux/patches/172-add-TEW673GRU-driver.patch @@ -0,0 +1,553 @@ +--- a/drivers.m4 ++++ b/drivers.m4 +@@ -38,7 +38,7 @@ AC_ARG_WITH( + [ LW_ABP, M50530, MatrixOrbital, MatrixOrbitalGX, MilfordInstruments, MDM166A,] + [ Newhaven, Noritake, NULL, Pertelian, PHAnderson,] + [ PICGraphic, picoLCD, picoLCDGraphic, PNG, PPM, RouterBoard,] +- [ Sample, serdisplib, ShuttleVFD, SimpleLCD, st2205, T6963,] ++ [ Sample, serdisplib, ShuttleVFD, SimpleLCD, st2205, T6963, TEW673GRU] + [ Trefon, ULA200, USBHUB, USBLCD, VNC, WincorNixdorf, X11], + drivers=$withval, + drivers=all +@@ -104,6 +104,7 @@ for driver in $drivers; do + SHUTTLEVFD="yes" + SIMPLELCD="yes" + T6963="yes" ++ TEW673GRU="yes" + Trefon="yes" + ULA200="yes" + USBHUB="yes" +@@ -244,6 +245,9 @@ for driver in $drivers; do + T6963) + T6963=$val + ;; ++ TEW673GRU) ++ TEW673GRU=$val ++ ;; + Trefon) + Trefon=$val + ;; +@@ -740,6 +744,18 @@ if test "$T6963" = "yes"; then + fi + fi + ++if test "$TEW673GRU" = "yes"; then ++ if test "$has_spidev" = "true"; then ++ GRAPHIC="yes" ++ TEXT="yes" ++ SPIDEV="yes" ++ DRIVERS="$DRIVERS drv_TEW673GRU.o" ++ AC_DEFINE(WITH_TEW673GRU,1,[TEW673GRU driver]) ++ else ++ AC_MSG_WARN(linux/spi/spidev.h not found: TEW673GRU driver disabled) ++ fi ++fi ++ + if test "$Trefon" = "yes"; then + if test "$has_usb" = "true"; then + TEXT="yes" +--- a/drv.c ++++ b/drv.c +@@ -89,6 +89,7 @@ extern DRIVER drv_serdisplib; + extern DRIVER drv_ShuttleVFD; + extern DRIVER drv_SimpleLCD; + extern DRIVER drv_T6963; ++extern DRIVER drv_TEW673GRU; + extern DRIVER drv_Trefon; + extern DRIVER drv_ula200; + extern DRIVER drv_USBHUB; +@@ -232,6 +233,9 @@ DRIVER *Driver[] = { + #ifdef WITH_T6963 + &drv_T6963, + #endif ++#ifdef WITH_TEW673GRU ++ &drv_TEW673GRU, ++#endif + #ifdef WITH_TREFON + &drv_Trefon, + #endif +--- a/Makefile.am ++++ b/Makefile.am +@@ -115,6 +115,7 @@ drv_serdisplib.c \ + drv_ShuttleVFD.c \ + drv_SimpleLCD.c \ + drv_T6963.c \ ++drv_TEW673GRU.c \ + drv_Trefon.c \ + drv_ula200.c \ + drv_USBHUB.c \ +--- /dev/null ++++ b/drv_TEW673GRU.c +@@ -0,0 +1,457 @@ ++/* $Id$ ++ * $URL$ ++ * ++ * TRENDnet TEW673GRU LCD4linux driver ++ * ++ * Copyright (C) 2012 Gabor Juhos ++ * ++ * based on the Sample driver which is: ++ * Copyright (C) 2005 Michael Reinelt ++ * Copyright (C) 2005, 2006, 2007 The LCD4Linux Team ++ * ++ * This file is part of LCD4Linux. ++ * ++ * LCD4Linux 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, or (at your option) ++ * any later version. ++ * ++ * LCD4Linux 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++ ++/* ++ * exported fuctions: ++ * ++ * struct DRIVER drv_TEW673GRU ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "debug.h" ++#include "cfg.h" ++#include "qprintf.h" ++#include "udelay.h" ++#include "plugin.h" ++#include "widget.h" ++#include "widget_text.h" ++#include "widget_icon.h" ++#include "widget_bar.h" ++#include "drv.h" ++ ++#include "drv_generic_text.h" ++#include "drv_generic_graphic.h" ++#include "drv_generic_spidev.h" ++ ++#ifdef WITH_DMALLOC ++#include ++#endif ++ ++#define TEW673GRU_NUM_COLS 220 ++#define TEW673GRU_NUM_ROWS 176 ++#define TEW673GRU_BPP 2 /* bytes per pixel */ ++ ++#define TEW673GRU_CMD_SIZE 9 ++#define TEW673GRU_NUM_ROW_BYTES (TEW673GRU_NUM_COLS * TEW673GRU_BPP) ++ ++enum { ++ CMD_SHOW_STRING = 49, ++ CMD_SHOW_IMAGE_DIR = 52, ++ CMD_SCREEN_COLOR = 54, ++}; ++ ++static char Name[] = "TEW673GRU"; ++ ++static char *drv_TEW673GRU_FB; ++static long FB_SIZE; ++static int MODE; ++ ++static unsigned int RGBAto16(RGBA rgb) ++{ ++ return (((rgb.R >> 3) << 11) | ((rgb.G >> 2) << 5) | (rgb.B >> 3)); ++} ++ ++static unsigned char color_msb(unsigned int color) ++{ ++ return color >> 8; ++} ++ ++static unsigned char color_lsb(unsigned int color) ++{ ++ return color & 0xff; ++} ++ ++static void drv_TEW673GRU_hw_clear(const unsigned int color) ++{ ++ unsigned char cmd[TEW673GRU_CMD_SIZE]; ++ struct spi_ioc_transfer tr[1]; ++ ++ memset(tr, '\0', sizeof(tr)); ++ memset(cmd, '\0', sizeof(cmd)); ++ ++ cmd[0] = CMD_SCREEN_COLOR; ++ cmd[7] = color_msb(color); ++ cmd[8] = color_lsb(color); ++ ++ tr[0].tx_buf = (unsigned long) cmd; ++ tr[0].len = sizeof(cmd); ++ ++ drv_generic_spidev_transfer(1, tr); ++} ++ ++static void drv_TEW673GRU_hw_send_row(const int row, const int col, const char *data, const int width) ++{ ++ unsigned char cmd[TEW673GRU_CMD_SIZE]; ++ struct spi_ioc_transfer tr[2]; ++ int datasize; ++ ++ memset(tr, '\0', sizeof(tr)); ++ memset(cmd, '\0', sizeof(cmd)); ++ ++ datasize = width * TEW673GRU_BPP; ++ ++ cmd[0] = CMD_SHOW_IMAGE_DIR; ++ cmd[1] = col; ++ cmd[2] = col + width; ++ cmd[3] = row; ++ cmd[4] = row; ++ cmd[5] = datasize >> 8; ++ cmd[6] = datasize & 0xff; ++ ++ tr[0].tx_buf = (unsigned long) cmd; ++ tr[0].len = sizeof(cmd); ++ tr[1].tx_buf = (unsigned long) data; ++ tr[1].len = datasize; ++ ++ drv_generic_spidev_transfer(2, tr); ++} ++ ++static void drv_TEW673GRU_hw_write_string(const int row, const int col, const char *data, const int datasize) ++{ ++ unsigned char cmd[TEW673GRU_CMD_SIZE]; ++ struct spi_ioc_transfer tr[2]; ++ unsigned char len; ++ ++ memset(tr, '\0', sizeof(tr)); ++ memset(cmd, '\0', sizeof(cmd)); ++ ++ len = datasize & 0xff; ++ cmd[0] = CMD_SHOW_STRING; ++ cmd[1] = col; ++ cmd[2] = col + (XRES * len); ++ cmd[3] = row; ++ cmd[4] = row + YRES; ++ cmd[7] = 0; ++ cmd[8] = len; ++ ++ tr[0].tx_buf = (unsigned long) cmd; ++ tr[0].len = sizeof(cmd); ++ tr[1].tx_buf = (unsigned long) data; ++ tr[1].len = datasize; ++ ++ drv_generic_spidev_transfer(2, tr); ++} ++ ++static void drv_TEW673GRU_FB_set_pixel(const int col, const unsigned int color) ++{ ++ int pos; ++ ++ pos = col * TEW673GRU_BPP; ++ drv_TEW673GRU_FB[pos] = color_msb(color); ++ drv_TEW673GRU_FB[pos + 1] = color_lsb(color); ++} ++ ++static void drv_TEW673GRU_blit(const int row, const int col, const int height, const int width) ++{ ++ int r, c; ++ ++ debug("%s: update area r:%d c:%d w:%d h:%d", Name, row, col, height, width); ++ ++ for (r = row; r < row + height; r++) { ++ for (c = col; c < col + width; c++) { ++ unsigned int color; ++ RGBA rgb; ++ ++ rgb = drv_generic_graphic_rgb(r, c); ++ color = RGBAto16(rgb); ++ drv_TEW673GRU_FB_set_pixel(c, color); ++ } ++ ++ if (width) { ++ char *data; ++ ++ data = &drv_TEW673GRU_FB[col * TEW673GRU_BPP]; ++ drv_TEW673GRU_hw_send_row(r, col, data, width); ++ udelay(100 + width * 50); ++ } ++ } ++} ++ ++static void drv_TEW673GRU_clear(RGBA rgba) ++{ ++ unsigned int color; ++ ++ color = RGBAto16(rgba); ++ drv_TEW673GRU_hw_clear(color); ++} ++ ++static void drv_TEW673GRU_write(const int row, const int col, const char *data, const int len) ++{ ++ int i; ++ ++ for (i = 0; i < len; i++) { ++ drv_TEW673GRU_hw_write_string(row * YRES, (col + i) * XRES, " ", 1); ++ udelay(10000); ++ drv_TEW673GRU_hw_write_string(row * YRES, 2 + (col + i) * XRES, " ", 1); ++ udelay(10000); ++ drv_TEW673GRU_hw_write_string(row * YRES, (col + i) * XRES, &data[i], 1); ++ udelay(10000); ++ } ++} ++ ++static int drv_TEW673GRU_open(const char *section) ++{ ++ int err; ++ ++ err = drv_generic_spidev_open(section, Name); ++ if (err < 0) ++ return err; ++ ++ return 0; ++} ++ ++static int drv_TEW673GRU_close(void) ++{ ++ drv_generic_spidev_close(); ++ return 0; ++} ++ ++static void drv_TEW673GRU_clear_screen(void) ++{ ++ if (MODE) { ++ drv_generic_graphic_clear(); ++ } else { ++ memset(drv_TEW673GRU_FB, ' ', FB_SIZE); ++ drv_TEW673GRU_hw_clear(0x0000); ++ } ++} ++ ++static int drv_TEW673GRU_init_font(const char *section) ++{ ++ char *font; ++ int ret = -1; ++ ++ font = cfg_get(section, "Font", "6x8"); ++ if (font == NULL) { ++ error("%s: no '%s.Font' entry from %s", Name, section, cfg_source()); ++ goto out; ++ } ++ ++ if (*font == '\0') { ++ error("%s: invalid '%s.Font' entry in %s", Name, section, cfg_source()); ++ goto out_free; ++ } ++ ++ XRES = -1; ++ YRES = -1; ++ if (sscanf(font, "%dx%d", &XRES, &YRES) != 2 || ++ XRES < 1 || ++ YRES < 1) { ++ error("%s: bad Font '%s' from %s", Name, font, cfg_source()); ++ goto out_free; ++ } ++ ++ if (XRES != 6 && YRES != 8) { ++ error("%s: bad Font '%s' from %s (only 6x8 at the moment)", ++ Name, font, cfg_source()); ++ goto out_free; ++ } ++ ++ error("%s: font '%s' selected", Name, font); ++ ++ ret = 0; ++ ++out_free: ++ free(font); ++out: ++ return ret; ++} ++ ++static int drv_TEW673GRU_start(const char *section) ++{ ++ int ret; ++ ++ DCOLS = TEW673GRU_NUM_COLS; ++ DROWS = TEW673GRU_NUM_ROWS; ++ ++ if (MODE) { ++ ret = drv_TEW673GRU_init_font(section); ++ if (ret) ++ goto err; ++ ++ FB_SIZE = DCOLS * TEW673GRU_BPP; ++ } else { ++ XRES = 10; ++ YRES = 16; ++ DCOLS = DCOLS / XRES; ++ DROWS = DROWS / YRES; ++ ++ FB_SIZE = DCOLS * DROWS; ++ } ++ ++ if (FB_SIZE) { ++ drv_TEW673GRU_FB = malloc(FB_SIZE); ++ if (drv_TEW673GRU_FB == NULL) { ++ error("%s: framebuffer could not be allocated", Name); ++ goto err; ++ } ++ } ++ ++ ret = drv_TEW673GRU_open(section); ++ if (ret < 0) ++ goto err_free; ++ ++ if (MODE == 0) ++ drv_TEW673GRU_clear_screen(); ++ ++ return 0; ++ ++ err_free: ++ if (drv_TEW673GRU_FB) ++ free(drv_TEW673GRU_FB); ++ err: ++ return -1; ++} ++ ++static int drv_TEW673GRU_greet(const char *msg1, const char *msg2) ++{ ++ if (MODE) ++ return drv_generic_graphic_greet(msg1, msg2); ++ ++ return drv_generic_text_greet(msg1, msg2); ++} ++ ++ ++/****************************************/ ++/*** widget callbacks ***/ ++/****************************************/ ++ ++ ++/* using drv_generic_text_draw(W) */ ++/* using drv_generic_text_icon_draw(W) */ ++/* using drv_generic_text_bar_draw(W) */ ++/* using drv_generic_gpio_draw(W) */ ++ ++ ++/****************************************/ ++/*** exported functions ***/ ++/****************************************/ ++ ++int drv_TEW673GRU_list(void) ++{ ++ printf("TEW673GRU driver"); ++ return 0; ++} ++ ++int drv_TEW673GRU_init(const char *section, const int quiet) ++{ ++ WIDGET_CLASS wc; ++ int ret; ++ ++ cfg_number(section, "Mode", 0, 0, 1, &MODE); ++ ++ if (MODE) { ++ drv_generic_graphic_real_blit = drv_TEW673GRU_blit; ++ drv_generic_graphic_real_clear = drv_TEW673GRU_clear; ++ } else { ++ drv_generic_text_real_write = drv_TEW673GRU_write; ++ } ++ ++ ret = drv_TEW673GRU_start(section); ++ if (ret) ++ return ret; ++ ++ if (MODE) { ++ ret = drv_generic_graphic_init(section, Name); ++ if (ret) ++ return ret; ++ } else { ++ ret = drv_generic_text_init(section, Name); ++ if (ret) ++ return ret; ++ ++ ret = drv_generic_text_icon_init(); ++ if (ret != 0) ++ return ret; ++ ++ ret = drv_generic_text_bar_init(1); ++ if (ret != 0) ++ return ret; ++ ++ drv_generic_text_bar_add_segment(0, 0, 255, ' '); ++ drv_generic_text_bar_add_segment(255, 255, 255, '#'); ++ ++ wc = Widget_Text; ++ wc.draw = drv_generic_text_draw; ++ widget_register(&wc); ++ ++ wc = Widget_Icon; ++ wc.draw = drv_generic_text_icon_draw; ++ widget_register(&wc); ++ ++ wc = Widget_Bar; ++ wc.draw = drv_generic_text_bar_draw; ++ widget_register(&wc); ++ } ++ ++ if (!quiet) { ++ char buffer[40]; ++ qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, DCOLS, DROWS); ++ drv_TEW673GRU_greet(buffer, "www.openwrt.org"); ++ sleep(3); ++ drv_TEW673GRU_clear_screen(); ++ } ++ ++ return 0; ++} ++ ++int drv_TEW673GRU_quit(const int quiet) ++{ ++ ++ info("%s: shutting down.", Name); ++ ++ drv_TEW673GRU_clear_screen(); ++ ++ if (!quiet) ++ drv_TEW673GRU_greet("goodbye!", NULL); ++ ++ if (MODE) ++ drv_generic_graphic_quit(); ++ else ++ drv_generic_text_quit(); ++ ++ debug("closing connection"); ++ drv_TEW673GRU_close(); ++ ++ return (0); ++} ++ ++DRIVER drv_TEW673GRU = { ++ .name = Name, ++ .list = drv_TEW673GRU_list, ++ .init = drv_TEW673GRU_init, ++ .quit = drv_TEW673GRU_quit, ++}; +--- a/lcd4linux.conf.sample ++++ b/lcd4linux.conf.sample +@@ -547,6 +547,12 @@ Display VNC { + HttpPort '5800' + } + ++Display TEW673GRU { ++ Driver 'TEW673GRU' ++ Font '6x8' ++ Port '/dev/spidev1.0' ++} ++ + #Plugin KVV { + # StationID '12_701' + # Refresh 30