From 181cec4348da40331b3e8ab365732c025ec149b2 Mon Sep 17 00:00:00 2001 From: Reinhard Tartler Date: Wed, 27 Apr 2011 19:24:15 +0200 Subject: Import upstream version 0.11.0~svn1143 --- drv_RouterBoard.c | 693 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 693 insertions(+) create mode 100644 drv_RouterBoard.c (limited to 'drv_RouterBoard.c') diff --git a/drv_RouterBoard.c b/drv_RouterBoard.c new file mode 100644 index 0000000..0948255 --- /dev/null +++ b/drv_RouterBoard.c @@ -0,0 +1,693 @@ +/* $Id: drv_RouterBoard.c 771 2007-02-25 12:27:26Z michael $ + * $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/drv_RouterBoard.c $ + * + * driver for the "Router Board LCD port" + * see port details at http://www.routerboard.com + * + * Copyright (C) 2004 Roman Jozsef + * Copyright (C) 2004 The LCD4Linux Team + * + * based on the HD44780 parallel port driver and RB SDK example + * + * 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. + * + */ + + +/* This particulary board not have paralell port but have a special LCD header + * where can connect an HD44780 display. + * This port called IOSC0 port, and is write only, this port control the + * 4 leds on board too. + * Because its a write only port you can't control leds outside lcd driver + * or inverse, for this added the socket controlled leds. To send led status + * simply open an UDP socket and send to localhost 127.0.0.1 port 3333 one + * byte or more anyway only the first byte 4 low bits used the others is + * cleared and ignored bit0 = Led1 ,bit1 = Led2 ... + * This socket polled via timer callback, for detail see at drv_RB_start() + * I add at to end of this file an example! + * If you don't want coment #define RB_WITH LEDS and this part will be ignored + * + * The connection details: + * The IOCS0 port lower 16 bits connected as follows: + * bit LCD LEDS + * 0..7 data + * 8 INITX + * 9 SLINX + * 10 AFDX + * 11 backlit + * 12 LED1 + * 13 LED2 + * 14 LED3 + * 15 LED4 + * + * LCD male header: + * 1 Vcc +5V + * 2 GND + * 3 RS (Register Select,AFDX) + * 4 Contrast adjust (controlled) but how? if you know tell me not mentioned on User Manual + * 5 E (enable signal, INITX) + * 6 R/W (Data read/write or SLINX) not used connect LCD pin to ground + * 7 Data 1 + * 8 Data 0 + * 9 Data 3 + * 10 Data 2 + * 11 Data 5 + * 12 Data 4 + * 13 Data 7 + * 14 Data 6 + * 15 Backlit GND (controlled) (IOSC0 bit 11) + * 16 Backlit Vcc +5V + * + * If you using this driver and board and you have any fun device connected, + * program or story :-) ,please share for me. Thanks. + * + * Literature + * [GEODE] Geode SC1100 Information Appliance On a Chip + * (http://www.national.com/ds/SC/SC1100.pdf) + * [RB User Manual] + * (http://www.routerboard.com) + * + * + * Revision 1.2 + * Added backlight control + */ + + +/* + * + * exported fuctions: + * + * struct DRIVER drv_RouterBoard + * + */ + + + + + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "debug.h" +#include "cfg.h" +#include "udelay.h" +#include "qprintf.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_gpio.h" + + +/* #define RB_WITH_LEDS 1 */ + +#ifdef RB_WITH_LEDS /* Build without socket&led support */ + +#include +#include +#include + +#define POLL_TIMEOUT 10 /* Socket poll timeout */ +#define MAXMSG_SIZE 100 /* Max messagge we can receive */ + +static int sock_c; /* Socket handler */ +static struct sockaddr_in *sacl; +char sock_msg[MAXMSG_SIZE]; + +#endif + + +static char Name[] = "RouterBoard"; + +static int Model; +static int Capabilities; + +/* RouterBoard control signals */ + +#define LCD_INITX 0x0100 +#define LCD_SLINX 0x0200 +#define LCD_AFDX 0x0400 +#define LCD_BACKLIGHT 0x0800 +#define RB_LEDS 0xF000 + +#define CAR 0x0CF8 +#define CDR 0x0CFC + + +/* HD44780 execution timings [microseconds] + * as these values differ from spec to spec, + * we use the worst-case values. + */ + +#define T_INIT1 4100 /* first init sequence: 4.1 msec */ +#define T_INIT2 100 /* second init sequence: 100 usec */ +#define T_EXEC 80 /* normal execution time */ +#define T_WRCG 120 /* CG RAM Write */ +#define T_CLEAR 1680 /* Clear Display */ +#define T_AS 60 /* Address setup time */ + + +/* buffer holding the GPO state */ +static unsigned char GPO = 0; + +/* buffor holding backlight and LED states */ +static unsigned int RB_Leds = 0; + +typedef struct { + int type; + char *name; + int capabilities; +} MODEL; + +#define CAP_HD66712 (1<<0) + +static MODEL Models[] = { + {0x01, "HD44780", 0}, + {0x02, "HD66712", CAP_HD66712}, + {0xff, "Unknown", 0} +}; + + +/****************************************/ +/*** hardware dependant functions ***/ +/****************************************/ + +#ifdef RB_WITH_LEDS + +static int drv_RB_sock_init() +{ + + if ((sacl = (struct sockaddr_in *) malloc(sizeof(struct sockaddr_in))) == NULL) { + return -1; + } + + memset(sacl, 0, sizeof(struct sockaddr_in)); + sacl->sin_family = AF_INET; + sacl->sin_port = htons(3333); /* Listen Port */ + sacl->sin_addr.s_addr = inet_addr("127.0.0.1"); /* Listen Address */ + + if ((sock_c = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + error("Socket open failed"); + free(sacl); + return -1; + } + + if (bind(sock_c, (struct sockaddr *) sacl, sizeof(struct sockaddr_in)) < 0) { + error("Socket bind open failed"); + free(sacl); + return -1; + } + return 0; +} + + +static void drv_RB_poll_data(void __attribute__ ((unused)) * notused) +{ + int len, size; + struct pollfd usfd; + usfd.fd = sock_c; + usfd.events = POLLIN | POLLPRI; + while (poll(&usfd, 1, POLL_TIMEOUT) > 0) { + len = sizeof(struct sockaddr_in); + if ((size = recvfrom(sock_c, sock_msg, MAXMSG_SIZE, 0, (struct sockaddr *) sacl, (socklen_t *) & len)) < 0); + else { + RB_Leds &= 0x0fff; + RB_Leds |= (sock_msg[0] & 0x0F) << 12; + /* fprintf(stderr, "Received data %s\n",sock_msg); */ + } + } +} + +#endif + + +static void drv_RB_outw(const unsigned int data) +{ + static unsigned int port = 0; + + /* IOCS0 port number can read from PCI Configuration Space Function 0 (F0) */ + /* at index 74h as 16 bit value (see [GEODE] 5.3.1 pg.151 and pg.176 Table 5-29 */ + if (port == 0) { + /* get IO permission, here you can't use ioperm command */ + iopl(3); + outl(0x80009074, CAR); + port = inw(CDR); + } + + outw(data | RB_Leds, port); +} + + +static int drv_RB_backlight(int backlight) +{ + /* -1 is used to query the current Backlight */ + if (backlight == -1) { + return (RB_Leds & LCD_BACKLIGHT) ? 1 : 0; + } + + if (backlight > 0) { + /* set bit */ + RB_Leds |= LCD_BACKLIGHT; + backlight = 1; + } else { + backlight = 0; + /* clear bit */ + RB_Leds &= ~LCD_BACKLIGHT; + } + + /* Set backlight output */ + drv_RB_outw(0); + + return backlight; +} + + + + +static void drv_RB_command(const unsigned char cmd, const int delay) +{ + + drv_RB_outw(LCD_INITX | cmd); + ndelay(T_AS); + drv_RB_outw(cmd); + + /* wait for command completion */ + udelay(delay); + +} + + +static void drv_RB_data(const char *string, const int len, const int delay) +{ + int l = len; + unsigned char ch; + + /* sanity check */ + if (len <= 0) + return; + + while (l--) { + + ch = *(string++); + + drv_RB_outw(ch | LCD_AFDX | LCD_INITX); + ndelay(T_AS); + drv_RB_outw(ch | LCD_AFDX); + + /* wait for command completion */ + udelay(delay); + + } +} + + +static void drv_RB_clear(void) +{ + drv_RB_command(0x01, T_CLEAR); +} + + +static void drv_RB_goto(int row, int col) +{ + int pos; + + /* 16x1 Displays are organized as 8x2 :-( */ + if (DCOLS == 16 && DROWS == 1 && col > 7) { + row++; + col -= 8; + } + + if (Capabilities & CAP_HD66712) { + /* the HD66712 doesn't have a braindamadged RAM layout */ + pos = row * 32 + col; + } else { + /* 16x4 Displays use a slightly different layout */ + if (DCOLS == 16 && DROWS == 4) { + pos = (row % 2) * 64 + (row / 2) * 16 + col; + } else { + pos = (row % 2) * 64 + (row / 2) * 20 + col; + } + } + drv_RB_command((0x80 | pos), T_EXEC); +} + + +static void drv_RB_write(const int row, const int col, const char *data, const int len) +{ + drv_RB_goto(row, col); + drv_RB_data(data, len, T_EXEC); +} + + +static void drv_RB_defchar(const int ascii, const unsigned char *matrix) +{ + int i; + char buffer[8]; + + for (i = 0; i < 8; i++) { + buffer[i] = matrix[i] & 0x1f; + } + + drv_RB_command(0x40 | 8 * ascii, T_EXEC); + drv_RB_data(buffer, 8, T_WRCG); +} + + +static int drv_RB_GPO(const int num, const int val) +{ + int v; + + if (val > 0) { + /* set bit */ + v = 1; + GPO |= 1 << num; + } else { + /* clear bit */ + v = 0; + GPO &= ~(1 << num); + } + + RB_Leds &= 0x0fff; + RB_Leds |= GPO << 12; + + drv_RB_outw(0); + + return v; +} + + +static int drv_RB_start(const char *section, const int quiet) +{ + char *model, *strsize; + int rows = -1, cols = -1, gpos = -1; + int l; + + model = cfg_get(section, "Model", "HD44780"); + if (model != NULL && *model != '\0') { + int i; + for (i = 0; Models[i].type != 0xff; i++) { + if (strcasecmp(Models[i].name, model) == 0) + break; + } + if (Models[i].type == 0xff) { + error("%s: %s.Model '%s' is unknown from %s", Name, section, model, cfg_source()); + return -1; + } + Model = i; + Capabilities = Models[Model].capabilities; + info("%s: using model '%s'", Name, Models[Model].name); + } else { + error("%s: empty '%s.Model' entry from %s", Name, section, cfg_source()); + return -1; + } + free(model); + + strsize = cfg_get(section, "Size", NULL); + if (strsize == NULL || *strsize == '\0') { + error("%s: no '%s.Size' entry from %s", Name, section, cfg_source()); + free(strsize); + return -1; + } + if (sscanf(strsize, "%dx%d", &cols, &rows) != 2 || rows < 1 || cols < 1) { + error("%s: bad %s.Size '%s' from %s", Name, section, strsize, cfg_source()); + free(strsize); + return -1; + } + free(strsize); + + /*set backlight */ + if (cfg_number(section, "Backlight", 1, 0, 1, &l) > 0) { + drv_RB_backlight(l); + } + + if (cfg_number(section, "GPOs", 0, 0, 4, &gpos) < 0) + return -1; + GPOS = gpos; + if (GPOS > 0) { + info("%s: using %d GPO's", Name, GPOS); + } +#ifdef RB_WITH_LEDS + + if (drv_RB_sock_init() < 0) { + error("Sock error"); + return -1; + } else + timer_add(drv_RB_poll_data, NULL, 500, 0); + +#endif + + DROWS = rows; + DCOLS = cols; + + drv_RB_command(0x30, T_INIT1); /* 8 Bit mode, wait 4.1 ms */ + drv_RB_command(0x30, T_INIT2); /* 8 Bit mode, wait 100 us */ + drv_RB_command(0x38, T_EXEC); /* 8 Bit mode, 1/16 duty cycle, 5x8 font */ + + drv_RB_command(0x08, T_EXEC); /* Display off, cursor off, blink off */ + drv_RB_command(0x0c, T_CLEAR); /* Display on, cursor off, blink off, wait 1.64 ms */ + drv_RB_command(0x06, T_EXEC); /* curser moves to right, no shift */ + + if ((Capabilities & CAP_HD66712) && DROWS > 2) { + drv_RB_command(0x3c, T_EXEC); /* set extended register enable bit */ + drv_RB_command(0x09, T_EXEC); /* set 4-line mode */ + drv_RB_command(0x38, T_EXEC); /* clear extended register enable bit */ + } + + drv_RB_clear(); + drv_RB_command(0x03, T_CLEAR); /* return home */ + + if (!quiet) { + char buffer[40]; + qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, DCOLS, DROWS); + if (drv_generic_text_greet(buffer, NULL)) { + sleep(3); + drv_RB_clear(); + } + } + + return 0; +} + + +/****************************************/ +/*** plugins ***/ +/****************************************/ +static void plugin_backlight(RESULT * result, const int argc, RESULT * argv[]) +{ + double backlight; + + switch (argc) { + case 0: + backlight = drv_RB_backlight(-1); + SetResult(&result, R_NUMBER, &backlight); + break; + case 1: + backlight = drv_RB_backlight(R2N(argv[0])); + SetResult(&result, R_NUMBER, &backlight); + break; + default: + error("%s::backlight(): wrong number of parameters", Name); + SetResult(&result, R_STRING, ""); + } +} + + + +/****************************************/ +/*** 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 ***/ +/****************************************/ + + +/* list models */ +int drv_RB_list(void) +{ + int i; + + for (i = 0; Models[i].type != 0xff; i++) { + printf("%s ", Models[i].name); + } + return 0; +} + +/* initialize driver & display */ +int drv_RB_init(const char *section, const int quiet) +{ + WIDGET_CLASS wc; + int asc255bug; + int ret; + + info("%s: %s", Name, "$Rev: 771 $"); + + /* display preferences */ + XRES = 5; /* pixel width of one char */ + YRES = 8; /* pixel height of one char */ + CHARS = 8; /* number of user-defineable characters */ + CHAR0 = 0; /* ASCII of first user-defineable char */ + GOTO_COST = 2; /* number of bytes a goto command requires */ + + /* real worker functions */ + drv_generic_text_real_write = drv_RB_write; + drv_generic_text_real_defchar = drv_RB_defchar; + drv_generic_gpio_real_set = drv_RB_GPO; + + + /* start display */ + if ((ret = drv_RB_start(section, quiet)) != 0) + return ret; + + /* initialize generic text driver */ + if ((ret = drv_generic_text_init(section, Name)) != 0) + return ret; + + /* initialize generic icon driver */ + if ((ret = drv_generic_text_icon_init()) != 0) + return ret; + + /* initialize generic bar driver */ + if ((ret = drv_generic_text_bar_init(0)) != 0) + return ret; + + /* add fixed chars to the bar driver */ + /* most displays have a full block on ascii 255, but some have kind of */ + /* an 'inverted P'. If you specify 'asc255bug 1 in the config, this */ + /* char will not be used, but rendered by the bar driver */ + cfg_number(section, "asc255bug", 0, 0, 1, &asc255bug); + drv_generic_text_bar_add_segment(0, 0, 255, 32); /* ASCII 32 = blank */ + if (!asc255bug) + drv_generic_text_bar_add_segment(255, 255, 255, 255); /* ASCII 255 = block */ + + /* initialize generic GPIO driver */ + if ((ret = drv_generic_gpio_init(section, Name)) != 0) + return ret; + + /* register text widget */ + wc = Widget_Text; + wc.draw = drv_generic_text_draw; + widget_register(&wc); + + /* register icon widget */ + wc = Widget_Icon; + wc.draw = drv_generic_text_icon_draw; + widget_register(&wc); + + /* register bar widget */ + wc = Widget_Bar; + wc.draw = drv_generic_text_bar_draw; + widget_register(&wc); + + /* register plugins */ + AddFunction("LCD::backlight", -1, plugin_backlight); + + return 0; +} + + +/* close driver & display */ +int drv_RB_quit(const int quiet) +{ + + info("%s: shutting down.", Name); + + drv_generic_text_quit(); + drv_generic_gpio_quit(); + + /* clear *both* displays */ + drv_RB_clear(); + + /* say goodbye... */ + if (!quiet) { + drv_generic_text_greet("goodbye!", NULL); + } +#ifdef RB_WITH_LEDS + close(sock_c); + free(sacl); /*close network socket */ +#endif + + return (0); +} + + +DRIVER drv_RouterBoard = { + .name = Name, + .list = drv_RB_list, + .init = drv_RB_init, + .quit = drv_RB_quit, +}; + + + +#if 0 + +Simple example to send led status to port 3333 +#include +#include +#include +int send_packet(unsigned char leds) +{ + struct sockaddr_in *sas; + int sock; + char msg[20]; + msg[0] = leds; + msg[1] = 0; + + if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + fprintf(stderr, "Socket option failed.\n"); + return -1; + } + + if ((sas = (struct sockaddr_in *) malloc(sizeof(struct sockaddr_in))) == NULL) + return -1; + memset(sas, 0, sizeof(struct sockaddr_in)); + sas->sin_family = AF_INET; + sas->sin_port = htons(3333); + sas->sin_addr.s_addr = inet_addr("127.0.0.1"); + if (sendto(sock, msg, 6, 0, (struct sockaddr *) sas, sizeof(struct sockaddr_in)) > 0) { + free(sas); + return 1; + } + /* sent ok to dest */ + free(sas); + return -1; /* Send failed */ +} + +int main() +{ + send_packet(0x03); + return 0; +} + +#endif -- cgit v1.2.3