root/tags/0.10.0/drv_T6963.c

Revision 547, 15.5 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_T6963.c,v 1.16 2005/05/08 04:32:44 reinelt Exp $
2 *
3 * new style driver for T6963-based displays
4 *
5 * Copyright (C) 2003 Michael Reinelt <reinelt@eunet.at>
6 * Copyright (C) 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
7 *
8 * This file is part of LCD4Linux.
9 *
10 * LCD4Linux is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * LCD4Linux is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 *
25 * $Log: drv_T6963.c,v $
26 * Revision 1.16  2005/05/08 04:32:44  reinelt
27 * CodingStyle added and applied
28 *
29 * Revision 1.15  2005/05/05 08:36:12  reinelt
30 * changed SELECT to SLCTIN
31 *
32 * Revision 1.14  2005/01/18 06:30:23  reinelt
33 * added (C) to all copyright statements
34 *
35 * Revision 1.13  2004/12/22 20:24:02  reinelt
36 * T6963 fix for displays > 8 rows
37 *
38 * Revision 1.12  2004/06/26 12:04:59  reinelt
39 *
40 * uh-oh... the last CVS log message messed up things a lot...
41 *
42 * Revision 1.11  2004/06/26 09:27:21  reinelt
43 *
44 * added '-W' to CFLAGS
45 * changed all C++ comments to C ones
46 * cleaned up a lot of signed/unsigned mistakes
47 *
48 * Revision 1.10  2004/06/20 10:09:54  reinelt
49 *
50 * 'const'ified the whole source
51 *
52 * Revision 1.9  2004/06/17 06:23:39  reinelt
53 *
54 * hash handling rewritten to solve performance issues
55 *
56 * Revision 1.8  2004/06/09 06:40:29  reinelt
57 *
58 * splash screen for T6963 driver
59 *
60 * Revision 1.7  2004/06/06 06:51:59  reinelt
61 *
62 * do not display end splash screen if quiet=1
63 *
64 * Revision 1.6  2004/06/02 09:41:19  reinelt
65 *
66 * prepared support for startup splash screen
67 *
68 * Revision 1.5  2004/06/01 06:45:30  reinelt
69 *
70 * some Fixme's processed
71 * documented some code
72 *
73 * Revision 1.4  2004/02/24 05:55:04  reinelt
74 *
75 * X11 driver ported
76 *
77 * Revision 1.3  2004/02/22 17:35:41  reinelt
78 * some fixes for generic graphic driver and T6963
79 * removed ^M from plugin_imon (Nico, are you editing under Windows?)
80 *
81 * Revision 1.2  2004/02/18 06:39:20  reinelt
82 * T6963 driver for graphic displays finished
83 *
84 * Revision 1.1  2004/02/15 21:43:43  reinelt
85 * T6963 driver nearly finished
86 * framework for graphic displays done
87 * i2c_sensors patch from Xavier
88 * some more old generation files removed
89 *
90 */
91
92/*
93 *
94 * exported fuctions:
95 *
96 * struct DRIVER drv_T6963
97 *
98 */
99
100#include "config.h"
101
102#include <stdlib.h>
103#include <stdio.h>
104#include <string.h>
105#include <errno.h>
106#include <unistd.h>
107#include <termios.h>
108#include <fcntl.h>
109#include <sys/time.h>
110
111#include "debug.h"
112#include "cfg.h"
113#include "qprintf.h"
114#include "udelay.h"
115#include "plugin.h"
116#include "widget.h"
117#include "widget_text.h"
118#include "widget_icon.h"
119#include "widget_bar.h"
120#include "drv.h"
121#include "drv_generic_graphic.h"
122#include "drv_generic_parport.h"
123
124#ifdef WITH_DMALLOC
125#include <dmalloc.h>
126#endif
127
128static char Name[] = "T6963";
129static int Model;
130
131typedef struct {
132    int type;
133    char *name;
134} MODEL;
135
136static MODEL Models[] = {
137    {0x01, "generic"},
138    {0xff, "Unknown"}
139};
140
141
142static unsigned char SIGNAL_CE;
143static unsigned char SIGNAL_CD;
144static unsigned char SIGNAL_RD;
145static unsigned char SIGNAL_WR;
146
147unsigned char *Buffer1, *Buffer2;
148
149static int bug = 0;
150
151
152/****************************************/
153/***  hardware dependant functions    ***/
154/****************************************/
155
156/* perform normal status check */
157static void drv_T6_status1(void)
158{
159    int n;
160
161    /* turn off data line drivers */
162    drv_generic_parport_direction(1);
163
164    /* lower CE and RD */
165    drv_generic_parport_control(SIGNAL_CE | SIGNAL_RD, 0);
166
167    /* Access Time: 150 ns  */
168    ndelay(150);
169
170    /* wait for STA0=1 and STA1=1 */
171    n = 0;
172    do {
173  rep_nop();
174  if (++n > 1000) {
175      debug("hang in status1");
176      bug = 1;
177      break;
178  }
179    } while ((drv_generic_parport_read() & 0x03) != 0x03);
180
181    /* rise RD and CE */
182    drv_generic_parport_control(SIGNAL_RD | SIGNAL_CE, SIGNAL_RD | SIGNAL_CE);
183
184    /* Output Hold Time: 50 ns  */
185    ndelay(50);
186
187    /* turn on data line drivers */
188    drv_generic_parport_direction(0);
189}
190
191
192/* perform status check in "auto mode" */
193static void drv_T6_status2(void)
194{
195    int n;
196
197    /* turn off data line drivers */
198    drv_generic_parport_direction(1);
199
200    /* lower RD and CE */
201    drv_generic_parport_control(SIGNAL_RD | SIGNAL_CE, 0);
202
203    /* Access Time: 150 ns  */
204    ndelay(150);
205
206    /* wait for STA3=1 */
207    n = 0;
208    do {
209  rep_nop();
210  if (++n > 1000) {
211      debug("hang in status2");
212      bug = 1;
213      break;
214  }
215    } while ((drv_generic_parport_read() & 0x08) != 0x08);
216
217    /* rise RD and CE */
218    drv_generic_parport_control(SIGNAL_RD | SIGNAL_CE, SIGNAL_RD | SIGNAL_CE);
219
220    /* Output Hold Time: 50 ns  */
221    ndelay(50);
222
223    /* turn on data line drivers */
224    drv_generic_parport_direction(0);
225}
226
227
228static void drv_T6_write_cmd(const unsigned char cmd)
229{
230    /* wait until the T6963 is idle */
231    drv_T6_status1();
232
233    /* put data on DB1..DB8 */
234    drv_generic_parport_data(cmd);
235
236    /* lower WR and CE */
237    drv_generic_parport_control(SIGNAL_WR | SIGNAL_CE, 0);
238
239    /* Pulse width */
240    ndelay(80);
241
242    /* rise WR and CE */
243    drv_generic_parport_control(SIGNAL_WR | SIGNAL_CE, SIGNAL_WR | SIGNAL_CE);
244
245    /* Data Hold Time */
246    ndelay(40);
247}
248
249
250static void drv_T6_write_data(const unsigned char data)
251{
252    /* wait until the T6963 is idle */
253    drv_T6_status1();
254
255    /* put data on DB1..DB8 */
256    drv_generic_parport_data(data);
257
258    /* lower C/D */
259    drv_generic_parport_control(SIGNAL_CD, 0);
260
261    /* C/D Setup Time */
262    ndelay(20);
263
264    /* lower WR and CE */
265    drv_generic_parport_control(SIGNAL_WR | SIGNAL_CE, 0);
266
267    /* Pulse Width */
268    ndelay(80);
269
270    /* rise WR and CE */
271    drv_generic_parport_control(SIGNAL_WR | SIGNAL_CE, SIGNAL_WR | SIGNAL_CE);
272
273    /* Data Hold Time */
274    ndelay(40);
275
276    /* rise CD */
277    drv_generic_parport_control(SIGNAL_CD, SIGNAL_CD);
278}
279
280
281static void drv_T6_write_auto(const unsigned char data)
282{
283    /* wait until the T6963 is idle */
284    drv_T6_status2();
285
286    /* put data on DB1..DB8 */
287    drv_generic_parport_data(data);
288
289    /* lower C/D */
290    drv_generic_parport_control(SIGNAL_CD, 0);
291
292    /* C/D Setup Time */
293    ndelay(20);
294
295    /* lower WR and CE */
296    drv_generic_parport_control(SIGNAL_WR | SIGNAL_CE, 0);
297
298    /* Pulse Width */
299    ndelay(80);
300
301    /* rise WR and CE */
302    drv_generic_parport_control(SIGNAL_WR | SIGNAL_CE, SIGNAL_WR | SIGNAL_CE);
303
304    /* Data Hold Time */
305    ndelay(40);
306
307    /* rise CD */
308    drv_generic_parport_control(SIGNAL_CD, SIGNAL_CD);
309}
310
311
312#if 0       /* not used */
313static void drv_T6_send_byte(const unsigned char cmd, const unsigned char data)
314{
315    drv_T6_write_data(data);
316    drv_T6_write_cmd(cmd);
317}
318#endif
319
320static void drv_T6_send_word(const unsigned char cmd, const unsigned short data)
321{
322    drv_T6_write_data(data & 0xff);
323    drv_T6_write_data(data >> 8);
324    drv_T6_write_cmd(cmd);
325}
326
327
328static void drv_T6_clear(const unsigned short addr, const int len)
329{
330    int i;
331
332    drv_T6_send_word(0x24, addr); /* Set Adress Pointer */
333    drv_T6_write_cmd(0xb0); /* Set Data Auto Write */
334    for (i = 0; i < len; i++) {
335  drv_T6_write_auto(0);
336  if (bug) {
337      bug = 0;
338      debug("bug occured at byte %d of %d", i, len);
339  }
340    }
341    drv_T6_status2();
342    drv_T6_write_cmd(0xb2); /* Auto Reset */
343}
344
345
346static void drv_T6_copy(const unsigned short addr, const unsigned char *data, const int len)
347{
348    int i;
349
350    drv_T6_send_word(0x24, 0x0200 + addr);  /* Set Adress Pointer */
351    drv_T6_write_cmd(0xb0); /* Set Data Auto Write */
352    for (i = 0; i < len; i++) {
353  drv_T6_write_auto(*(data++));
354  if (bug) {
355      bug = 0;
356      debug("bug occured at byte %d of %d, addr=%d", i, len, addr);
357  }
358    }
359    drv_T6_status2();
360    drv_T6_write_cmd(0xb2); /* Auto Reset */
361}
362
363
364static void drv_T6_blit(const int row, const int col, const int height, const int width)
365{
366    int i, j, e, m;
367    int r, c;
368
369    for (r = row; r < row + height; r++) {
370  for (c = col; c < col + width; c++) {
371      unsigned char mask = 1 << (XRES - 1 - c % XRES);
372      if (drv_generic_graphic_FB[r * LCOLS + c]) {
373    /* set bit */
374    Buffer1[(r * DCOLS + c) / XRES] |= mask;
375      } else {
376    /* clear bit */
377    Buffer1[(r * DCOLS + c) / XRES] &= ~mask;
378      }
379  }
380    }
381
382    /* upper half */
383
384    /* max address */
385    if (row + height - 1 < 64) {
386  m = ((row + height - 1) * DCOLS + col + width) / XRES;
387    } else {
388  m = (64 * DCOLS + col + width) / XRES;
389    }
390
391    for (i = (row * DCOLS + col) / XRES; i <= m; i++) {
392  if (Buffer1[i] == Buffer2[i])
393      continue;
394  for (j = i, e = 0; i <= m; i++) {
395      if (Buffer1[i] == Buffer2[i]) {
396    if (++e > 4)
397        break;
398      } else {
399    e = 0;
400      }
401  }
402  memcpy(Buffer2 + j, Buffer1 + j, i - j - e + 1);
403  drv_T6_copy(j, Buffer1 + j, i - j - e + 1);
404    }
405
406    /* lower half */
407
408    /* max address */
409    m = ((row + height - 1) * DCOLS + col + width) / XRES;
410
411    for (i = (64 * DCOLS + col) / XRES; i <= m; i++) {
412  if (Buffer1[i] == Buffer2[i])
413      continue;
414  for (j = i, e = 0; i <= m; i++) {
415      if (Buffer1[i] == Buffer2[i]) {
416    if (++e > 4)
417        break;
418      } else {
419    e = 0;
420      }
421  }
422  memcpy(Buffer2 + j, Buffer1 + j, i - j - e + 1);
423  drv_T6_copy(j, Buffer1 + j, i - j - e + 1);
424    }
425}
426
427
428static int drv_T6_start(const char *section)
429{
430    char *model, *s;
431    int rows, TROWS, TCOLS;
432
433    model = cfg_get(section, "Model", "generic");
434    if (model != NULL && *model != '\0') {
435  int i;
436  for (i = 0; Models[i].type != 0xff; i++) {
437      if (strcasecmp(Models[i].name, model) == 0)
438    break;
439  }
440  if (Models[i].type == 0xff) {
441      error("%s: %s.Model '%s' is unknown from %s", Name, section, model, cfg_source());
442      return -1;
443  }
444  Model = i;
445  info("%s: using model '%s'", Name, Models[Model].name);
446    } else {
447  error("%s: empty '%s.Model' entry from %s", Name, section, cfg_source());
448  return -1;
449    }
450
451    /* read display size from config */
452    s = cfg_get(section, "Size", NULL);
453    if (s == NULL || *s == '\0') {
454  error("%s: no '%s.Size' entry from %s", Name, section, cfg_source());
455  return -1;
456    }
457
458    DROWS = -1;
459    DCOLS = -1;
460    if (sscanf(s, "%dx%d", &DCOLS, &DROWS) != 2 || DCOLS < 1 || DROWS < 1) {
461  error("%s: bad Size '%s' from %s", Name, s, cfg_source());
462  return -1;
463    }
464
465    s = cfg_get(section, "Font", "6x8");
466    if (s == NULL || *s == '\0') {
467  error("%s: no '%s.Font' entry from %s", Name, section, cfg_source());
468  return -1;
469    }
470
471    XRES = -1;
472    YRES = -1;
473    if (sscanf(s, "%dx%d", &XRES, &YRES) != 2 || XRES < 1 || YRES < 1) {
474  error("%s: bad Font '%s' from %s", Name, s, cfg_source());
475  return -1;
476    }
477
478    /* Fixme: provider other fonts someday... */
479    if (XRES != 6 && YRES != 8) {
480  error("%s: bad Font '%s' from %s (only 6x8 at the moment)", Name, s, cfg_source());
481  return -1;
482    }
483
484    TROWS = DROWS / YRES; /* text rows */
485    TCOLS = DCOLS / XRES; /* text cols */
486
487    Buffer1 = malloc(TCOLS * DROWS);
488    if (Buffer1 == NULL) {
489  error("%s: framebuffer #1 could not be allocated: malloc() failed", Name);
490  return -1;
491    }
492
493    debug("malloc buffer 2 (%d*%d)=%d", TCOLS, DROWS, TCOLS * DROWS);
494    Buffer2 = malloc(TCOLS * DROWS);
495    if (Buffer2 == NULL) {
496  error("%s: framebuffer #2 could not be allocated: malloc() failed", Name);
497  return -1;
498    }
499
500    memset(Buffer1, 0, TCOLS * DROWS * sizeof(*Buffer1));
501    memset(Buffer2, 0, TCOLS * DROWS * sizeof(*Buffer2));
502
503    if (drv_generic_parport_open(section, Name) != 0) {
504  error("%s: could not initialize parallel port!", Name);
505  return -1;
506    }
507
508    if ((SIGNAL_CE = drv_generic_parport_wire_ctrl("CE", "STROBE")) == 0xff)
509  return -1;
510    if ((SIGNAL_CD = drv_generic_parport_wire_ctrl("CD", "SLCTIN")) == 0xff)
511  return -1;
512    if ((SIGNAL_RD = drv_generic_parport_wire_ctrl("RD", "AUTOFD")) == 0xff)
513  return -1;
514    if ((SIGNAL_WR = drv_generic_parport_wire_ctrl("WR", "INIT")) == 0xff)
515  return -1;
516
517    /* rise CE, CD, RD and WR */
518    drv_generic_parport_control(SIGNAL_CE | SIGNAL_CD | SIGNAL_RD | SIGNAL_WR, SIGNAL_CE | SIGNAL_CD | SIGNAL_RD | SIGNAL_WR);
519    /* set direction: write */
520    drv_generic_parport_direction(0);
521
522
523    /* initialize display */
524
525    drv_T6_send_word(0x40, 0x0000); /* Set Text Home Address */
526    drv_T6_send_word(0x41, TCOLS);  /* Set Text Area */
527
528    drv_T6_send_word(0x42, 0x0200); /* Set Graphic Home Address */
529    drv_T6_send_word(0x43, TCOLS);  /* Set Graphic Area */
530
531    drv_T6_write_cmd(0x80); /* Mode Set: OR mode, Internal CG RAM mode */
532    drv_T6_send_word(0x22, 0x0002); /* Set Offset Register */
533    drv_T6_write_cmd(0x98); /* Set Display Mode: Curser off, Text off, Graphics on */
534    drv_T6_write_cmd(0xa0); /* Set Cursor Pattern: 1 line cursor */
535    drv_T6_send_word(0x21, 0x0000); /* Set Cursor Pointer to (0,0) */
536
537
538    /* clear display */
539
540    /* upper half */
541    rows = TROWS > 8 ? 8 : TROWS;
542    drv_T6_clear(0x0000, TCOLS * rows); /* clear text area  */
543    drv_T6_clear(0x0200, TCOLS * rows * 8); /* clear graphic area */
544
545    /* lower half */
546    if (TROWS > 8) {
547  rows = TROWS - 8;
548  drv_T6_clear(0x8000, TCOLS * rows); /* clear text area #2 */
549  drv_T6_clear(0x8200, TCOLS * rows * 8); /* clear graphic area #2 */
550    }
551
552    return 0;
553}
554
555
556/****************************************/
557/***            plugins               ***/
558/****************************************/
559
560/* none at the moment... */
561
562
563/****************************************/
564/***        widget callbacks          ***/
565/****************************************/
566
567
568/* using drv_generic_graphic_draw(W) */
569/* using drv_generic_graphic_icon_draw(W) */
570/* using drv_generic_graphic_bar_draw(W) */
571
572
573/****************************************/
574/***        exported functions        ***/
575/****************************************/
576
577
578/* list models */
579int drv_T6_list(void)
580{
581    int i;
582
583    for (i = 0; Models[i].type != 0xff; i++) {
584  printf("%s ", Models[i].name);
585    }
586    return 0;
587}
588
589
590/* initialize driver & display */
591int drv_T6_init(const char *section, const int quiet)
592{
593    WIDGET_CLASS wc;
594    int ret;
595
596    /* real worker functions */
597    drv_generic_graphic_real_blit = drv_T6_blit;
598
599    /* start display */
600    if ((ret = drv_T6_start(section)) != 0)
601  return ret;
602
603    /* initialize generic graphic driver */
604    if ((ret = drv_generic_graphic_init(section, Name)) != 0)
605  return ret;
606
607    if (!quiet) {
608  char buffer[40];
609  qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, DCOLS, DROWS);
610  if (drv_generic_graphic_greet(buffer, NULL)) {
611      sleep(3);
612      drv_generic_graphic_clear();
613  }
614    }
615
616    /* register text widget */
617    wc = Widget_Text;
618    wc.draw = drv_generic_graphic_draw;
619    widget_register(&wc);
620
621    /* register icon widget */
622    wc = Widget_Icon;
623    wc.draw = drv_generic_graphic_icon_draw;
624    widget_register(&wc);
625
626    /* register bar widget */
627    wc = Widget_Bar;
628    wc.draw = drv_generic_graphic_bar_draw;
629    widget_register(&wc);
630
631    /* register plugins */
632    /* none at the moment... */
633
634
635    return 0;
636}
637
638
639/* close driver & display */
640int drv_T6_quit(const int quiet)
641{
642
643    info("%s: shutting down.", Name);
644
645    drv_generic_graphic_clear();
646
647    if (!quiet) {
648  drv_generic_graphic_greet("goodbye!", NULL);
649    }
650
651    drv_generic_graphic_quit();
652    drv_generic_parport_close();
653
654    if (Buffer1) {
655  free(Buffer1);
656  Buffer1 = NULL;
657    }
658
659    if (Buffer2) {
660  free(Buffer2);
661  Buffer2 = NULL;
662    }
663
664    return (0);
665}
666
667
668DRIVER drv_T6963 = {
669  name:Name,
670  list:drv_T6_list,
671  init:drv_T6_init,
672  quit:drv_T6_quit,
673};
Note: See TracBrowser for help on using the browser.