root/tags/0.10.0/drv_RouterBoard.c

Revision 547, 16.0 kB (checked in by reinelt, 4 years ago)

[lcd4linux @ 2005-05-08 04:32:43 by reinelt]
CodingStyle? added and applied

Line 
1/* $Id: drv_RouterBoard.c,v 1.5 2005/05/08 04:32:44 reinelt Exp $
2 *
3 * driver for the "Router Board LCD port"
4 * see port details at http://www.routerboard.com
5 *
6 * Copyright (C) 2004  Roman Jozsef <rjoco77@freemail.hu>
7 * Copyright (C) 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
8 *
9 * based on the HD44780 parallel port driver and RB SDK example
10 *
11 * This file is part of LCD4Linux.
12 *
13 * LCD4Linux is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2, or (at your option)
16 * any later version.
17 *
18 * LCD4Linux is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 *
27 *
28 * $Log: drv_RouterBoard.c,v $
29 * Revision 1.5  2005/05/08 04:32:44  reinelt
30 * CodingStyle added and applied
31 *
32 * Revision 1.4  2005/01/18 06:30:23  reinelt
33 * added (C) to all copyright statements
34 *
35 * Revision 1.3  2004/08/30 12:48:52  rjoco77
36 *  * Added backlight update immediatelly
37 *
38 * Revision 1.2  2004/08/29 20:07:55  reinelt
39 *
40 * Patch from Joco: Make RouterBoard Backlight configurable
41 *
42 */
43
44
45/* This particulary board not have paralell port but have a special LCD header
46 * where can connect an HD44780 display.
47 * This port called IOSC0 port, and is write only, this port control the
48 * 4 leds on board too.
49 * Because its a write only port you can't control leds outside lcd driver
50 * or inverse, for this added the socket controlled leds. To send led status
51 * simply open an UDP socket and send to localhost 127.0.0.1 port 3333 one
52 * byte or more anyway only the first byte 4 low bits used the others is
53 * cleared and ignored bit0 = Led1 ,bit1 = Led2 ...
54 * This socket polled via timer callback, for detail see at drv_RB_start()
55 * I add at to end of this file an example!
56 * If you don't want coment #define RB_WITH LEDS and this part will be ignored
57 *
58 * The connection details:
59 *    The IOCS0 port lower 16 bits connected as follows:
60 *     bit   LCD  LEDS
61 *     0..7  data
62 *      8    INITX
63 *      9    SLINX
64 *      10   AFDX
65 *      11   backlit
66 *      12      LED1
67 *      13      LED2
68 *      14      LED3
69 *      15      LED4
70 *   
71 * LCD male header:
72 * 1  Vcc +5V
73 * 2  GND
74 * 3  RS (Register Select,AFDX)
75 * 4  Contrast adjust (controlled) but how? if you know tell me not mentioned on User Manual
76 * 5  E (enable signal, INITX)
77 * 6  R/W (Data read/write or SLINX) not used connect LCD pin to ground
78 * 7  Data 1
79 * 8  Data 0
80 * 9  Data 3
81 * 10 Data 2
82 * 11 Data 5
83 * 12 Data 4
84 * 13 Data 7
85 * 14 Data 6
86 * 15 Backlit GND (controlled) (IOSC0 bit 11)
87 * 16   Backlit Vcc +5V
88 *
89 * If you using this driver and board and you have any fun device connected,
90 * program or story :-) ,please share for me. Thanks.
91 *         
92 * Literature
93 *    [GEODE] Geode SC1100 Information Appliance On a Chip
94 *      (http://www.national.com/ds/SC/SC1100.pdf)     
95 *    [RB User Manual]
96 *      (http://www.routerboard.com)
97 *
98 *
99 * Revision 1.2
100 * Added backlight control
101 */
102
103
104/*
105 *
106 * exported fuctions:
107 *
108 * struct DRIVER drv_RouterBoard
109 *
110 */
111
112
113
114
115
116#include "config.h"
117
118#include <stdio.h>
119#include <stdlib.h>
120#include <string.h>
121#include <errno.h>
122#include <unistd.h>
123#include <sys/io.h>
124
125#include "debug.h"
126#include "cfg.h"
127#include "udelay.h"
128#include "qprintf.h"
129#include "plugin.h"
130#include "widget.h"
131#include "widget_text.h"
132#include "widget_icon.h"
133#include "widget_bar.h"
134#include "drv.h"
135#include "drv_generic_text.h"
136
137
138/* #define RB_WITH_LEDS 1 */
139
140#ifdef RB_WITH_LEDS   /* Build without socket&led support */
141
142#include <arpa/inet.h>
143#include <sys/socket.h>
144#include <sys/poll.h>
145
146#define POLL_TIMEOUT  10  /* Socket poll timeout */
147#define MAXMSG_SIZE 100 /* Max messagge we can receive */
148
149static int sock_c;    /* Socket handler */
150static struct sockaddr_in *sacl;
151char sock_msg[MAXMSG_SIZE];
152
153#endif
154
155
156static char Name[] = "RouterBoard";
157
158static int Model;
159static int Capabilities;
160
161/* RouterBoard control signals */
162
163#define LCD_INITX     0x0100
164#define LCD_SLINX     0x0200
165#define LCD_AFDX      0x0400
166#define LCD_BACKLIGHT 0x0800
167#define RB_LEDS       0xF000
168
169#define CAR 0x0CF8
170#define CDR 0x0CFC
171
172
173/* HD44780 execution timings [microseconds]
174 * as these values differ from spec to spec,
175 * we use the worst-case values.
176 */
177
178#define T_INIT1 4100    /* first init sequence:  4.1 msec */
179#define T_INIT2  100    /* second init sequence: 100 usec */
180#define T_EXEC    80    /* normal execution time */
181#define T_WRCG   120    /* CG RAM Write */
182#define T_CLEAR 1680    /* Clear Display */
183#define T_AS      60    /* Address setup time */
184
185/* Fixme: GPO's not yet implemented */
186static int GPOS;
187/* static int GPO=0; */
188
189/* Fixme: This actually ARE the GPO's... */
190static unsigned RB_Leds = 0;
191
192static unsigned RB_BackLight = 0;
193
194typedef struct {
195    int type;
196    char *name;
197    int capabilities;
198} MODEL;
199
200#define CAP_HD66712    (1<<0)
201
202static MODEL Models[] = {
203    {0x01, "HD44780", 0},
204    {0x02, "HD66712", CAP_HD66712},
205    {0xff, "Unknown", 0}
206};
207
208
209/****************************************/
210/***  hardware dependant functions    ***/
211/****************************************/
212
213#ifdef RB_WITH_LEDS
214
215static int drv_RB_sock_init()
216{
217
218    if ((sacl = (struct sockaddr_in *) malloc(sizeof(struct sockaddr_in))) == NULL) {
219  return -1;
220    }
221
222    memset(sacl, 0, sizeof(struct sockaddr_in));
223    sacl->sin_family = AF_INET;
224    sacl->sin_port = htons(3333); //Listen Port
225    sacl->sin_addr.s_addr = inet_addr("127.0.0.1"); //Listen Address
226
227    if ((sock_c = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
228  error("Socket open failed");
229  free(sacl);
230  return -1;
231    }
232
233    if (bind(sock_c, (struct sockaddr *) sacl, sizeof(struct sockaddr_in)) < 0) {
234  error("Socket bind open failed");
235  free(sacl);
236  return -1;
237    }
238    return 0;
239}
240
241
242static void drv_RB_poll_data(void __attribute__ ((unused)) * notused)
243{
244    int len, size;
245    struct pollfd usfd;
246    usfd.fd = sock_c;
247    usfd.events = POLLIN | POLLPRI;
248    while (poll(&usfd, 1, POLL_TIMEOUT) > 0) {
249  len = sizeof(struct sockaddr_in);
250  if ((size = recvfrom(sock_c, sock_msg, MAXMSG_SIZE, 0, (struct sockaddr *) sacl, (socklen_t *) & len)) < 0);
251  else {
252      RB_Leds = sock_msg[0] & 0x0F;
253      RB_Leds = RB_Leds << 12;
254      /* fprintf(stderr, "Received data %s\n",sock_msg); */
255  }
256    }
257}
258
259#endif
260
261/* IOCS0 port number can read from PCI Configuration Space Function 0 (F0) */
262/* at index 74h as 16 bit value (see [GEODE] 5.3.1 pg.151 and pg.176 Table 5-29 */
263
264static unsigned getIocs0Port(void)
265{
266    static unsigned ret = 0;
267
268    /*get IO permission, here you can't use ioperm command */
269    iopl(3);
270
271    if (!ret) {
272  outl(0x80009074, CAR);
273  ret = inw(CDR);
274    }
275    return ret;
276}
277
278
279static int drv_RB_backlight(int backlight)
280{
281    /* -1 is used to query  the current Backlight */
282    if (backlight == -1) {
283  if (RB_BackLight > 0)
284      return 1;   // because RB_Backlight actually is 0x0800 or 0
285  return 0;
286    }
287
288    if (backlight < 0)
289  backlight = 0;
290    if (backlight > 1)
291  backlight = 1;
292
293    RB_BackLight = backlight ? LCD_BACKLIGHT : 0;
294
295    /* Set backlight output */
296    outw(RB_Leds | RB_BackLight, getIocs0Port());
297
298    return backlight;
299}
300
301
302
303
304static void drv_RB_command(const unsigned char cmd, const int delay)
305{
306
307    outw(RB_Leds | LCD_INITX | RB_BackLight | cmd, getIocs0Port());
308
309    ndelay(T_AS);
310
311    outw(RB_Leds | RB_BackLight | cmd, getIocs0Port());
312
313    // wait for command completion
314    udelay(delay);
315
316}
317
318
319static void drv_RB_data(const char *string, const int len, const int delay)
320{
321    int l = len;
322    unsigned char ch;
323
324    /* sanity check */
325    if (len <= 0)
326  return;
327
328    while (l--) {
329
330  ch = *(string++);
331
332  outw(RB_Leds | LCD_AFDX | LCD_INITX | RB_BackLight | ch, getIocs0Port());
333
334  ndelay(T_AS);
335
336  outw(RB_Leds | LCD_AFDX | RB_BackLight | ch, getIocs0Port());
337
338  // wait for command completion
339  udelay(delay);
340
341    }
342}
343
344
345static void drv_RB_clear(void)
346{
347    drv_RB_command(0x01, T_CLEAR);
348}
349
350
351static void drv_RB_goto(int row, int col)
352{
353    int pos;
354
355    /* 16x1 Displays are organized as 8x2 :-( */
356    if (DCOLS == 16 && DROWS == 1 && col > 7) {
357  row++;
358  col -= 8;
359    }
360
361    if (Capabilities & CAP_HD66712) {
362  /* the HD66712 doesn't have a braindamadged RAM layout */
363  pos = row * 32 + col;
364    } else {
365  /* 16x4 Displays use a slightly different layout */
366  if (DCOLS == 16 && DROWS == 4) {
367      pos = (row % 2) * 64 + (row / 2) * 16 + col;
368  } else {
369      pos = (row % 2) * 64 + (row / 2) * 20 + col;
370  }
371    }
372    drv_RB_command((0x80 | pos), T_EXEC);
373}
374
375
376static void drv_RB_write(const int row, const int col, const char *data, const int len)
377{
378    drv_RB_goto(row, col);
379    drv_RB_data(data, len, T_EXEC);
380}
381
382
383static void drv_RB_defchar(const int ascii, const unsigned char *matrix)
384{
385    int i;
386    char buffer[8];
387
388    for (i = 0; i < 8; i++) {
389  buffer[i] = matrix[i] & 0x1f;
390    }
391
392    drv_RB_command(0x40 | 8 * ascii, T_EXEC);
393    drv_RB_data(buffer, 8, T_WRCG);
394}
395
396
397/* Fixme: GPO's */
398#if 0
399static void drv_RB_setGPO(const int bits)
400{
401}
402#endif
403
404static int drv_RB_start(const char *section, const int quiet)
405{
406    char *model, *strsize;
407    int rows = -1, cols = -1, gpos = -1;
408    int l;
409
410    model = cfg_get(section, "Model", "HD44780");
411    if (model != NULL && *model != '\0') {
412  int i;
413  for (i = 0; Models[i].type != 0xff; i++) {
414      if (strcasecmp(Models[i].name, model) == 0)
415    break;
416  }
417  if (Models[i].type == 0xff) {
418      error("%s: %s.Model '%s' is unknown from %s", Name, section, model, cfg_source());
419      return -1;
420  }
421  Model = i;
422  Capabilities = Models[Model].capabilities;
423  info("%s: using model '%s'", Name, Models[Model].name);
424    } else {
425  error("%s: empty '%s.Model' entry from %s", Name, section, cfg_source());
426  return -1;
427    }
428    free(model);
429
430    strsize = cfg_get(section, "Size", NULL);
431    if (strsize == NULL || *strsize == '\0') {
432  error("%s: no '%s.Size' entry from %s", Name, section, cfg_source());
433  free(strsize);
434  return -1;
435    }
436    if (sscanf(strsize, "%dx%d", &cols, &rows) != 2 || rows < 1 || cols < 1) {
437  error("%s: bad %s.Size '%s' from %s", Name, section, strsize, cfg_source());
438  free(strsize);
439  return -1;
440    }
441    free(strsize);
442
443    /*set backlight */
444    if (cfg_number(section, "Backlight", 1, 0, 1, &l) > 0) {
445  drv_RB_backlight(l);
446    }
447
448    if (cfg_number(section, "GPOs", 0, 0, 8, &gpos) < 0)
449  return -1;
450    info("%s: controlling %d GPO's", Name, gpos);
451
452#ifdef RB_WITH_LEDS
453
454    if (drv_RB_sock_init() < 0) {
455  error("Sock error");
456  return -1;
457    } else
458  timer_add(drv_RB_poll_data, NULL, 500, 0);
459
460#endif
461
462    DROWS = rows;
463    DCOLS = cols;
464    GPOS = gpos;
465
466    drv_RB_command(0x30, T_INIT1);  /* 8 Bit mode, wait 4.1 ms */
467    drv_RB_command(0x30, T_INIT2);  /* 8 Bit mode, wait 100 us */
468    drv_RB_command(0x38, T_EXEC); /* 8 Bit mode, 1/16 duty cycle, 5x8 font */
469
470    drv_RB_command(0x08, T_EXEC); /* Display off, cursor off, blink off */
471    drv_RB_command(0x0c, T_CLEAR);  /* Display on, cursor off, blink off, wait 1.64 ms */
472    drv_RB_command(0x06, T_EXEC); /* curser moves to right, no shift */
473
474    if ((Capabilities & CAP_HD66712) && DROWS > 2) {
475  drv_RB_command(0x3c, T_EXEC); /* set extended register enable bit */
476  drv_RB_command(0x09, T_EXEC); /* set 4-line mode */
477  drv_RB_command(0x38, T_EXEC); /* clear extended register enable bit */
478    }
479
480    drv_RB_clear();
481    drv_RB_command(0x03, T_CLEAR);  /* return home */
482
483    if (!quiet) {
484  char buffer[40];
485  qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, DCOLS, DROWS);
486  if (drv_generic_text_greet(buffer, NULL)) {
487      sleep(3);
488      drv_RB_clear();
489  }
490    }
491
492    return 0;
493}
494
495
496/****************************************/
497/***            plugins               ***/
498/****************************************/
499static void plugin_backlight(RESULT * result, const int argc, RESULT * argv[])
500{
501    double backlight;
502
503    switch (argc) {
504    case 0:
505  backlight = drv_RB_backlight(-1);
506  SetResult(&result, R_NUMBER, &backlight);
507  break;
508    case 1:
509  backlight = drv_RB_backlight(R2N(argv[0]));
510  SetResult(&result, R_NUMBER, &backlight);
511  break;
512    default:
513  error("%s::backlight(): wrong number of parameters", Name);
514  SetResult(&result, R_STRING, "");
515    }
516}
517
518
519
520/****************************************/
521/***        widget callbacks          ***/
522/****************************************/
523
524
525/* using drv_generic_text_draw(W) */
526/* using drv_generic_text_icon_draw(W) */
527/* using drv_generic_text_bar_draw(W) */
528
529
530/****************************************/
531/***        exported functions        ***/
532/****************************************/
533
534
535/* list models */
536int drv_RB_list(void)
537{
538    int i;
539
540    for (i = 0; Models[i].type != 0xff; i++) {
541  printf("%s ", Models[i].name);
542    }
543    return 0;
544}
545
546/* initialize driver & display */
547int drv_RB_init(const char *section, const int quiet)
548{
549    WIDGET_CLASS wc;
550    int asc255bug;
551    int ret;
552
553    /* display preferences */
554    XRES = 5;     /* pixel width of one char  */
555    YRES = 8;     /* pixel height of one char  */
556    CHARS = 8;      /* number of user-defineable characters */
557    CHAR0 = 0;      /* ASCII of first user-defineable char */
558    GOTO_COST = 2;    /* number of bytes a goto command requires */
559
560    /* real worker functions */
561    drv_generic_text_real_write = drv_RB_write;
562    drv_generic_text_real_defchar = drv_RB_defchar;
563
564
565    /* start display */
566    if ((ret = drv_RB_start(section, quiet)) != 0)
567  return ret;
568
569    /* initialize generic text driver */
570    if ((ret = drv_generic_text_init(section, Name)) != 0)
571  return ret;
572
573    /* initialize generic icon driver */
574    if ((ret = drv_generic_text_icon_init()) != 0)
575  return ret;
576
577    /* initialize generic bar driver */
578    if ((ret = drv_generic_text_bar_init(0)) != 0)
579  return ret;
580
581    /* add fixed chars to the bar driver */
582    /* most displays have a full block on ascii 255, but some have kind of  */
583    /* an 'inverted P'. If you specify 'asc255bug 1 in the config, this */
584    /* char will not be used, but rendered by the bar driver */
585    cfg_number(section, "asc255bug", 0, 0, 1, &asc255bug);
586    drv_generic_text_bar_add_segment(0, 0, 255, 32);  /* ASCII  32 = blank */
587    if (!asc255bug)
588  drv_generic_text_bar_add_segment(255, 255, 255, 255); /* ASCII 255 = block */
589
590    /* register text widget */
591    wc = Widget_Text;
592    wc.draw = drv_generic_text_draw;
593    widget_register(&wc);
594
595    /* register icon widget */
596    wc = Widget_Icon;
597    wc.draw = drv_generic_text_icon_draw;
598    widget_register(&wc);
599
600    /* register bar widget */
601    wc = Widget_Bar;
602    wc.draw = drv_generic_text_bar_draw;
603    widget_register(&wc);
604
605    /* register plugins */
606    AddFunction("LCD::backlight", -1, plugin_backlight);
607
608    return 0;
609}
610
611
612/* close driver & display */
613int drv_RB_quit(const int quiet)
614{
615
616    info("%s: shutting down.", Name);
617
618    drv_generic_text_quit();
619
620    /* clear *both* displays */
621    drv_RB_clear();
622
623    /* say goodbye... */
624    if (!quiet) {
625  drv_generic_text_greet("goodbye!", NULL);
626    }
627#ifdef RB_WITH_LEDS
628
629    close(sock_c);
630    free(sacl);     /*close network socket */
631
632#endif
633
634    return (0);
635}
636
637
638DRIVER drv_RouterBoard = {
639  name:Name,
640  list:drv_RB_list,
641  init:drv_RB_init,
642  quit:drv_RB_quit,
643};
644
645
646
647/*
648
649Simple example to send led status to port 3333
650#include <stdio.h>
651#include <arpa/inet.h>
652#include <errno.h>
653
654int send_packet (unsigned char leds)
655{
656    struct sockaddr_in *sas;
657    int sock;
658    char msg[20];
659    msg[0]=leds;
660    msg[1]=0;
661   
662    if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
663  fprintf(stderr, "Socket option failed.\n");
664  return -1;
665    }
666   
667    if (( sas = (struct sockaddr_in *) malloc(sizeof(struct sockaddr_in))) == NULL)
668            return -1 ;
669    memset( sas, 0, sizeof(struct sockaddr_in));
670    sas->sin_family = AF_INET;
671    sas->sin_port = htons(3333);
672    sas->sin_addr.s_addr = inet_addr("127.0.0.1");
673    if(sendto(sock,msg,6, 0, (struct sockaddr *) sas, sizeof(struct sockaddr_in)) > 0)
674      { free(sas);
675  return 1;
676       }  //sent ok to dest
677
678    free(sas);
679    return -1;  //Send failed
680}
681 
682int main ()
683{
684 send_packet(0x03);
685 return 0;
686}
687
688*/
Note: See TracBrowser for help on using the browser.