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.
This commit is contained in:
mmdolze
2011-01-03 10:51:50 +00:00
parent a0e30b34b5
commit 680891761e
4 changed files with 470 additions and 381 deletions
+82 -56
View File
@@ -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.
</para>
<para>
The driver uses the text mode of the chipset with a custom font loaded which
resembles the characters from Code Page 437.
</para>
<para>
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!
</para>
<sect2 id="t6963-connections">
<title>Connections</title>
<warning>
<para>
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!
</para>
<para>
We do not give wiring examples for power, contrast, and other control lines.
You have to figure out this from your display's datasheet!
</para>
</warning>
<table id="t6963-connections.mapping">
<title>T6963 wiring schematic</title>
<tgroup cols="2">
<tgroup cols="5" align="left">
<colspec colname="lpt1"/>
<colspec colname="lpt2" align="right"/>
<colspec colname="base" align="center"/>
<colspec colname="lcd1"/>
<colspec colname="lcd2"/>
<thead>
<row>
<entry>Parallel port</entry>
<entry>LCD</entry>
<entry namest="lpt1" nameend="lpt2" align="center">Parallel port</entry>
<entry morerows="1">&lt;-&gt;</entry>
<entry namest="lcd1" nameend="lcd2" align="center">LCD</entry>
</row>
<row>
<entry>name</entry>
<entry>pin</entry>
<entry>name</entry>
<entry>pin</entry>
</row>
</thead>
<tbody>
<row>
<entry>1 (Strobe)</entry>
<entry>5 (WR)</entry>
<entry>nSTRB</entry>
<entry>1</entry>
<entry></entry>
<entry>/WR</entry>
<entry>*</entry>
</row>
<row>
<entry>2-9 (Data)</entry>
<entry>11-18 (Data)</entry>
<entry>D0-D7</entry>
<entry>2-9</entry>
<entry></entry>
<entry>DB0-DB7</entry>
<entry>*</entry>
</row>
<row>
<entry>14 (Autofeed)</entry>
<entry>7 (CE)</entry>
<entry>nLF</entry>
<entry>14</entry>
<entry></entry>
<entry>/CE</entry>
<entry>*</entry>
</row>
<row>
<entry>16 (Init)</entry>
<entry>8 (C/D)</entry>
<entry>INIT</entry>
<entry>16</entry>
<entry></entry>
<entry>C/D</entry>
<entry>*</entry>
</row>
<row>
<entry>17 (Slct)</entry>
<entry>6 (RD)</entry>
</row>
<row>
<entry>18 (GND)</entry>
<entry>3 (GND)</entry>
</row>
<row>
<entry>+5V</entry>
<entry>3 (LCD +)</entry>
<entry>nSEL</entry>
<entry>17</entry>
<entry></entry>
<entry>/RD</entry>
<entry>*</entry>
</row>
</tbody>
</tgroup>
@@ -100,18 +144,31 @@ can be done by specifying "--enable-drivers=all" or by
<term>
<property>ECPlpt</property> = &parameters.yesdefno;
</term>
<listitem><para>
<listitem>
<para>
Is ECP mode on? [default: <literal>yes</literal>; legal: <literal>yes</literal>, <literal>no</literal>]
</para></listitem>
</para>
<para>
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.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<property>graphic</property> = &parameters.yesnodef;
</term>
<listitem><para>
<listitem>
<para>
Use graphic? [default: <literal>no</literal>; legal: <literal>yes</literal>, <literal>no</literal>]
</para></listitem>
</para>
<para>
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.
</para>
</listitem>
</varlistentry>
</variablelist>
@@ -119,35 +176,4 @@ can be done by specifying "--enable-drivers=all" or by
</sect2>
<sect2 id="t6963-running">
<title>Running</title>
<para>
Modify the <filename>LCDd.conf</filename> file before you run LCDd. In this config file are
detailed instructions on how to configure the T6963 driver.
</para>
<para>
Then as usual, start LCDd with the correct config file:
</para>
<para>
E.g. <command>LCDd -c ./LCDd.conf</command>
</para>
<para>
If you want to override the driver selection in LCDd.conf then use:
</para>
<para>
<command>LCDd -c ./LCDd.conf -d T6963</command>
</para>
<para>
If you use this, the T6963 driver will read the options from the config
file anyway.
</para>
</sect2>
</sect1>
+317 -236
View File
@@ -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 <Alexander.Frink@Uni-Mainz.DE>
* Parts of this file are based on the kernel driver by A
* lexander Frink <Alexander.Frink@Uni-Mainz.DE>
*
*
* This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package.
*
* Copyright (c) 2001 Manuel Stahl <mythos@xmythos.de>
*
*
*/
#include <stdlib.h>
@@ -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;
+54 -77
View File
@@ -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 <Alexander.Frink@Uni-Mainz.DE>
* Parts of this file are based on the kernel driver by
* Alexander Frink <Alexander.Frink@Uni-Mainz.DE>
*
* This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package.
*
* Copyright (c) 2001 Manuel Stahl <mythos@xmythos.de>
*
* 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);
+17 -12
View File
@@ -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 <Alexander.Frink@Uni-Mainz.DE>
*
* Parts of this file are based on the kernel driver by
* Alexander Frink <Alexander.Frink@Uni-Mainz.DE>
*
* 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,