1
/* $Id: drv_RouterBoard.c 771 2007-02-25 12:27:26Z michael $
2
* $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/drv_RouterBoard.c $
4
* driver for the "Router Board LCD port"
5
* see port details at http://www.routerboard.com
7
* Copyright (C) 2004 Roman Jozsef <rjoco77@freemail.hu>
8
* Copyright (C) 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
10
* based on the HD44780 parallel port driver and RB SDK example
12
* This file is part of LCD4Linux.
14
* LCD4Linux is free software; you can redistribute it and/or modify
15
* it under the terms of the GNU General Public License as published by
16
* the Free Software Foundation; either version 2, or (at your option)
19
* LCD4Linux is distributed in the hope that it will be useful,
20
* but WITHOUT ANY WARRANTY; without even the implied warranty of
21
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
* GNU General Public License for more details.
24
* You should have received a copy of the GNU General Public License
25
* along with this program; if not, write to the Free Software
26
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31
/* This particulary board not have paralell port but have a special LCD header
32
* where can connect an HD44780 display.
33
* This port called IOSC0 port, and is write only, this port control the
34
* 4 leds on board too.
35
* Because its a write only port you can't control leds outside lcd driver
36
* or inverse, for this added the socket controlled leds. To send led status
37
* simply open an UDP socket and send to localhost 127.0.0.1 port 3333 one
38
* byte or more anyway only the first byte 4 low bits used the others is
39
* cleared and ignored bit0 = Led1 ,bit1 = Led2 ...
40
* This socket polled via timer callback, for detail see at drv_RB_start()
41
* I add at to end of this file an example!
42
* If you don't want coment #define RB_WITH LEDS and this part will be ignored
44
* The connection details:
45
* The IOCS0 port lower 16 bits connected as follows:
60
* 3 RS (Register Select,AFDX)
61
* 4 Contrast adjust (controlled) but how? if you know tell me not mentioned on User Manual
62
* 5 E (enable signal, INITX)
63
* 6 R/W (Data read/write or SLINX) not used connect LCD pin to ground
72
* 15 Backlit GND (controlled) (IOSC0 bit 11)
75
* If you using this driver and board and you have any fun device connected,
76
* program or story :-) ,please share for me. Thanks.
79
* [GEODE] Geode SC1100 Information Appliance On a Chip
80
* (http://www.national.com/ds/SC/SC1100.pdf)
82
* (http://www.routerboard.com)
86
* Added backlight control
94
* struct DRIVER drv_RouterBoard
117
#include "widget_text.h"
118
#include "widget_icon.h"
119
#include "widget_bar.h"
121
#include "drv_generic_text.h"
122
#include "drv_generic_gpio.h"
125
/* #define RB_WITH_LEDS 1 */
127
#ifdef RB_WITH_LEDS /* Build without socket&led support */
129
#include <arpa/inet.h>
130
#include <sys/socket.h>
131
#include <sys/poll.h>
133
#define POLL_TIMEOUT 10 /* Socket poll timeout */
134
#define MAXMSG_SIZE 100 /* Max messagge we can receive */
136
static int sock_c; /* Socket handler */
137
static struct sockaddr_in *sacl;
138
char sock_msg[MAXMSG_SIZE];
143
static char Name[] = "RouterBoard";
146
static int Capabilities;
148
/* RouterBoard control signals */
150
#define LCD_INITX 0x0100
151
#define LCD_SLINX 0x0200
152
#define LCD_AFDX 0x0400
153
#define LCD_BACKLIGHT 0x0800
154
#define RB_LEDS 0xF000
160
/* HD44780 execution timings [microseconds]
161
* as these values differ from spec to spec,
162
* we use the worst-case values.
165
#define T_INIT1 4100 /* first init sequence: 4.1 msec */
166
#define T_INIT2 100 /* second init sequence: 100 usec */
167
#define T_EXEC 80 /* normal execution time */
168
#define T_WRCG 120 /* CG RAM Write */
169
#define T_CLEAR 1680 /* Clear Display */
170
#define T_AS 60 /* Address setup time */
173
/* buffer holding the GPO state */
174
static unsigned char GPO = 0;
176
/* buffor holding backlight and LED states */
177
static unsigned int RB_Leds = 0;
185
#define CAP_HD66712 (1<<0)
187
static MODEL Models[] = {
188
{0x01, "HD44780", 0},
189
{0x02, "HD66712", CAP_HD66712},
194
/****************************************/
195
/*** hardware dependant functions ***/
196
/****************************************/
200
static int drv_RB_sock_init()
203
if ((sacl = (struct sockaddr_in *) malloc(sizeof(struct sockaddr_in))) == NULL) {
207
memset(sacl, 0, sizeof(struct sockaddr_in));
208
sacl->sin_family = AF_INET;
209
sacl->sin_port = htons(3333); /* Listen Port */
210
sacl->sin_addr.s_addr = inet_addr("127.0.0.1"); /* Listen Address */
212
if ((sock_c = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
213
error("Socket open failed");
218
if (bind(sock_c, (struct sockaddr *) sacl, sizeof(struct sockaddr_in)) < 0) {
219
error("Socket bind open failed");
227
static void drv_RB_poll_data(void __attribute__ ((unused)) * notused)
232
usfd.events = POLLIN | POLLPRI;
233
while (poll(&usfd, 1, POLL_TIMEOUT) > 0) {
234
len = sizeof(struct sockaddr_in);
235
if ((size = recvfrom(sock_c, sock_msg, MAXMSG_SIZE, 0, (struct sockaddr *) sacl, (socklen_t *) & len)) < 0);
238
RB_Leds |= (sock_msg[0] & 0x0F) << 12;
239
/* fprintf(stderr, "Received data %s\n",sock_msg); */
247
static void drv_RB_outw(const unsigned int data)
249
static unsigned int port = 0;
251
/* IOCS0 port number can read from PCI Configuration Space Function 0 (F0) */
252
/* at index 74h as 16 bit value (see [GEODE] 5.3.1 pg.151 and pg.176 Table 5-29 */
254
/* get IO permission, here you can't use ioperm command */
256
outl(0x80009074, CAR);
260
outw(data | RB_Leds, port);
264
static int drv_RB_backlight(int backlight)
266
/* -1 is used to query the current Backlight */
267
if (backlight == -1) {
268
return (RB_Leds & LCD_BACKLIGHT) ? 1 : 0;
273
RB_Leds |= LCD_BACKLIGHT;
278
RB_Leds &= ~LCD_BACKLIGHT;
281
/* Set backlight output */
290
static void drv_RB_command(const unsigned char cmd, const int delay)
293
drv_RB_outw(LCD_INITX | cmd);
297
/* wait for command completion */
303
static void drv_RB_data(const char *string, const int len, const int delay)
316
drv_RB_outw(ch | LCD_AFDX | LCD_INITX);
318
drv_RB_outw(ch | LCD_AFDX);
320
/* wait for command completion */
327
static void drv_RB_clear(void)
329
drv_RB_command(0x01, T_CLEAR);
333
static void drv_RB_goto(int row, int col)
337
/* 16x1 Displays are organized as 8x2 :-( */
338
if (DCOLS == 16 && DROWS == 1 && col > 7) {
343
if (Capabilities & CAP_HD66712) {
344
/* the HD66712 doesn't have a braindamadged RAM layout */
345
pos = row * 32 + col;
347
/* 16x4 Displays use a slightly different layout */
348
if (DCOLS == 16 && DROWS == 4) {
349
pos = (row % 2) * 64 + (row / 2) * 16 + col;
351
pos = (row % 2) * 64 + (row / 2) * 20 + col;
354
drv_RB_command((0x80 | pos), T_EXEC);
358
static void drv_RB_write(const int row, const int col, const char *data, const int len)
360
drv_RB_goto(row, col);
361
drv_RB_data(data, len, T_EXEC);
365
static void drv_RB_defchar(const int ascii, const unsigned char *matrix)
370
for (i = 0; i < 8; i++) {
371
buffer[i] = matrix[i] & 0x1f;
374
drv_RB_command(0x40 | 8 * ascii, T_EXEC);
375
drv_RB_data(buffer, 8, T_WRCG);
379
static int drv_RB_GPO(const int num, const int val)
394
RB_Leds |= GPO << 12;
402
static int drv_RB_start(const char *section, const int quiet)
404
char *model, *strsize;
405
int rows = -1, cols = -1, gpos = -1;
408
model = cfg_get(section, "Model", "HD44780");
409
if (model != NULL && *model != '\0') {
411
for (i = 0; Models[i].type != 0xff; i++) {
412
if (strcasecmp(Models[i].name, model) == 0)
415
if (Models[i].type == 0xff) {
416
error("%s: %s.Model '%s' is unknown from %s", Name, section, model, cfg_source());
420
Capabilities = Models[Model].capabilities;
421
info("%s: using model '%s'", Name, Models[Model].name);
423
error("%s: empty '%s.Model' entry from %s", Name, section, cfg_source());
428
strsize = cfg_get(section, "Size", NULL);
429
if (strsize == NULL || *strsize == '\0') {
430
error("%s: no '%s.Size' entry from %s", Name, section, cfg_source());
434
if (sscanf(strsize, "%dx%d", &cols, &rows) != 2 || rows < 1 || cols < 1) {
435
error("%s: bad %s.Size '%s' from %s", Name, section, strsize, cfg_source());
442
if (cfg_number(section, "Backlight", 1, 0, 1, &l) > 0) {
446
if (cfg_number(section, "GPOs", 0, 0, 4, &gpos) < 0)
450
info("%s: using %d GPO's", Name, GPOS);
454
if (drv_RB_sock_init() < 0) {
458
timer_add(drv_RB_poll_data, NULL, 500, 0);
465
drv_RB_command(0x30, T_INIT1); /* 8 Bit mode, wait 4.1 ms */
466
drv_RB_command(0x30, T_INIT2); /* 8 Bit mode, wait 100 us */
467
drv_RB_command(0x38, T_EXEC); /* 8 Bit mode, 1/16 duty cycle, 5x8 font */
469
drv_RB_command(0x08, T_EXEC); /* Display off, cursor off, blink off */
470
drv_RB_command(0x0c, T_CLEAR); /* Display on, cursor off, blink off, wait 1.64 ms */
471
drv_RB_command(0x06, T_EXEC); /* curser moves to right, no shift */
473
if ((Capabilities & CAP_HD66712) && DROWS > 2) {
474
drv_RB_command(0x3c, T_EXEC); /* set extended register enable bit */
475
drv_RB_command(0x09, T_EXEC); /* set 4-line mode */
476
drv_RB_command(0x38, T_EXEC); /* clear extended register enable bit */
480
drv_RB_command(0x03, T_CLEAR); /* return home */
484
qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, DCOLS, DROWS);
485
if (drv_generic_text_greet(buffer, NULL)) {
495
/****************************************/
497
/****************************************/
498
static void plugin_backlight(RESULT * result, const int argc, RESULT * argv[])
504
backlight = drv_RB_backlight(-1);
505
SetResult(&result, R_NUMBER, &backlight);
508
backlight = drv_RB_backlight(R2N(argv[0]));
509
SetResult(&result, R_NUMBER, &backlight);
512
error("%s::backlight(): wrong number of parameters", Name);
513
SetResult(&result, R_STRING, "");
519
/****************************************/
520
/*** widget callbacks ***/
521
/****************************************/
524
/* using drv_generic_text_draw(W) */
525
/* using drv_generic_text_icon_draw(W) */
526
/* using drv_generic_text_bar_draw(W) */
527
/* using drv_generic_gpio_draw(W) */
530
/****************************************/
531
/*** exported functions ***/
532
/****************************************/
536
int drv_RB_list(void)
540
for (i = 0; Models[i].type != 0xff; i++) {
541
printf("%s ", Models[i].name);
546
/* initialize driver & display */
547
int drv_RB_init(const char *section, const int quiet)
553
info("%s: %s", Name, "$Rev: 771 $");
555
/* display preferences */
556
XRES = 5; /* pixel width of one char */
557
YRES = 8; /* pixel height of one char */
558
CHARS = 8; /* number of user-defineable characters */
559
CHAR0 = 0; /* ASCII of first user-defineable char */
560
GOTO_COST = 2; /* number of bytes a goto command requires */
562
/* real worker functions */
563
drv_generic_text_real_write = drv_RB_write;
564
drv_generic_text_real_defchar = drv_RB_defchar;
565
drv_generic_gpio_real_set = drv_RB_GPO;
569
if ((ret = drv_RB_start(section, quiet)) != 0)
572
/* initialize generic text driver */
573
if ((ret = drv_generic_text_init(section, Name)) != 0)
576
/* initialize generic icon driver */
577
if ((ret = drv_generic_text_icon_init()) != 0)
580
/* initialize generic bar driver */
581
if ((ret = drv_generic_text_bar_init(0)) != 0)
584
/* add fixed chars to the bar driver */
585
/* most displays have a full block on ascii 255, but some have kind of */
586
/* an 'inverted P'. If you specify 'asc255bug 1 in the config, this */
587
/* char will not be used, but rendered by the bar driver */
588
cfg_number(section, "asc255bug", 0, 0, 1, &asc255bug);
589
drv_generic_text_bar_add_segment(0, 0, 255, 32); /* ASCII 32 = blank */
591
drv_generic_text_bar_add_segment(255, 255, 255, 255); /* ASCII 255 = block */
593
/* initialize generic GPIO driver */
594
if ((ret = drv_generic_gpio_init(section, Name)) != 0)
597
/* register text widget */
599
wc.draw = drv_generic_text_draw;
600
widget_register(&wc);
602
/* register icon widget */
604
wc.draw = drv_generic_text_icon_draw;
605
widget_register(&wc);
607
/* register bar widget */
609
wc.draw = drv_generic_text_bar_draw;
610
widget_register(&wc);
612
/* register plugins */
613
AddFunction("LCD::backlight", -1, plugin_backlight);
619
/* close driver & display */
620
int drv_RB_quit(const int quiet)
623
info("%s: shutting down.", Name);
625
drv_generic_text_quit();
626
drv_generic_gpio_quit();
628
/* clear *both* displays */
633
drv_generic_text_greet("goodbye!", NULL);
637
free(sacl); /*close network socket */
644
DRIVER drv_RouterBoard = {
655
Simple example to send led status to port 3333
657
#include <arpa/inet.h>
659
int send_packet(unsigned char leds)
661
struct sockaddr_in *sas;
667
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
668
fprintf(stderr, "Socket option failed.\n");
672
if ((sas = (struct sockaddr_in *) malloc(sizeof(struct sockaddr_in))) == NULL)
674
memset(sas, 0, sizeof(struct sockaddr_in));
675
sas->sin_family = AF_INET;
676
sas->sin_port = htons(3333);
677
sas->sin_addr.s_addr = inet_addr("127.0.0.1");
678
if (sendto(sock, msg, 6, 0, (struct sockaddr *) sas, sizeof(struct sockaddr_in)) > 0) {
682
/* sent ok to dest */
684
return -1; /* Send failed */