From 680891761e634700cb8653892119a66f44c8eb0e Mon Sep 17 00:00:00 2001 From: mmdolze Date: Mon, 3 Jan 2011 10:51:50 +0000 Subject: [PATCH] Analyze and document the t6963 driver: * Add Doxygen comments (also for internal functions, shortened for API). * Document initialization. * Remove some unused variables and defines. * Pass through indent. * Remove references to LCD pins from documentation and add some warning. --- docs/lcdproc-user/drivers/t6963.docbook | 138 +++--- server/drivers/t6963.c | 553 ++++++++++++++---------- server/drivers/t6963.h | 131 +++--- server/drivers/t6963_font.h | 29 +- 4 files changed, 470 insertions(+), 381 deletions(-) diff --git a/docs/lcdproc-user/drivers/t6963.docbook b/docs/lcdproc-user/drivers/t6963.docbook index 481ed50..583bfa9 100644 --- a/docs/lcdproc-user/drivers/t6963.docbook +++ b/docs/lcdproc-user/drivers/t6963.docbook @@ -7,46 +7,90 @@ T6963 chipset from Toshiba. Usually, this chipset is used on big character LCD displays that can often act as a screen. + +The driver uses the text mode of the chipset with a custom font loaded which +resembles the characters from Code Page 437. + + + +Only displays in 'Single Scan' configurations are supported. Displays configured +as 'Dual Scan' are currently not supported. Those use onboard memory differently. +Check the datasheet of your display! + + Connections + + + Displays using T6963 chipset come in a variety of pin-outs and power configurations. + They usually require negative voltage for contrast and some displays have + a negative voltage generator onboard. Therefore the wiring table below does + only list signal names, not LCD pins. Be sure to get the correct datasheet + for your display and identify the pins to use! + + + We do not give wiring examples for power, contrast, and other control lines. + You have to figure out this from your display's datasheet! + + + T6963 wiring schematic - + + + + + + - Parallel port - LCD + Parallel port + <-> + LCD + + + name + pin + name + pin - 1 (Strobe) - 5 (WR) + nSTRB + 1 + + /WR + * - 2-9 (Data) - 11-18 (Data) + D0-D7 + 2-9 + + DB0-DB7 + * - 14 (Autofeed) - 7 (CE) + nLF + 14 + + /CE + * - 16 (Init) - 8 (C/D) + INIT + 16 + + C/D + * - 17 (Slct) - 6 (RD) - - - 18 (GND) - 3 (GND) - - - +5V - 3 (LCD +) + nSEL + 17 + + /RD + * @@ -100,18 +144,31 @@ can be done by specifying "--enable-drivers=all" or by ECPlpt = ¶meters.yesdefno; - + + Is ECP mode on? [default: yes; legal: yes, no] - + + + Despite its name, this driver does not use ECP mode of parallel port. This + option turns bi-directional mode of the port on or off. Leave this on + unless you experience problems. + + graphic = ¶meters.yesnodef; - + + Use graphic? [default: no; legal: yes, no] - + + + Enables / disables drawing of the content of the graphic RAM. This is + currently a no-op as the driver does not make use of the graphic RAM. + + @@ -119,35 +176,4 @@ can be done by specifying "--enable-drivers=all" or by - -Running - - -Modify the LCDd.conf file before you run LCDd. In this config file are -detailed instructions on how to configure the T6963 driver. - - - -Then as usual, start LCDd with the correct config file: - - - -E.g. LCDd -c ./LCDd.conf - - - -If you want to override the driver selection in LCDd.conf then use: - - - -LCDd -c ./LCDd.conf -d T6963 - - - -If you use this, the T6963 driver will read the options from the config -file anyway. - - - - diff --git a/server/drivers/t6963.c b/server/drivers/t6963.c index 32554ec..d9e0d88 100644 --- a/server/drivers/t6963.c +++ b/server/drivers/t6963.c @@ -1,19 +1,33 @@ /** \file server/drivers/t6963.c - * LCDd \c t6963 driver for Toshiba T6963 based LCD displays. + * LCDd \c t6963 driver for Toshiba T6963 based LCD displays. The display is + * driven in text mode with a custom font loaded. + * + * Wiring (no pins for the display given. Check with your datasheet!) + * + *\verbatim + * Parallel: LCD: + * 1 (Strobe) ----------- /WR + * 2-9 (Data) ----------- DB0-DB7 + * 14 (Autofeed) -------- /CE + * 16 (Init) ------------ C/D + * 17 (Slct) ------------ /RD + *\endverbatim + * + * \todo This driver uses writes to port 0x80 to implement delay. Convert it + * to use \c timing.h. */ -/* +/*- * Base driver module for Toshiba T6963 based LCD displays. ver 2.2 * - * Parts of this file are based on the kernel driver by Alexander Frink + * Parts of this file are based on the kernel driver by A + * lexander Frink * * * This file is released under the GNU General Public License. Refer to the * COPYING file distributed with this package. * * Copyright (c) 2001 Manuel Stahl - * - * */ #include @@ -39,9 +53,8 @@ typedef struct t6963_private_data { u16 port; u16 display_mode; - u8 *display_buffer1; - u8 *display_buffer2; - u8 graph_line[6]; + u8 *display_buffer1; + u8 *display_buffer2; int width; int height; @@ -51,20 +64,23 @@ typedef struct t6963_private_data { short graphicON; } PrivateData; -// Vars for the server core +/* Vars for the server core */ MODULE_EXPORT char *api_version = API_VERSION; MODULE_EXPORT int stay_in_foreground = 0; MODULE_EXPORT int supports_multiple = 0; MODULE_EXPORT char *symbol_prefix = "t6963_"; +/** + * API: Initialize the driver. + */ MODULE_EXPORT int -t6963_init (Driver *drvthis) +t6963_init(Driver * drvthis) { PrivateData *p; int w, h, i, ecp_input; char size[200] = DEFAULT_SIZE; - debug(RPT_INFO, "T6963: init(%p)", drvthis ); + debug(RPT_INFO, "T6963: init(%p)", drvthis); /* Allocate and store private data */ p = (PrivateData *) calloc(1, sizeof(PrivateData)); @@ -75,66 +91,56 @@ t6963_init (Driver *drvthis) /* initialize private data */ p->display_mode = 0; - p->graph_line[0] = 0x20; - p->graph_line[1] = 0x30; - p->graph_line[2] = 0x38; - p->graph_line[3] = 0x3C; - p->graph_line[4] = 0x3E; - p->graph_line[5] = 0x3F; - p->cellwidth = 6; - p->cellheight = 8; - + p->cellwidth = DEFAULT_CELL_WIDTH; + p->cellheight = DEFAULT_CELL_HEIGHT; debug(RPT_DEBUG, "T6963: reading config file..."); /* Read config file */ - /* -------------------------- Which size --------------------------------------*/ + /* Which size? */ strncpy(size, drvthis->config_get_string(drvthis->name, "Size", 0, DEFAULT_SIZE), sizeof(size)); - size[sizeof(size)-1] = '\0'; + size[sizeof(size) - 1] = '\0'; if ((sscanf(size, "%dx%d", &w, &h) != 2) || (w <= 0) || (w > LCD_MAX_WIDTH) || (h <= 0) || (h > LCD_MAX_HEIGHT)) { - report(RPT_WARNING, "%s: cannot read Size: %s, Using default %s", - drvthis->name, size, DEFAULT_SIZE); + report(RPT_WARNING, "%s: cannot read Size: %s, Using default %s", + drvthis->name, size, DEFAULT_SIZE); sscanf(DEFAULT_SIZE, "%dx%d", &w, &h); } p->width = w; p->height = h; - /* --------------------------- Which port --------------------------------------*/ + /* Which port? */ p->port = drvthis->config_get_int(drvthis->name, "Port", 0, DEFAULT_PORT); if ((p->port < 0x200) || (p->port > 0x400)) { p->port = DEFAULT_PORT; report(RPT_WARNING, "%s: Port value must be between 0x200 and 0x400. Using default 0x%03X", - drvthis->name, DEFAULT_PORT); + drvthis->name, DEFAULT_PORT); } - /* ---------------------------- Is ECP mode on ----------------------------------*/ + /* Is ECP mode on? Default: yes */ p->bidirectLPT = drvthis->config_get_bool(drvthis->name, "ECPlpt", 0, 1); - /* ---------------------------- Use graphic -------------------------------------*/ - p->graphicON = drvthis->config_get_bool(drvthis->name, "graphic", 0, 0); + /* Use graphic? Default: no */ + p->graphicON = drvthis->config_get_bool(drvthis->name, "graphic", 0, 0); - /* -- Get permission to parallel port --------------------------------------------*/ + /* Get permission to parallel port */ debug(RPT_DEBUG, "T6963: Getting permission to parallel port %d...", p->port); - - if (port_access_multiple(p->port, 3)) { + if (port_access_multiple(p->port, 3)) { report(RPT_ERR, "%s: no permission to port 0x%03X: (%s)", - drvthis->name, p->port, strerror(errno)); - return -1; - } - - if (port_access(0x80)) { - report(RPT_ERR, "%s: no permission to port 0x80: (%s)", - drvthis->name, strerror(errno)); - return -1; - } + drvthis->name, p->port, strerror(errno)); + return -1; + } + if (port_access(0x80)) { + report(RPT_ERR, "%s: no permission to port 0x80: (%s)", + drvthis->name, strerror(errno)); + return -1; + } debug(RPT_DEBUG, "T6963: cool, got 'em!"); - /* -- Allocate memory for double buffering --*/ - + /* Allocate memory for double buffering */ debug(RPT_DEBUG, "T6963: Allocating double buffering..."); p->display_buffer1 = malloc(p->width * p->height); p->display_buffer2 = malloc(p->width * p->height); @@ -143,77 +149,90 @@ t6963_init (Driver *drvthis) t6963_close(drvthis); return -1; } - /* - Clear front and back buffer -*/ + + /* Clear front and back buffer */ memset(p->display_buffer1, ' ', p->width * p->height); memset(p->display_buffer2, ' ', p->width * p->height); debug(RPT_DEBUG, "T6963: done!"); - /* ------------------- I N I T I A L I Z A T I O N ----------------------- */ + /* ------------------- I N I T I A L I Z A T I O N --------------- */ debug(RPT_DEBUG, "T6963: Sending init to display..."); - t6963_low_set_control(drvthis, 1, 1, 1, 1); - T6963_DATAOUT(p->port); // make 8-bit parallel port an output port + t6963_low_set_control(drvthis, 1, 1, 1, 1); + T6963_DATAOUT(p->port); /* configure port for output */ - /* - Test ECP mode -*/ - if (p->bidirectLPT == 1) { - debug(RPT_WARNING, "T6963: Testing ECP mode..."); - i=0; ecp_input=0; + /* Test if bidirectional mode is working */ + if (p->bidirectLPT == 1) { + debug(RPT_WARNING, "T6963: Testing bidirectional mode..."); + i = 0; + ecp_input = 0; T6963_DATAIN(p->port); + /* + * Try to read status from display. STA0 and STA1 must both + * be set 1 (= 0x03). + */ do { - i++; - t6963_low_set_control(drvthis, 1, 1, 1, 1); // wr, ce, cd, rd + i++; + t6963_low_set_control(drvthis, 1, 1, 1, 1); t6963_low_set_control(drvthis, 1, 0, 1, 0); t6963_low_set_control(drvthis, 1, 0, 1, 0); t6963_low_set_control(drvthis, 1, 0, 1, 0); ecp_input = port_in(T6963_DATA_PORT(p->port)); t6963_low_set_control(drvthis, 1, 1, 1, 1); - } while (i < 100 && (ecp_input & 0x03)!=0x03); + } while (i < 100 && (ecp_input & 0x03) != 0x03); T6963_DATAOUT(p->port); if (i >= 100) { - debug(RPT_WARNING, "T6963: ECP mode not working!\n -> is now disabled (STA0: %i, STA1: %i", ecp_input & 1, ecp_input & 2); + debug(RPT_WARNING, "T6963: Bidirectional mode not working!\n -> is now disabled (STA0: %i, STA1: %i)", ecp_input & 1, ecp_input & 2); p->bidirectLPT = 0; } else debug(RPT_WARNING, "T6963: working!"); - } + } debug(RPT_DEBUG, "T6963: set graphic/text home adress and area"); - t6963_low_command_word(drvthis, SET_GRAPHIC_HOME_ADDRESS, ATTRIB_BASE); - t6963_low_command_word(drvthis, SET_GRAPHIC_AREA, p->width); - t6963_low_command_word(drvthis, SET_TEXT_HOME_ADDRESS, TEXT_BASE); - t6963_low_command_word(drvthis, SET_TEXT_AREA, p->width); + /* Set text and graphic addresses */ + t6963_low_command_word(drvthis, SET_GRAPHIC_HOME_ADDRESS, ATTRIB_BASE); + t6963_low_command_word(drvthis, SET_GRAPHIC_AREA, p->width); + t6963_low_command_word(drvthis, SET_TEXT_HOME_ADDRESS, TEXT_BASE); + t6963_low_command_word(drvthis, SET_TEXT_AREA, p->width); - t6963_low_command (drvthis, SET_MODE | OR_MODE | EXTERNAL_CG); - t6963_low_command_2_bytes (drvthis, SET_OFFSET_REGISTER, CHARGEN_BASE>>11, 0); - t6963_low_command (drvthis, SET_CURSOR_PATTERN | 7); // cursor is 8 lines high - t6963_low_command_2_bytes (drvthis, SET_CURSOR_POINTER, 0, 0); + /* Enable external character generator */ + t6963_low_command(drvthis, SET_MODE | OR_MODE | EXTERNAL_CG); + /* Set address of CG RAM address start */ + t6963_low_command_2_bytes(drvthis, SET_OFFSET_REGISTER, CHARGEN_BASE >> 11, 0); - t6963_set_nchar(drvthis, 0, fontdata_6x8, 256); + /* Set cursor to 8 lines and place it at position (0,0) */ + t6963_low_command(drvthis, SET_CURSOR_PATTERN | 7); + t6963_low_command_2_bytes(drvthis, SET_CURSOR_POINTER, 0, 0); - t6963_low_enable_mode(drvthis, TEXT_ON); - if (p->graphicON == 0) + /* Load font data */ + t6963_set_nchar(drvthis, 0, fontdata_6x8, 256); + + /* Turn on text and optionally graphics, turn off cursor */ + t6963_low_enable_mode(drvthis, TEXT_ON); + if (p->graphicON == 0) t6963_low_disable_mode(drvthis, GRAPHIC_ON); - else + else t6963_low_enable_mode(drvthis, GRAPHIC_ON); - t6963_low_disable_mode(drvthis, CURSOR_ON); - t6963_low_disable_mode(drvthis, BLINK_ON); + t6963_low_disable_mode(drvthis, CURSOR_ON); + t6963_low_disable_mode(drvthis, BLINK_ON); - t6963_clear(drvthis); - t6963_graphic_clear(drvthis, 0, 0, p->width, p->cellheight * p->height); - t6963_flush(drvthis); + /* Clear display */ + t6963_clear(drvthis); + t6963_graphic_clear(drvthis, 0, 0, p->width, p->cellheight * p->height); + t6963_flush(drvthis); report(RPT_DEBUG, "%s: init() done", drvthis->name); - return 0; // return success + return 0; /* return success */ } -// Below here, you may use either lcd.framebuf or driver->framebuf.. -// lcd.framebuf will be set to the appropriate buffer before calling -// your driver. - +/** + * API: Close the driver. + */ MODULE_EXPORT void -t6963_close (Driver *drvthis) +t6963_close(Driver * drvthis) { PrivateData *p = drvthis->private_data; @@ -222,7 +241,7 @@ t6963_close (Driver *drvthis) if (p != NULL) { t6963_low_disable_mode(drvthis, BLINK_ON); - port_deny_multiple(p->port,3); + port_deny_multiple(p->port, 3); if (p->display_buffer1 != NULL) free(p->display_buffer1); @@ -235,33 +254,33 @@ t6963_close (Driver *drvthis) drvthis->store_private_ptr(drvthis, NULL); } -///////////////////////////////////////////////////////////////// -// Returns the display width -// +/** + * API: Returns the display width + */ MODULE_EXPORT int -t6963_width (Driver *drvthis) +t6963_width(Driver * drvthis) { PrivateData *p = drvthis->private_data; return p->width; } -///////////////////////////////////////////////////////////////// -// Returns the display height -// +/** + * API: Returns the display height + */ MODULE_EXPORT int -t6963_height (Driver *drvthis) +t6963_height(Driver * drvthis) { PrivateData *p = drvthis->private_data; return p->height; } -///////////////////////////////////////////////////////////////// -// Clears the LCD screen -// +/** + * API: Clears the LCD screen (clear display buffer) + */ MODULE_EXPORT void -t6963_clear (Driver *drvthis) +t6963_clear(Driver * drvthis) { PrivateData *p = drvthis->private_data; @@ -270,25 +289,33 @@ t6963_clear (Driver *drvthis) debug(RPT_DEBUG, "Done"); } +/** + * Clears the specified area of graphic RAM. + * \param drvthis Pointer to driver structure. + * \param x1 Start column (character!) + * \param y1 Start line (pixel row) + * \param x2 End column (character!) + * \param y2 End line (pixel row) + */ void -t6963_graphic_clear(Driver *drvthis, int x1, int y1, int x2, int y2) +t6963_graphic_clear(Driver * drvthis, int x1, int y1, int x2, int y2) { PrivateData *p = drvthis->private_data; int x; - debug(RPT_DEBUG, "Clearing Graphic %d bytes", (x2-x1)*(y2-y1)); - for ( ; y1 < y2; y1++) { + debug(RPT_DEBUG, "Clearing Graphic %d bytes", (x2 - x1) * (y2 - y1)); + for (; y1 < y2; y1++) { t6963_low_command_word(drvthis, SET_ADDRESS_POINTER, ATTRIB_BASE + y1 * p->width + x1); for (x = x1; x < x2; x++) t6963_low_command_byte(drvthis, DATA_WRITE_INC, 0); } } -////////////////////////////////////////////////////////////////// -// Flushes all output to the lcd... -// +/** + * API: Flushes all output to the lcd. + */ MODULE_EXPORT void -t6963_flush (Driver *drvthis) +t6963_flush(Driver * drvthis) { PrivateData *p = drvthis->private_data; int i; @@ -296,42 +323,42 @@ t6963_flush (Driver *drvthis) debug(RPT_DEBUG, "Flushing %d x %d", p->width, p->height); for (i = 0; i < (p->width * p->height); i++) { - // debug(RPT_DEBUG, "%i%i|", p->display_buffer1[i], p->display_buffer2[i]); + //debug(RPT_DEBUG, "%i%|i", p->display_buffer1[i], p->display_buffer2[i]); if (p->display_buffer1[i] != p->display_buffer2[i]) { t6963_low_command_word(drvthis, SET_ADDRESS_POINTER, TEXT_BASE + i); t6963_low_command_byte(drvthis, DATA_WRITE, p->display_buffer1[i]); } } debug(RPT_DEBUG, "Done"); + /* Reverse the two buffers and clear buffer1 */ t6963_swap_buffers(drvthis); t6963_clear(drvthis); } -///////////////////////////////////////////////////////////////// -// Prints a string on the lcd display, at position (x,y). The -// upper-left is (1,1), and the lower right should be (20,6). -// +/** + * API: Prints a string on the lcd display, at position (x,y). The + * upper-left is (1,1), and the lower right should be (20,6). + */ MODULE_EXPORT void -t6963_string (Driver *drvthis, int x, int y, const char string[]) +t6963_string(Driver * drvthis, int x, int y, const char string[]) { PrivateData *p = drvthis->private_data; debug(RPT_DEBUG, "String out"); - x--; // Convert 1-based coords to 0-based... + x--; /* Convert 1-based coords to 0-based */ y--; - if ((y * p->width + x + strlen(string)) <= (p->width * p->height)); + if ((y * p->width + x + strlen(string)) <= (p->width * p->height)) memcpy(&p->display_buffer1[y * p->width + x], string, strlen(string)); - } -///////////////////////////////////////////////////////////////// -// Prints a character on the lcd display, at position (x,y). The -// upper-left is (1,1), and the lower right should be (20,6). -// +/** + * API: Prints a character on the lcd display, at position (x,y). The + * upper-left is (1,1), and the lower right should be (20,6). + */ MODULE_EXPORT void -t6963_chr (Driver *drvthis, int x, int y, char c) +t6963_chr(Driver * drvthis, int x, int y, char c) { PrivateData *p = drvthis->private_data; @@ -343,20 +370,24 @@ t6963_chr (Driver *drvthis, int x, int y, char c) p->display_buffer1[(y * p->width) + x] = c; } -////////////////////////////////////////////////////////////////////// -// Draws a big (4-row) number. -// +/** + * API: Draws a big (4-row) number. (NOT IMPLEMENTED) + */ MODULE_EXPORT void -t6963_num (Driver *drvthis, int x, int num) +t6963_num(Driver * drvthis, int x, int num) { -// printf("BigNum(%i, %i)\n", x, num); + //printf("BigNum(%i, %i)\n", x, num); } -////////////////////////////////////////////////////////////////////// -// Changes the font data of character n. -// +/** + * Changes the font data of character n. + * \param drvthis Pointer to driver structure. + * \param n Index of character in CGRAM to update. + * \param dat Data (must consist of num*cellwidth*cellheight bytes). + * \param num Number of characters stored in data. + */ void -t6963_set_nchar (Driver *drvthis, int n, unsigned char *dat, int num) +t6963_set_nchar(Driver * drvthis, int n, unsigned char *dat, int num) { PrivateData *p = drvthis->private_data; int row, col; @@ -364,201 +395,240 @@ t6963_set_nchar (Driver *drvthis, int n, unsigned char *dat, int num) debug(RPT_DEBUG, "Setting char %d", n); - if ((!dat) || (n + num > 256)) - return; + if ((!dat) || (n + num > 256)) + return; - t6963_low_command_word(drvthis, SET_ADDRESS_POINTER, CHARGEN_BASE + n*8); - for (row = 0; row < p->cellheight * num; row++) { - letter = 0; - for (col = 0; col < p->cellwidth; col++) { - letter <<= 1; - letter |= (dat[(row * p->cellwidth) + col] > 0); - } + t6963_low_command_word(drvthis, SET_ADDRESS_POINTER, CHARGEN_BASE + n * 8); + for (row = 0; row < p->cellheight * num; row++) { + letter = 0; + /* Accumulate data for one pixel row */ + for (col = 0; col < p->cellwidth; col++) { + letter <<= 1; + letter |= (dat[(row * p->cellwidth) + col] > 0); + } t6963_low_command_byte(drvthis, DATA_WRITE_INC, letter); - } + } } +/** + * API: Define a custom character and write it to the LCD. + */ MODULE_EXPORT void -t6963_set_char (Driver *drvthis, int n, char *dat) +t6963_set_char(Driver * drvthis, int n, char *dat) { - t6963_set_nchar(drvthis, n, (unsigned char *) dat, 1); + t6963_set_nchar(drvthis, n, (unsigned char *)dat, 1); } -///////////////////////////////////////////////////////////////// -// Draws a vertical bar, from the bottom of the screen up. -// +/** + * API: Draws a vertical bar, from the bottom of the screen up. + */ MODULE_EXPORT void -t6963_vbar (Driver *drvthis, int x, int y, int len, int promille, int options) +t6963_vbar(Driver * drvthis, int x, int y, int len, int promille, int options) { PrivateData *p = drvthis->private_data; lib_vbar_static(drvthis, x, y, len, promille, options, p->cellheight, 212); } -///////////////////////////////////////////////////////////////// -// Draws a horizontal bar to the right. -// +/** + * API: Draws a horizontal bar to the right. + */ MODULE_EXPORT void -t6963_hbar (Driver *drvthis, int x, int y, int len, int promille, int options) +t6963_hbar(Driver * drvthis, int x, int y, int len, int promille, int options) { PrivateData *p = drvthis->private_data; lib_hbar_static(drvthis, x, y, len, promille, options, p->cellwidth, 220); } -///////////////////////////////////////////////////////////////// -// Sets an icon... -// +/** + * API: Sets an icon... + */ MODULE_EXPORT int -t6963_icon (Driver *drvthis, int x, int y, int icon) +t6963_icon(Driver * drvthis, int x, int y, int icon) { debug(RPT_DEBUG, "T6963: set icon %d", icon); switch (icon) { - case ICON_BLOCK_FILLED: - t6963_chr(drvthis, x, y, 219 ); - break; - case ICON_HEART_FILLED: - t6963_chr(drvthis, x, y, 3 ); - break; - case ICON_HEART_OPEN: - t6963_chr(drvthis, x, y, 4 ); - break; - default: - return -1; + case ICON_BLOCK_FILLED: + t6963_chr(drvthis, x, y, 219); + break; + case ICON_HEART_FILLED: + t6963_chr(drvthis, x, y, 3); + break; + case ICON_HEART_OPEN: + t6963_chr(drvthis, x, y, 4); + break; + default: + return -1; } return 0; } -/* ---------------------- internal functions ------------------------------------- */ +/*---------------------- internal functions -------------------------------*/ + +/** + * Set control lines for the display. State values are \c 0 or \c 1 and + * represent the real level as it arrives at the display. This function + * takes into account the hardware inversion of control lines. + * + * \param drvthis Pointer to driver structure. + * \param wr State of the /RW pin (0 or 1). + * \param ce State of the /CE pin (0 or 1). + * \param cd State of the C/D pin (0 or 1). + * \param rd State of the /RD pin (0 or 1). + */ void -t6963_low_set_control(Driver *drvthis, char wr, char ce, char cd, char rd) +t6963_low_set_control(Driver * drvthis, char wr, char ce, char cd, char rd) { PrivateData *p = drvthis->private_data; - unsigned char status = port_in(T6963_CONTROL_PORT(p->port)); /* TODO: support multiple wirings! */ - if (wr == 1) /* WR = HI */ + unsigned char status = port_in(T6963_CONTROL_PORT(p->port)); + if (wr == 1) /* WR = HI */ status &= 0xfe; else if (wr == 0) status |= 0x01; - if (ce == 1) /* CE = HI */ + if (ce == 1) /* CE = HI */ status &= 0xfd; else if (ce == 0) status |= 0x02; - if (cd == 0) /* CD = HI */ + if (cd == 0) /* CD = HI */ status &= 0xfb; else if (cd == 1) status |= 0x04; - if (rd == 1) /* CE = HI */ + if (rd == 1) /* RD = HI */ status &= 0xf7; else if (rd == 0) status |= 0x08; port_out(T6963_CONTROL_PORT(p->port), status); } +/** + * Check display status. + * \param drvthis Pointer to driver structure. + */ void -t6963_low_dsp_ready (Driver *drvthis) +t6963_low_dsp_ready(Driver * drvthis) { - PrivateData *p = drvthis->private_data; - int i = 0; - int input; + PrivateData *p = drvthis->private_data; + int i = 0; + int input; - T6963_DATAIN(p->port); - if (p->bidirectLPT == 1) { - do { - i++; -/* t6963_low_set_control(drvthis, 1, 0, 1, -1); - t6963_low_set_control(drvthis, 1, 0, 1, 0); - input = port_in(T6963_DATA_PORT(p->port)); - t6963_low_set_control(drvthis, 1, 0, 1, -1); */ - t6963_low_set_control(drvthis, 1, 1, 1, 1); - t6963_low_set_control(drvthis, 1, 0, 1, 0); - t6963_low_set_control(drvthis, 1, 0, 1, 0); - t6963_low_set_control(drvthis, 1, 0, 1, 0); - // tacc max 150ns - input = port_in(T6963_DATA_PORT(p->port)); - t6963_low_set_control(drvthis, 1, 1, 1, 1); + T6963_DATAIN(p->port); + if (p->bidirectLPT == 1) { + do { + i++; + t6963_low_set_control(drvthis, 1, 1, 1, 1); + /* + * Output control lines 3 times (hold value for tacc + * max 150ns + */ + t6963_low_set_control(drvthis, 1, 0, 1, 0); + t6963_low_set_control(drvthis, 1, 0, 1, 0); + t6963_low_set_control(drvthis, 1, 0, 1, 0); + input = port_in(T6963_DATA_PORT(p->port)); + t6963_low_set_control(drvthis, 1, 1, 1, 1); - } while (i < 100 && (input & 3)!=3); - } else { - // for (i=0; i<3; i++) + } while (i < 100 && (input & 3) != 3); + } + else { t6963_low_set_control(drvthis, 1, 1, 1, 1); t6963_low_set_control(drvthis, 1, 0, 1, 0); t6963_low_set_control(drvthis, 1, 1, 1, 1); - port_out(0x80, 0x00); // wait 1ms - } - T6963_DATAOUT(p->port); + port_out(0x80, 0x00); /* wait 1ms */ + } + T6963_DATAOUT(p->port); } + +/** + * Send one data byte to the display. + * \param drvthis Pointer to driver structure. + * \param byte Data byte. + */ void -t6963_low_data (Driver *drvthis, u8 byte) +t6963_low_data(Driver * drvthis, u8 byte) { - PrivateData *p = drvthis->private_data; + PrivateData *p = drvthis->private_data; - t6963_low_dsp_ready(drvthis); - t6963_low_set_control(drvthis, 1, 1, 0, 1); // CD down (data) - t6963_low_set_control(drvthis, 0, 0, 0, 1); // CE & WR down - port_out(T6963_DATA_PORT(p->port), byte); // present data - port_out(0x80, 0x00); - t6963_low_set_control(drvthis, 1, 1, 1, 1); // all up again - -/* port_out(T6963_DATA_PORT(p->port), byte); // write value to data port - t6963_low_set_control(drvthis, 1, 1, 0, 1); - t6963_low_set_control(drvthis, 0, 0, 0, 1); - t6963_low_set_control(drvthis, 1, 1, 1, 1); */ + t6963_low_dsp_ready(drvthis); /* Check if display ready */ + t6963_low_set_control(drvthis, 1, 1, 0, 1); /* CD down (data) */ + t6963_low_set_control(drvthis, 0, 0, 0, 1); /* CE & WR down */ + port_out(T6963_DATA_PORT(p->port), byte); /* present data */ + port_out(0x80, 0x00); /* short wait */ + t6963_low_set_control(drvthis, 1, 1, 1, 1); /* all up again */ } +/** + * Send one command byte to the display. + * \param drvthis Pointer to driver structure. + * \param byte Command byte. + */ void -t6963_low_command (Driver *drvthis, u8 byte) +t6963_low_command(Driver * drvthis, u8 byte) { - PrivateData *p = drvthis->private_data; + PrivateData *p = drvthis->private_data; - t6963_low_dsp_ready(drvthis); - t6963_low_set_control(drvthis, 1, 1, 1, 1); // CD up (command) - t6963_low_set_control(drvthis, 0, 0, 1, 1); // CE & WR down - port_out(T6963_DATA_PORT(p->port), byte); // present data to LCD on PC's port pins - port_out(0x80, 0x00); - t6963_low_set_control(drvthis, 1, 1, 0, 1); // CE & WR up, CD down - -/* - port_out(T6963_DATA_PORT(p->port), byte); // present data to LCD on PC's port pins - t6963_low_set_control(drvthis, 1, 1, 1, 1); - t6963_low_set_control(drvthis, 0, 0, 1, 1); - t6963_low_set_control(drvthis, 1, 1, 0, 1); */ + t6963_low_dsp_ready(drvthis); /* Check if display ready */ + t6963_low_set_control(drvthis, 1, 1, 1, 1); /* CD up (command) */ + t6963_low_set_control(drvthis, 0, 0, 1, 1); /* CE & WR down */ + port_out(T6963_DATA_PORT(p->port), byte); /* present data */ + port_out(0x80, 0x00); /* short wait */ + t6963_low_set_control(drvthis, 1, 1, 0, 1); /* CE & WR up, CD down */ } +/** + * Send one byte of data followed by one command byte to the display. + * \param drvthis Pointer to driver structure. + * \param cmd Command byte. + * \param byte Data value. + */ void -t6963_low_command_byte(Driver *drvthis, u8 cmd, u8 byte) +t6963_low_command_byte(Driver * drvthis, u8 cmd, u8 byte) { - //PrivateData *p = drvthis->private_data; - - t6963_low_data(drvthis, byte); - t6963_low_command(drvthis, cmd); + t6963_low_data(drvthis, byte); + t6963_low_command(drvthis, cmd); } +/** + * Send two bytes of data followed by one command byte to the display. + * \param drvthis Pointer to driver structure. + * \param cmd Command byte. + * \param byte1 Data value (byte 1) + * \param byte2 Data value (byte 2) + */ void -t6963_low_command_2_bytes(Driver *drvthis, u8 cmd, u8 byte1, u8 byte2) +t6963_low_command_2_bytes(Driver * drvthis, u8 cmd, u8 byte1, u8 byte2) { - //PrivateData *p = drvthis->private_data; - - t6963_low_data(drvthis, byte1); - t6963_low_data(drvthis, byte2); - t6963_low_command(drvthis, cmd); + t6963_low_data(drvthis, byte1); + t6963_low_data(drvthis, byte2); + t6963_low_command(drvthis, cmd); } +/** + * Send one word (two bytes) of data followed by one command byte to the + * display. Low byte is output first. + * \param drvthis Pointer to driver structure. + * \param cmd Command byte. + * \param word Data value (2 bytes) + */ void -t6963_low_command_word(Driver *drvthis, u8 cmd, u16 word) +t6963_low_command_word(Driver * drvthis, u8 cmd, u16 word) { - //PrivateData *p = drvthis->private_data; - - t6963_low_data(drvthis, word%256); - t6963_low_data(drvthis, word>>8); - t6963_low_command(drvthis, cmd); + t6963_low_data(drvthis, word % 256); + t6963_low_data(drvthis, word >> 8); + t6963_low_command(drvthis, cmd); } +/** + * Send 'SET DISPLAY MODE' command to LCD setting the desired mode and store + * it in private data. + * \param drvthis Pointer to driver structure. + * \param mode Display mode to set. + */ void -t6963_low_enable_mode (Driver *drvthis, u8 mode) +t6963_low_enable_mode(Driver * drvthis, u8 mode) { PrivateData *p = drvthis->private_data; @@ -566,8 +636,14 @@ t6963_low_enable_mode (Driver *drvthis, u8 mode) t6963_low_command(drvthis, SET_DISPLAY_MODE | p->display_mode); } +/** + * Send 'SET DISPLAY MODE' command to LCD with the desired mode cleared and + * store the new value in private data. + * \param drvthis Pointer to driver structure. + * \param mode Display mode to clear. + */ void -t6963_low_disable_mode (Driver *drvthis, u8 mode) +t6963_low_disable_mode(Driver * drvthis, u8 mode) { PrivateData *p = drvthis->private_data; @@ -575,8 +651,13 @@ t6963_low_disable_mode (Driver *drvthis, u8 mode) t6963_low_command(drvthis, SET_DISPLAY_MODE | p->display_mode); } +/** + * Swap the two display buffers. This function does not swap the actual + * data but the pointers to the buffers. + * \param drvthis Pointer to driver structure. + */ void -t6963_swap_buffers (Driver *drvthis) +t6963_swap_buffers(Driver * drvthis) { PrivateData *p = drvthis->private_data; diff --git a/server/drivers/t6963.h b/server/drivers/t6963.h index c408359..18d76e4 100644 --- a/server/drivers/t6963.h +++ b/server/drivers/t6963.h @@ -1,117 +1,95 @@ -/* +/*- * Base driver module for Toshiba T6963 based LCD displays ver 2.2 * ( ver 2.* is not at all compatible to 1.* versions!) * - * Parts of this file are based on the kernel driver by Alexander Frink + * Parts of this file are based on the kernel driver by + * Alexander Frink * * This file is released under the GNU General Public License. Refer to the * COPYING file distributed with this package. * * Copyright (c) 2001 Manuel Stahl - * - * Wiring: - * Parallel:              LCD: - * 1 (Strobe) ----------- 5 (WR) - * 2-9 (Data) ----------- 11-18 (Data) - * 14 (Autofeed) -------- 7 (CE) - * 16 (Init) ------------ 8 (C/D) - * 17 (Slct) ------------ 6 (RD) - * 18 (GND) ------------- 3 (GND) - * +5V ------------------ 3(LCD +) - * */ #ifndef T6963_H #define T6963_H -#include "lcd.h" - #define DEFAULT_CELL_WIDTH 6 #define DEFAULT_CELL_HEIGHT 8 #define DEFAULT_SIZE "20x6" #define DEFAULT_PORT 0x378 -#define DEFAULT_WRHI 0x04 -#define DEFAULT_WRLO 0xfb -#define DEFAULT_CEHI 0xfe -#define DEFAULT_CELO 0x01 -#define DEFAULT_CDHI 0xf7 -#define DEFAULT_CDLO 0x08 -#define DEFAULT_RDHI 0xfd -#define DEFAULT_RDLO 0x02 -#define SM_UP (1) -#define SM_DOWN (2) -#define CM_ERASE (2) -#define CUR_LOWER_THIRD 3 -#define CUR_LOWER_HALF 4 -#define CUR_TWO_THIRDS 5 -#define CUR_BLOCK 6 -#define CUR_NONE 1 - -// 8bit Data input +/** Configure LPT port for bidirectional input */ #define T6963_DATAIN(p) port_out(T6963_CONTROL_PORT(p), port_in(T6963_CONTROL_PORT(p)) | 0x20) -// 8bit Data output +/** Configure LPT port for bidirectional output */ #define T6963_DATAOUT(p) port_out(T6963_CONTROL_PORT(p), port_in(T6963_CONTROL_PORT(p)) & 0xdf) -#define TEXT_BASE 0x0000 -#define ATTRIB_BASE 0x7000 -#define CHARGEN_BASE 0xF000 +/* RAM layout base addresses (for 64 KB RAM) */ +/* + * FIXME: Those addresses are fine for 64 KB RAM. If the display has less, + * these values need to be adjusted by the user. It should do no harm setting + * these for 8 KB RAM. + * / +#define TEXT_BASE 0x0000 +#define ATTRIB_BASE 0x7000 +#define CHARGEN_BASE 0xF000 -#define SET_CURSOR_POINTER 0x21 -#define SET_OFFSET_REGISTER 0x22 -#define SET_ADDRESS_POINTER 0x24 +/* 'Registers setting' commands */ +#define SET_CURSOR_POINTER 0x21 +#define SET_OFFSET_REGISTER 0x22 +#define SET_ADDRESS_POINTER 0x24 -#define SET_TEXT_HOME_ADDRESS 0x40 -#define SET_TEXT_AREA 0x41 -#define SET_GRAPHIC_HOME_ADDRESS 0x42 -#define SET_GRAPHIC_AREA 0x43 +/* 'Set control word' commands */ +#define SET_TEXT_HOME_ADDRESS 0x40 +#define SET_TEXT_AREA 0x41 +#define SET_GRAPHIC_HOME_ADDRESS 0x42 +#define SET_GRAPHIC_AREA 0x43 -#define SET_MODE 0x80 -#define OR_MODE 0x00 -#define EXOR_MODE 0x01 -#define AND_MODE 0x03 -#define ATTRIBUTE_MODE 0x04 -#define INTERNAL_CG 0x00 -#define EXTERNAL_CG 0x08 +/* 'Mode set' command and options*/ +#define SET_MODE 0x80 +#define OR_MODE 0x00 +#define EXOR_MODE 0x01 +#define AND_MODE 0x03 +#define ATTRIBUTE_MODE 0x04 +#define INTERNAL_CG 0x00 +#define EXTERNAL_CG 0x08 -#define SET_DISPLAY_MODE 0x90 -#define BLINK_ON 0x01 -#define CURSOR_ON 0x02 -#define TEXT_ON 0x04 -#define GRAPHIC_ON 0x08 +/* 'Display mode' command and options */ +#define SET_DISPLAY_MODE 0x90 +#define BLINK_ON 0x01 +#define CURSOR_ON 0x02 +#define TEXT_ON 0x04 +#define GRAPHIC_ON 0x08 -#define SET_CURSOR_PATTERN 0xa0 +/* 'Cursor pattern select' command */ +#define SET_CURSOR_PATTERN 0xa0 -#define DATA_WRITE_INC 0xc0 -#define DATA_READ_INC 0xc1 -#define DATA_WRITE_DEC 0xc2 -#define DATA_READ_DEC 0xc3 -#define DATA_WRITE 0xc4 -#define DATA_READ 0xc5 +/* 'Data read/write' commands */ +#define DATA_WRITE_INC 0xc0 +#define DATA_READ_INC 0xc1 +#define DATA_WRITE_DEC 0xc2 +#define DATA_READ_DEC 0xc3 +#define DATA_WRITE 0xc4 +#define DATA_READ 0xc5 -#define AUTO_WRITE 0xb0 -#define AUTO_READ 0xb1 -#define AUTO_RESET 0xb +/* 'Data auto read/write' commands */ +#define AUTO_WRITE 0xb0 +#define AUTO_READ 0xb1 +#define AUTO_RESET 0xb -#define POSITION(x,y) ((y)*lcd.wid + (x)) +/* Macros to make port usage more readable */ #define T6963_DATA_PORT(p) (p) #define T6963_STATUS_PORT(p) ((p)+1) #define T6963_CONTROL_PORT(p) ((p)+2) -// **************************************************************************************** -// * V A R I A B L E S * -// **************************************************************************************** - +/* Data types */ typedef unsigned short u16; typedef unsigned char u8; -// **************************************************************************************** -// * F U N C T I O N S * -// **************************************************************************************** - +/* API functions */ MODULE_EXPORT int t6963_init (Driver *drvthis); MODULE_EXPORT void t6963_close (Driver *drvthis); MODULE_EXPORT int t6963_width (Driver *drvthis); @@ -120,15 +98,14 @@ MODULE_EXPORT void t6963_clear (Driver *drvthis); MODULE_EXPORT void t6963_flush (Driver *drvthis); MODULE_EXPORT void t6963_string (Driver *drvthis, int x, int y, const char string[]); MODULE_EXPORT void t6963_chr (Driver *drvthis, int x, int y, char c); - MODULE_EXPORT void t6963_vbar (Driver *drvthis, int x, int y, int len, int promille, int options); MODULE_EXPORT void t6963_hbar (Driver *drvthis, int x, int y, int len, int promille, int options); MODULE_EXPORT void t6963_num (Driver *drvthis, int x, int num); MODULE_EXPORT int t6963_icon (Driver *drvthis, int x, int y, int icon); - MODULE_EXPORT void t6963_set_char (Driver *drvthis, int n, char *dat); +/* Internal functions */ void t6963_graphic_clear (Driver *drvthis, int x1, int y1, int x2, int y2); void t6963_set_nchar (Driver *drvthis, int n, unsigned char *dat, int num); diff --git a/server/drivers/t6963_font.h b/server/drivers/t6963_font.h index a014faa..e3d663c 100644 --- a/server/drivers/t6963_font.h +++ b/server/drivers/t6963_font.h @@ -1,8 +1,12 @@ -/* +/** \file server/drivers/t6963_font.h + * Font definition for use the t6963 driver. + */ + +/*- * Base driver module for Toshiba T6963 based LCD displays. ver 2.0 * - * Parts of this file are based on the kernel driver by Alexander Frink - * + * Parts of this file are based on the kernel driver by + * Alexander Frink * * This file is released under the GNU General Public License. Refer to the * COPYING file distributed with this package. @@ -12,7 +16,16 @@ #define FONTDATAMAX 12288 - +/** + * Definition of a 6x8 font recreating the characters from CP437 with the + * following exceptions at position: + * \li 4 contains the open heart icon + * \li 212-219 are vor vBars (bottom to top) + * \li 220-224 are for hBars (growing right) + * \li 247-251 are for hBars (growing left) + * \li 228,246,252 contain small german umlaute (upper case are missing) + * \li 243,244 contain ?? + */ unsigned char fontdata_6x8[FONTDATAMAX] = { /* num: 0 */ 0,0,0,0,0,0, @@ -59,14 +72,6 @@ unsigned char fontdata_6x8[FONTDATAMAX] = { 0,0,0,1,0,0, 0,0,0,0,0,0, 0,0,0,0,0,0, -/*0,0,0,0,0,0, -0,0,1,0,1,0, -0,1,0,1,0,1, -0,1,0,0,0,1, -0,1,0,0,0,1, -0,0,1,0,1,0, -0,0,0,1,0,0, -0,0,0,0,0,0,*/ /* num: 5 */ 0,0,0,1,0,0, 0,0,1,1,1,0,