1 //////////////////////////////////////////////////////////////////////////
2 // This is a driver for 122x32 pixel graphic displays based on the //
3 // SED1520 Controller connected to the parallel port. Check //
4 // http://www.usblcd.de/lcdproc/ for where to buy //
5 // and how to build the hardware. This Controller has no built in //
6 // character generator. Therefore all fonts and pixels are generated //
9 // This driver is based on drv_base.c and hd44780.c. //
10 // The HD44780 font in sed1520fm.c was shamelessly stolen from //
11 // Michael Reinelt / lcd4linux and is (C) 2000 by him. //
12 // The rest of fontmap.c and this driver is //
14 // Moved the delay timing code by Charles Steinkuehler to timing.h. //
15 // Guillaume Filion <gfk@logidac.com>, December 2001 //
17 // (C) 2001 Robin Adams ( robin@adams-online.de ) //
19 // This driver is released under the GPL. See file COPYING in this //
20 // package for further details. //
21 //////////////////////////////////////////////////////////////////////////
29 #include <sys/errno.h>
33 #define uPause timing_uPause
35 #include "sed1520fm.h"
43 # define DEFAULT_PORT 0x378
49 #define PIXELWIDTH 122
50 #define PIXELHEIGHT 32
52 #define WIDTH ((int) (PIXELWIDTH / CELLWIDTH)) /* 20 */
53 #define HEIGHT ((int) (PIXELHEIGHT / CELLHEIGHT)) /* 4 */
61 #include "shared/str.h"
67 typedef struct driver_private_data
{
70 unsigned char *framebuf
;
74 // Vars for the server core
75 MODULE_EXPORT
char *api_version
= API_VERSION
;
76 MODULE_EXPORT
int stay_in_foreground
= 0;
77 MODULE_EXPORT
int supports_multiple
= 0;
78 MODULE_EXPORT
char *symbol_prefix
= "sed1520_";
80 /////////////////////////////////////////////////////////////////
81 // writes command value to one or both sed1520 selected by chip
84 writecommand (unsigned int port
, int value
, int chip
)
86 port_out(port
, value
);
87 port_out(port
+ 2, WR
+ CS1
- (chip
& CS1
) + (chip
& CS2
));
88 port_out(port
+ 2, CS1
- (chip
& CS1
) + (chip
& CS2
));
90 port_out(port
+ 2, WR
+ CS1
- (chip
& CS1
) + (chip
& CS2
));
94 /////////////////////////////////////////////////////////////////
95 // writes data value to one or both sed 1520 selected by chip
98 writedata (unsigned int port
, int value
, int chip
)
100 port_out(port
, value
);
101 port_out(port
+ 2, A0
+ WR
+ CS1
- (chip
& CS1
) + (chip
& CS2
));
102 port_out(port
+ 2, A0
+ CS1
- (chip
& CS1
) + (chip
& CS2
));
104 port_out(port
+ 2, A0
+ WR
+ CS1
- (chip
& CS1
) + (chip
& CS2
));
108 /////////////////////////////////////////////////////////////////
109 // selects a page (=row) on both sed1520s
112 selectpage (unsigned int port
, int page
)
114 writecommand(port
, 0xB8 + (page
& 0x03), CS1
+ CS2
);
117 /////////////////////////////////////////////////////////////////
118 // selects a column on the sed1520s specified by chip
121 selectcolumn (unsigned int port
, int column
, int chip
)
123 writecommand(port
, (column
& 0x7F), chip
);
126 /////////////////////////////////////////////////////////////////
127 // draws char z from fontmap to the framebuffer at position
128 // x,y. These are zero-based textmode positions.
129 // The Fontmap is stored in rows while the framebuffer is stored
130 // in columns, so we need a little conversion.
133 drawchar2fb (unsigned char *framebuf
, int x
, int y
, unsigned char z
)
137 if ((x
< 0) || (x
>= WIDTH
) || (y
< 0) || (y
>= HEIGHT
))
140 for (i
= CELLWIDTH
; i
> 0; i
--) {
143 for (j
= 0; j
< CELLHEIGHT
; j
++)
144 k
|= ((fontmap
[(int) z
][j
] >> (i
-1)) & 0x01) << j
;
146 framebuf
[(y
* PIXELWIDTH
) + (x
* CELLWIDTH
) + (CELLWIDTH
- i
)] = k
;
150 /////////////////////////////////////////////////////////////////
151 // This initialises the stuff. We support supplying port as
152 // a command line argument.
155 sed1520_init (Driver
*drvthis
)
159 /* Allocate and store private data */
160 p
= (PrivateData
*) calloc(1, sizeof(PrivateData
));
163 if (drvthis
->store_private_ptr(drvthis
, p
))
167 /* Read config file */
169 /* What port to use */
170 p
->port
= drvthis
->config_get_int(drvthis
->name
, "Port", 0, DEFAULT_PORT
);
172 /* End of config file parsing */
174 if (timing_init() == -1) {
175 report(RPT_ERR
, "%s: timing_init() failed (%s)", drvthis
->name
, strerror(errno
));
179 // Allocate our framebuffer
180 p
->framebuf
= (unsigned char *) calloc(PIXELWIDTH
* HEIGHT
, sizeof(unsigned char));
181 if (p
->framebuf
== NULL
) {
182 report(RPT_ERR
, "%s: unable to allocate framebuffer", drvthis
->name
);
188 memset(p
->framebuf
, '\0', PIXELWIDTH
* HEIGHT
);
190 // Initialize the Port and the sed1520s
191 if (port_access(p
->port
) || port_access(p
->port
+2)) {
192 report(RPT_ERR
, "%s: unable to access port 0x%03X", drvthis
->name
, p
->port
);
197 port_out(p
->port
+2, WR
+ CS2
);
198 writecommand(p
->port
, 0xE2, CS1
+ CS2
);
199 writecommand(p
->port
, 0xAF, CS1
+ CS2
);
200 writecommand(p
->port
, 0xC0, CS1
+ CS2
);
201 selectpage(p
->port
, 3);
203 report(RPT_DEBUG
, "%s: init() done", drvthis
->name
);
208 /////////////////////////////////////////////////////////////////
209 // Frees the frambuffer and exits the driver.
212 sed1520_close (Driver
*drvthis
)
214 PrivateData
*p
= drvthis
->private_data
;
217 if (p
->framebuf
!= NULL
)
222 drvthis
->store_private_ptr(drvthis
, NULL
);
225 /////////////////////////////////////////////////////////////////
226 // Returns the display width
229 sed1520_width (Driver
*drvthis
)
231 //PrivateData *p = drvthis->private_data;
235 /////////////////////////////////////////////////////////////////
236 // Returns the display height
239 sed1520_height (Driver
*drvthis
)
241 //PrivateData *p = drvthis->private_data;
245 /////////////////////////////////////////////////////////////////
246 // Returns the display width
249 sed1520_cellwidth (Driver
*drvthis
)
251 //PrivateData *p = drvthis->private_data;
255 /////////////////////////////////////////////////////////////////
256 // Returns the display height
259 sed1520_cellheight (Driver
*drvthis
)
261 //PrivateData *p = drvthis->private_data;
265 /////////////////////////////////////////////////////////////////
266 // Clears the LCD screen
269 sed1520_clear (Driver
*drvthis
)
271 PrivateData
*p
= drvthis
->private_data
;
273 memset(p
->framebuf
, '\0', PIXELWIDTH
* HEIGHT
);
276 /////////////////////////////////////////////////////////////////
278 // Flushes all output to the lcd...
281 sed1520_flush (Driver
*drvthis
)
283 PrivateData
*p
= drvthis
->private_data
;
286 for (i
= 0; i
< HEIGHT
; i
++) {
287 selectpage(p
->port
, i
);
289 selectcolumn(p
->port
, 0, CS2
) ;
290 for (j
= 0; j
< PIXELWIDTH
/2; j
++)
291 writedata(p
->port
, p
->framebuf
[j
+ (i
* PIXELWIDTH
)], CS2
);
293 selectcolumn(p
->port
, 0, CS1
) ;
294 for (j
= PIXELWIDTH
/2; j
< PIXELWIDTH
; j
++)
295 writedata(p
->port
, p
->framebuf
[j
+ (i
* PIXELWIDTH
)], CS1
);
299 /////////////////////////////////////////////////////////////////
300 // Prints a string on the lc display, at position (x,y). The
301 // upper-left is (1,1), and the lower right should be (20,4).
304 sed1520_string (Driver
*drvthis
, int x
, int y
, const char string
[])
306 PrivateData
*p
= drvthis
->private_data
;
309 x
--; // Convert 1-based coords to 0-based
312 for (i
= 0; string
[i
] != '\0'; i
++)
313 drawchar2fb(p
->framebuf
, x
+ i
, y
, string
[i
]);
316 /////////////////////////////////////////////////////////////////
317 // Writes char c at position x,y into the framebuffer.
318 // x and y are 1-based textmode coordinates.
321 sed1520_chr (Driver
*drvthis
, int x
, int y
, char c
)
323 PrivateData
*p
= drvthis
->private_data
;
327 drawchar2fb(p
->framebuf
, x
, y
, c
);
330 /////////////////////////////////////////////////////////////////
331 // This function draws a number num into the last 3 rows of the
332 // framebuffer at 1-based position x. It should draw a 4-row font,
333 // but methinks this would look a little stretched. When
334 // num=10 a colon is drawn.
335 // FIXME: make big numbers use less memory
338 sed1520_num (Driver
*drvthis
, int x
, int num
)
340 PrivateData
*p
= drvthis
->private_data
;
344 // return on illegal char or illegal position
345 if ((x
>= WIDTH
) || (num
< 0) || (num
> 10))
348 if (num
== 10) { // colon
349 for (z
= 0; z
< 3; z
++) { // Zeilen a 8 Punkte
350 for (c
= 0; c
< 6; c
++) { // 6 columns
352 for (i
= 0; i
< 8; i
++) { // 8 bits aus zeilen
354 if (*(fontbigdp
[(z
* 8) + i
] + c
) == '.')
357 if ((x
* CELLWIDTH
+ c
>= 0) && (x
* CELLWIDTH
+ c
< PIXELWIDTH
))
358 p
->framebuf
[((z
+ 1) * PIXELWIDTH
) + (x
* CELLWIDTH
) + c
] = s
;
362 else { // digits 0 - 9
363 for (z
= 0; z
< 3; z
++) { // Zeilen a 8 Punkte
364 for (c
= 0; c
< 18; c
++) { // 18 columns
366 for (i
= 0; i
< 8; i
++) { // 8 bits aus zeilen
368 if (*(fontbignum
[num
][z
* 8 + i
] + c
) == '.')
371 if ((x
* CELLWIDTH
+ c
>= 0) && (x
* CELLWIDTH
+ c
< PIXELWIDTH
))
372 p
->framebuf
[((z
+ 1) * PIXELWIDTH
) + (x
* CELLWIDTH
) + c
] = s
;
379 /////////////////////////////////////////////////////////////////
380 // Changes the font of character n to a pattern given by *dat.
381 // HD44780 Controllers only posses 8 programmable chars. But
382 // we store the fontmap completely in RAM, so every character
383 // can be altered. !Important: Characters have to be redrawn
384 // by drawchar2fb() to show their new shape. Because we use
385 // a non-standard 6x8 font a *dat not calculated from
386 // width and height will fail.
389 sed1520_set_char (Driver
*drvthis
, int n
, char *dat
)
391 //PrivateData *p = drvthis->private_data;
394 if (n
< 0 || n
> 255)
399 for (row
= 0; row
< CELLHEIGHT
; row
++) {
402 for (col
= 0; col
< CELLWIDTH
; col
++)
403 i
= (i
<< 1) | (dat
[(row
* CELLWIDTH
) + col
] > 0);
410 /////////////////////////////////////////////////////////////////
411 // Draws a vertical from the bottom up to the last 3 rows of the
412 // framebuffer at 1-based position x. len is given in pixels.
415 sed1520_old_vbar (Driver
*drvthis
, int x
, int len
)
417 PrivateData
*p
= drvthis
->private_data
;
422 for (j
= 0; j
< 3; j
++) {
424 for (i
= 0; i
< CELLHEIGHT
; i
++) {
426 k
|= (1 << (CELLHEIGHT
-1 - i
));
429 p
->framebuf
[((3 - j
) * PIXELWIDTH
) + (x
* CELLWIDTH
) + 0] = 0;
430 p
->framebuf
[((3 - j
) * PIXELWIDTH
) + (x
* CELLWIDTH
) + 1] = 0;
431 p
->framebuf
[((3 - j
) * PIXELWIDTH
) + (x
* CELLWIDTH
) + 2] = k
;
432 p
->framebuf
[((3 - j
) * PIXELWIDTH
) + (x
* CELLWIDTH
) + 3] = k
;
433 p
->framebuf
[((3 - j
) * PIXELWIDTH
) + (x
* CELLWIDTH
) + 4] = k
;
434 p
->framebuf
[((3 - j
) * PIXELWIDTH
) + (x
* CELLWIDTH
) + 5] = 0;
440 /////////////////////////////////////////////////////////////////
441 // Draws a horizontal bar from left to right at 1-based position
442 // x,y into the framebuffer. len is given in pixels.
445 sed1520_old_hbar (Driver
*drvthis
, int x
, int y
, int len
)
447 PrivateData
*p
= drvthis
->private_data
;
453 if ((y
< 0) || (y
>= HEIGHT
) || (x
< 0) || (len
< 0) || ((x
+ (len
/ CELLWIDTH
)) >= WIDTH
))
456 for (i
= 0; i
< len
; i
++)
457 p
->framebuf
[(y
* PIXELWIDTH
) + (x
* CELLWIDTH
) + i
] = 0x3C; // set low 6 bits
460 /////////////////////////////////////////////////////////////////
461 // Reprogrammes character dest to contain an icon given by
462 // which. Calls set_char() to do this.
465 sed1520_icon (Driver
*drvthis
, int x
, int y
, int icon
)
467 //PrivateData *p = drvthis->private_data;
468 static char heart_open
[] = {
478 static char heart_filled
[] = {
489 case ICON_BLOCK_FILLED
:
490 sed1520_chr(drvthis
, x
, y
, 255);
492 case ICON_HEART_FILLED
:
493 sed1520_set_char(drvthis
, 0, heart_filled
);
494 sed1520_chr(drvthis
, x
, y
, 0);
496 case ICON_HEART_OPEN
:
497 sed1520_set_char(drvthis
, 0, heart_open
);
498 sed1520_chr(drvthis
, x
, y
, 0);