Base: LCDproc 0.5.2
[lcdproc-de200c.git] / server / drivers / stv5730.c
blob71541916cbd7388eb3eabaa11f419766fc2e4e9e
1 //////////////////////////////////////////////////////////////////////////
2 // This is a driver for the STV5730A on-screen display chip in con- //
3 // junction with a parallel port interface. Check //
4 // http://www.usblcd.de/lcdproc/ for where to buy iand how to build //
5 // the hardware. //
6 // The STV3730 displays 11 rows with 28 characters. The characters are //
7 // fixed and can not be reprogrammed. Luckily the chraracter set con- //
8 // tains a heartbeat icon and some characters that can be used as //
9 // hbars / vbars. //
10 // //
11 // Moved the delay timing code by Charles Steinkuehler to timing.h. //
12 // Guillaume Filion <gfk@logidac.com>, December 2001 //
13 // //
14 // (C) 2001 Robin Adams ( robin@adams-online.de ) //
15 // //
16 // This driver is released under the GPL. See file COPYING in this //
17 // package for further details. //
18 //////////////////////////////////////////////////////////////////////////
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <termios.h>
24 #include <fcntl.h>
25 #include <string.h>
26 #include <sys/errno.h>
27 //#include <sys/io.h>
28 #include <time.h>
29 #include "port.h"
30 #include "timing.h"
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
36 #include "shared/str.h"
37 #include "lcd.h"
38 #include "stv5730.h"
39 #include "report.h"
42 #ifndef LPTPORT
43 #define LPTPORT 0x378
44 #endif
46 #define STV5730_TEST_O 0x01
47 #define STV5730_BAR 0x02
48 #define STV5730_CLK 0x04
49 #define STV5730_CSN 0x08
50 #define STV5730_DATA 0x10
52 #define STV5730_TEST_I 0x40
53 #define STV5730_MUTE 0x80
55 // If it doesn't work try increasing this value
56 #define IODELAY 400
59 // Change that to NTSC if you are from the US...
60 #define PAL
63 #define STV5730_HGT 11
64 #define STV5730_WID 28
65 #define STV5730_ATTRIB 0x800
67 #define STV5730_REG_ZOOM 0xCC
68 #define STV5730_REG_COLOR 0xCD
69 #define STV5730_REG_CONTROL 0xCE
70 #define STV5730_REG_POSITION 0xCF
71 #define STV5730_REG_MODE 0xD0
73 // Choose Colors: FLINE: First line text color, TEXT: Text color, CBACK: Character Background Color
74 // CBORD: Character Border Color, SBACK: Screen Background color
75 // 0:Black, 1: Blue, 2:Green, 3: Cyan, 4: Red, 5: Magenta, 6: Yellow, 7: White
76 #define STV5730_COL_FLINE 4
77 #define STV5730_COL_TEXT 1
78 #define STV5730_COL_CBACK 3
79 #define STV5730_COL_CBORD 0
80 #define STV5730_COL_SBACK 2
83 typedef struct driver_private_data {
84 unsigned int port;
85 unsigned int charattrib;
86 unsigned int flags;
87 char *framebuf;
88 } PrivateData;
91 // Vars for the server core
92 MODULE_EXPORT char *api_version = API_VERSION;
93 MODULE_EXPORT int stay_in_foreground = 0;
94 MODULE_EXPORT int supports_multiple = 0;
95 MODULE_EXPORT char *symbol_prefix = "stv5730_";
98 // Translation map ascii->stv5730 charset
99 unsigned char stv5730_to_ascii[256] =
100 { 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
101 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
102 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
103 0x0B, 0x0B, 0x0B, 0x0B,
104 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
105 0x27, 0x0B, 0x27, 0x28,
106 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x26, 0x26,
107 0x62, 0x78, 0x61, 0x70,
108 0x6c, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
109 0x17, 0x18, 0x19, 0x1A,
110 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x0B,
111 0x0B, 0x0B, 0x0B, 0x72,
112 0x0B, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34,
113 0x35, 0x36, 0x37, 0x38,
114 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x6E,
115 0x6C, 0x71, 0x79, 0x7F,
116 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
117 0x0B, 0x0B, 0x0B, 0x0B,
118 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
119 0x0B, 0x0B, 0x0B, 0x0B,
120 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
121 0x0B, 0x0B, 0x0B, 0x0B,
122 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
123 0x0B, 0x0B, 0x0B, 0x0B,
124 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
125 0x0B, 0x0B, 0x0B, 0x0B,
126 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
127 0x0B, 0x0B, 0x0B, 0x0B,
128 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
129 0x0B, 0x0B, 0x0B, 0x0B,
130 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B,
131 0x0B, 0x0B, 0x0B, 0x77
136 //static void stv5730_upause(int delayCalls);
137 #define stv5730_upause timing_uPause
139 /////////////////////////////////////////////////////////////////
140 // This function returns true if a powered and working STV5730
141 // hardware is present at p->port
143 static int
144 stv5730_detect (unsigned int port)
146 int i;
148 for (i = 0; i < 10; i++) {
149 port_out(port, STV5730_TEST_O);
150 stv5730_upause(IODELAY);
151 if ((port_in(port + 1) & STV5730_TEST_I) == 0)
152 return -1;
153 port_out(port, 0);
154 stv5730_upause(IODELAY);
155 if ((port_in(port + 1) & STV5730_TEST_I) != 0)
156 return -1;
158 return 0;
161 /////////////////////////////////////////////////////////////////
162 // returns 0 if a valid video signal is connected to the video
163 // input
164 static int
165 stv5730_is_mute (unsigned int port)
167 stv5730_upause(IODELAY);
168 return ((port_in(port + 1) & STV5730_MUTE) ? 0 : 1);
171 /////////////////////////////////////////////////////////////////
172 // stv5730_write16bit, stv5730_write8bit, stv5730_write0bit
173 // this family of functions write commands or data to the stv5730
174 // 8 bit writes repeat the high byte, 0 byte writes repeat the last
175 // written word
177 static void
178 stv5730_write16bit (unsigned int port, unsigned int flags, unsigned int value)
180 int i;
182 stv5730_upause(IODELAY);
183 port_out(port, STV5730_CSN + flags);
184 stv5730_upause(IODELAY);
185 port_out(port, STV5730_CSN + STV5730_CLK + flags);
186 stv5730_upause(IODELAY);
187 port_out(port, STV5730_CLK + flags);
189 for (i = 15; i >= 0; i--) {
190 char databit = ((value & (1 << i)) != 0) ? STV5730_DATA : 0;
192 port_out(port, databit + STV5730_CLK + flags);
193 stv5730_upause(IODELAY);
194 port_out(port, databit + flags);
195 stv5730_upause(IODELAY);
196 port_out(port, databit + STV5730_CLK + flags);
197 stv5730_upause(IODELAY);
200 stv5730_upause(IODELAY);
201 port_out(port, STV5730_CSN + STV5730_CLK + flags);
202 stv5730_upause(IODELAY);
203 port_out(port, STV5730_CSN + flags);
204 stv5730_upause(IODELAY);
207 static void
208 stv5730_write8bit (unsigned int port, unsigned int flags, unsigned int value)
210 int i;
212 stv5730_upause(IODELAY);
213 port_out(port, STV5730_CSN + flags);
214 stv5730_upause(IODELAY);
215 port_out(port, STV5730_CSN + STV5730_CLK + flags);
216 stv5730_upause(IODELAY);
217 port_out(port, STV5730_CLK + flags);
219 for (i = 7; i >= 0; i--) {
220 char databit = ((value & (1 << i)) != 0) ? STV5730_DATA : 0;
222 port_out(port, databit + STV5730_CLK + flags);
223 stv5730_upause(IODELAY);
224 port_out(port, databit + flags);
225 stv5730_upause(IODELAY);
226 port_out(port, databit + STV5730_CLK + flags);
227 stv5730_upause(IODELAY);
230 stv5730_upause(IODELAY);
231 port_out(port, STV5730_CSN + STV5730_CLK + flags);
232 stv5730_upause(IODELAY);
233 port_out(port, STV5730_CSN + flags);
236 static void
237 stv5730_write0bit (unsigned int port, unsigned int flags)
239 stv5730_upause(IODELAY);
240 port_out(port, STV5730_CSN + flags);
241 stv5730_upause(IODELAY);
242 port_out(port, STV5730_CSN + STV5730_CLK + flags);
243 stv5730_upause(IODELAY);
244 port_out(port, STV5730_CLK + flags);
246 stv5730_upause(IODELAY);
247 port_out(port, STV5730_CSN + STV5730_CLK + flags);
248 stv5730_upause(IODELAY);
249 port_out(port, STV5730_CSN + flags);
253 /////////////////////////////////////////////////////////////////
254 // sets the memory pointer inside the stv5730 to the position
255 // row, col.
256 static void
257 stv5730_locate (unsigned int port, unsigned int flags, int row, int col)
259 if (row < 0 || row >= STV5730_HGT || col < 0 || col >= STV5730_WID)
260 return;
262 stv5730_write16bit(port, flags, (row << 8) + col);
265 /////////////////////////////////////////////////////////////////
266 // draws char z from fontmap to the framebuffer at position
267 // x,y. These are zero-based textmode positions.
268 // We need a conversion map to translate from ascii to the
269 // non-standard STV5730 charset.
271 static void
272 stv5730_drawchar2fb (Driver *drvthis, int x, int y, unsigned char z)
274 PrivateData *p = drvthis->private_data;
276 if ((x >= 0) && (x < STV5730_WID) && (y >= 0) && (y < STV5730_HGT))
277 p->framebuf[(y * STV5730_WID) + x] = stv5730_to_ascii[(unsigned int) z];
280 /////////////////////////////////////////////////////////////////
281 // This initialises the stuff. We support supplying port as
282 // a command line argument.
284 MODULE_EXPORT int
285 stv5730_init (Driver *drvthis)
287 PrivateData *p;
288 int i;
290 /* Allocate and store private data */
291 p = (PrivateData *) calloc(1, sizeof(PrivateData));
292 if (p == NULL)
293 return -1;
294 if (drvthis->store_private_ptr(drvthis, p))
295 return -1;
297 /* initialize private data */
298 p->port = LPTPORT;
299 p->charattrib = STV5730_ATTRIB;
300 p->flags = 0;
301 p->framebuf = NULL;
303 /* Read config file */
305 /* What port to use */
306 p->port = drvthis->config_get_int(drvthis->name, "Port", 0, LPTPORT);
308 /* End of config file parsing */
310 if (timing_init() == -1) {
311 report(RPT_ERR, "%s: timing_init() failed (%s)", drvthis->name, strerror(errno));
312 return -1;
315 // Initialize the Port and the stv5730
316 if (port_access(p->port) || port_access(p->port + 1)) {
317 report(RPT_ERR,
318 "%s: cannot get IO-permission for 0x%03X! Are we running as root?",
319 drvthis->name, p->port);
320 return -1;
323 if (stv5730_detect(p->port)) {
324 report(RPT_ERR, "%s: no STV5730 hardware found at 0x%03X ",
325 drvthis->name, p->port);
326 return -1;
329 port_out(p->port, 0);
331 // Reset the STV5730
332 stv5730_write16bit(p->port, p->flags, 0x3000);
333 stv5730_write16bit(p->port, p->flags, 0x3000);
334 stv5730_write16bit(p->port, p->flags, 0x00db);
335 stv5730_write16bit(p->port, p->flags, 0x1000);
337 // Setup Mode + Control Register for video detection
338 stv5730_write16bit(p->port, p->flags, STV5730_REG_MODE);
339 stv5730_write16bit(p->port, p->flags, 0x1576);
341 stv5730_write16bit(p->port, p->flags, STV5730_REG_CONTROL);
342 stv5730_write16bit(p->port, p->flags, 0x1FF4);
344 report(RPT_INFO, "%s: detecting video signal: ", drvthis->name);
345 usleep (50000);
347 if (stv5730_is_mute(p->port)) {
348 report(RPT_INFO, "%s: no video signal found; using full page mode", drvthis->name);
349 // Setup Mode + Control for full page mode
350 p->charattrib = STV5730_ATTRIB;
351 stv5730_write16bit(p->port, p->flags, STV5730_REG_MODE);
352 stv5730_write16bit(p->port, p->flags, 0x15A6);
354 stv5730_write16bit(p->port, p->flags, STV5730_REG_CONTROL);
355 #ifdef PAL
356 stv5730_write16bit(p->port, p->flags, 0x1FD5);
357 #endif
358 #ifdef NTSC
359 stv5730_write16bit(p->port, p->flags, 0x1ED4);
360 #endif
363 else {
364 report(RPT_INFO, "%s: video signal found, using mixed mode (B&W)", drvthis->name);
365 // Setup Mode + Control for mixed mode, disable color
366 p->charattrib = 0;
367 stv5730_write16bit(p->port, p->flags, STV5730_REG_MODE);
368 stv5730_write16bit(p->port, p->flags, 0x1576);
370 stv5730_write16bit(p->port, p->flags, STV5730_REG_CONTROL);
371 #ifdef PAL
372 stv5730_write16bit(p->port, p->flags, 0x1DD4);
373 #endif
374 #ifdef NTSC
375 stv5730_write16bit(p->port, p->flags, 0x1CF4);
376 #endif
379 // Position Register
380 stv5730_write16bit(p->port, p->flags, STV5730_REG_POSITION);
381 stv5730_write16bit(p->port, p->flags, 0x1000 + 64 * 30 + 30);
383 // Color Register
384 stv5730_write16bit(p->port, p->flags, STV5730_REG_COLOR);
385 stv5730_write16bit(p->port, p->flags, 0x1000 + (STV5730_COL_SBACK << 9) +
386 (STV5730_COL_CBORD << 6) + STV5730_COL_CBACK);
388 // Zoom Register: Zoom first line
389 stv5730_write16bit(p->port, p->flags, STV5730_REG_ZOOM);
390 stv5730_write16bit(p->port, p->flags, 0x1000 + 4);
392 // Set the Row Attributes
393 for (i = 0; i <= 10; i++) {
394 stv5730_write16bit(p->port, p->flags, 0x00C0 + i);
395 stv5730_write16bit(p->port, p->flags, 0x10C0);
398 // Allocate our own framebuffer
399 p->framebuf = malloc(STV5730_WID * STV5730_HGT);
400 if (p->framebuf == NULL) {
401 report(RPT_ERR, "%s: unable to allocate framebuffer", drvthis->name);
402 stv5730_close(drvthis);
403 return -1;
406 // clear screen
407 memset(p->framebuf, 0, STV5730_WID * STV5730_HGT);
409 report(RPT_DEBUG, "%s: init() done", drvthis->name);
411 return 1;
414 /////////////////////////////////////////////////////////////////
415 // Frees the framebuffer and exits the driver.
417 MODULE_EXPORT void
418 stv5730_close (Driver *drvthis)
420 PrivateData *p = drvthis->private_data;
422 if (p != NULL) {
423 if (p->framebuf != NULL)
424 free(p->framebuf);
426 free(p);
428 drvthis->store_private_ptr(drvthis, NULL);
431 /////////////////////////////////////////////////////////////////
432 // Returns the display width
434 MODULE_EXPORT int
435 stv5730_width (Driver *drvthis)
437 return STV5730_WID;
440 /////////////////////////////////////////////////////////////////
441 // Returns the display height
443 MODULE_EXPORT int
444 stv5730_height (Driver *drvthis)
446 return STV5730_HGT;
449 /////////////////////////////////////////////////////////////////
450 // Returns the number of pixels a character is wide
452 MODULE_EXPORT int
453 stv5730_cellwidth (Driver *drvthis)
455 return 4;
458 /////////////////////////////////////////////////////////////////
459 // Returns the number of pixels a character is high
461 MODULE_EXPORT int
462 stv5730_cellheight (Driver *drvthis)
464 return 6;
466 // cellwidth and cellheight are only needed for old_vbar.
467 // Therefor these values are now hardcoded into these functions.
468 // When old_vbar is not used anymore, these two functions can be removed.
471 /////////////////////////////////////////////////////////////////
472 // Clears the screen
474 MODULE_EXPORT void
475 stv5730_clear (Driver *drvthis)
477 PrivateData *p = drvthis->private_data;
479 memset(p->framebuf, 0x0B, STV5730_WID * STV5730_HGT);
482 /////////////////////////////////////////////////////////////////
484 // Flushes all output to the lcd...
486 MODULE_EXPORT void
487 stv5730_flush (Driver *drvthis)
489 PrivateData *p = drvthis->private_data;
490 int i, j, atr;
492 stv5730_locate(p->port, p->flags, 0, 0);
494 for (i = 0; i < STV5730_HGT; i++) {
495 if (i == 0)
496 atr = (STV5730_COL_FLINE << 8);
497 else
498 atr = (STV5730_COL_TEXT << 8);
499 stv5730_write16bit(p->port, p->flags, 0x1000 + atr + p->framebuf[i * STV5730_WID] +
500 p->charattrib);
501 for (j = 1; j < STV5730_WID; j++) {
502 if (p->framebuf[j + (i * STV5730_WID) - 1] !=
503 p->framebuf[j + (i * STV5730_WID)])
504 stv5730_write8bit(p->port, p->flags, p->framebuf[j + (i * STV5730_WID)]);
505 else
506 stv5730_write0bit(p->port, p->flags);
511 /////////////////////////////////////////////////////////////////
512 // Prints a string on the screen, at position (x,y). The
513 // upper-left is (1,1), and the lower right should be (28,11).
515 MODULE_EXPORT void
516 stv5730_string (Driver *drvthis, int x, int y, const char string[])
518 //PrivateData *p = drvthis->private_data;
519 int i;
521 x--; // Convert 1-based coords to 0-based...
522 y--;
524 for (i = 0; string[i] != '\0'; i++)
525 stv5730_drawchar2fb(drvthis, x + i, y, string[i]);
528 /////////////////////////////////////////////////////////////////
529 // Writes char c at position x,y into the framebuffer.
530 // x and y are 1-based textmode coordinates.
532 MODULE_EXPORT void
533 stv5730_chr (Driver *drvthis, int x, int y, char c)
535 //PrivateData *p = drvthis->private_data;
537 y--;
538 x--;
539 stv5730_drawchar2fb(drvthis, x, y, c);
542 /////////////////////////////////////////////////////////////////
543 // This function draws ugly big numbers. We could use the zoom
544 // feature of the stv5730 if we'd know when big numbers start
545 // and stop.
546 MODULE_EXPORT void
547 stv5730_num (Driver *drvthis, int x, int num)
549 //PrivateData *p = drvthis->private_data;
550 int i, j;
552 x--;
554 if ((x >= STV5730_WID) || (num < 0) || (num > 10))
555 return;
557 for (j = 1; j < 10; j++) {
558 if (num != 10) {
559 for (i = 0; i < 3; i++)
560 stv5730_drawchar2fb(drvthis, x + i, j, '0' + num);
562 else {
563 stv5730_drawchar2fb(drvthis, x, j, ':');
568 /////////////////////////////////////////////////////////////////
569 // Draws a vertical bar from the bottom up to the last 7 rows of the
570 // framebuffer at 1-based position x. len is given in pixels.
572 MODULE_EXPORT void
573 stv5730_old_vbar (Driver *drvthis, int x, int len)
575 PrivateData *p = drvthis->private_data;
576 int i;
578 x--;
580 if (x < 0 || len < 0 || (len / 6) >= STV5730_WID)
581 return;
583 for (i = 0; i <= len; i += 6) {
584 if (len >= (i + 6)) /* 6 = cellheight */
585 p->framebuf[((10 - (i / 6)) * STV5730_WID) + x] = 0x77;
586 else
587 p->framebuf[((10 - (i / 6)) * STV5730_WID) + x] = 0x72 + (len % 6);
592 /////////////////////////////////////////////////////////////////
593 // Draws a horizontal bar from left to right at 1-based position
594 // x,y into the framebuffer. len is given in pixels.
595 // It uses the STV5730 'channel-tuning' chars(0x64-0x68) to do
596 // this.
597 MODULE_EXPORT void
598 stv5730_old_hbar (Driver *drvthis, int x, int y, int len)
600 PrivateData *p = drvthis->private_data;
601 int i;
603 x--;
604 y--;
606 if (y < 0 || y >= STV5730_HGT || x < 0 || len < 0
607 || (x + (len / 5)) >= STV5730_WID)
608 return;
610 for (i = 0; i <= len; i += 5) {
611 if (len >= (i + 4)) /* 4 = cellwidth */
612 p->framebuf[(y * STV5730_WID) + x + (i / 5)] = 0x64;
613 else
614 p->framebuf[(y * STV5730_WID) + x + (i / 5)] = 0x65 + (len % 5);
618 /////////////////////////////////////////////////////////////////
619 // Reprogrammes character dest to contain an icon given by
620 // which.
621 // The STV5730 has no programmable chars. The charset is very
622 // limited, it doesn't even contain a '%' char. But wait...
623 // It contains a heartbeat char ! :-)
624 MODULE_EXPORT void
625 stv5730_old_icon (Driver *drvthis, int which, char dest)
627 //PrivateData *p = drvthis->private_data;
629 switch (which) {
630 case 0: // 0:empty Heart
631 stv5730_to_ascii[(int) dest] = 0x71;
632 break;
633 case 1: // 1:Filled Heart
634 stv5730_to_ascii[(int) dest] = 0x0B;
635 break;
636 case 2: // 2:Ellipsis
637 stv5730_to_ascii[(int) dest] = 0x5F;
638 break;
639 default:
640 stv5730_to_ascii[(int) dest] = 0x0B;
641 break;