From 9dcabf8ce54e40f917ffec90275b727832e064ab Mon Sep 17 00:00:00 2001 From: mmdolze Date: Fri, 9 Sep 2011 18:41:15 +0000 Subject: [PATCH] Step 1 to introduce the glcd driver: Refactor T6963 command set and low-level I/O routines into a separate file. --- server/drivers/Makefile.am | 2 +- server/drivers/t6963.c | 307 +++++++++++-------------------------- server/drivers/t6963.h | 88 +---------- server/drivers/t6963_low.c | 208 +++++++++++++++++++++++++ server/drivers/t6963_low.h | 112 ++++++++++++++ 5 files changed, 412 insertions(+), 305 deletions(-) create mode 100644 server/drivers/t6963_low.c create mode 100644 server/drivers/t6963_low.h diff --git a/server/drivers/Makefile.am b/server/drivers/Makefile.am index 3cca717..3930826 100644 --- a/server/drivers/Makefile.am +++ b/server/drivers/Makefile.am @@ -119,7 +119,7 @@ sli_SOURCES = lcd.h lcd_lib.h wirz-sli.h wirz-sli.c report.h stv5730_SOURCES = lcd.h stv5730.c stv5730.h report.h SureElec_SOURCES = lcd.h lcd_lib.h SureElec.c SureElec.h report.h adv_bignum.h svga_SOURCES = lcd.h svgalib_drv.c svgalib_drv.h report.h -t6963_SOURCES = lcd.h lcd_lib.h t6963.c t6963.h glcd_font5x8.h report.h +t6963_SOURCES = lcd.h lcd_lib.h t6963.c t6963.h glcd_font5x8.h report.h t6963_low.h t6963_low.c text_SOURCES = lcd.h text.h text.c report.h tyan_SOURCES = lcd.h lcd_lib.h tyan_lcdm.h tyan_lcdm.c report.h adv_bignum.h ula200_SOURCES = lcd.h adv_bignum.h ula200.h ula200.c report.h diff --git a/server/drivers/t6963.c b/server/drivers/t6963.c index 63b4f34..5c3d8ec 100644 --- a/server/drivers/t6963.c +++ b/server/drivers/t6963.c @@ -2,29 +2,12 @@ * 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 - * + 5V --- FS (6x8 font) - *\endverbatim - * - * \note The driver does not provide cellwidth / cellheight API functions. - * Thus the default cell size of 5x8 is assumed by server core! This - * works fine with the 5x8 font loaded into the controller. + * \note The display must be wired to use 6x8 font. Check with your datasheet. */ /*- * Base driver module for Toshiba T6963 based LCD displays. * - * Parts of this file are based on the kernel driver by - * Alexander Frink - * * Copyright (c) 2001 Manuel Stahl * 2011 Markus Dolze * @@ -44,29 +27,19 @@ #include "lcd.h" #include "t6963.h" #include "glcd_font5x8.h" -#include "timing.h" #include "report.h" #include "lcd_lib.h" -#include "port.h" -#include "lpt-port.h" - -/* Define the wiring for display */ -#define nWR nSTRB -#define nRD nSEL -#define nCE nLF -#define T_CMD INIT -#define T_DATA 0x00 /* ~INIT didn't work here */ +#include "t6963_low.h" /** private data for the \c t6963 driver */ typedef struct t6963_private_data { - u16 port; - u8 *display_buffer1; + unsigned char *display_buffer1; - int px_width, px_heigth; /* size in pixels */ + int px_width, px_height; /* size in pixels */ int width, height; /* size in characters */ - int bytes_per_line; /* memory allocated per line */ - short bidirectLPT; - short delayBus; + u16 bytes_per_line; /* memory allocated per line */ + + T6963_port *port_config; } PrivateData; /* Vars for the server core */ @@ -75,6 +48,16 @@ MODULE_EXPORT int stay_in_foreground = 0; MODULE_EXPORT int supports_multiple = 0; MODULE_EXPORT char *symbol_prefix = "t6963_"; +/* + * Width and height of one character cell including spacing. Thus it is 6x8 + * not 5x7! + */ +#define DEFAULT_CELL_WIDTH 6 +#define DEFAULT_CELL_HEIGHT 8 +#define DEFAULT_SIZE "128x64" +#define DEFAULT_PORT 0x378 + + /** * API: Initialize the driver. */ @@ -107,7 +90,7 @@ t6963_init(Driver *drvthis) sscanf(DEFAULT_SIZE, "%dx%d", &w, &h); } p->px_width = w; - p->px_heigth = h; + p->px_height = h; /* * Calculate the size in characters and the number of actual bytes @@ -117,32 +100,32 @@ t6963_init(Driver *drvthis) */ p->width = p->px_width / DEFAULT_CELL_WIDTH; p->bytes_per_line = (p->px_width % DEFAULT_CELL_WIDTH) ? p->width + 1 : p->width; - p->height = p->px_heigth / DEFAULT_CELL_HEIGHT; + p->height = p->px_height / DEFAULT_CELL_HEIGHT; + + /* Allocate port configuration structure */ + if ((p->port_config = (T6963_port *) calloc(1, sizeof(T6963_port))) == NULL) { + report(RPT_ERR, "%s: error mallocing", drvthis->name); + return -1; + } /* 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; + p->port_config->port = drvthis->config_get_int(drvthis->name, "Port", 0, DEFAULT_PORT); + if ((p->port_config->port < 0x200) || (p->port_config->port > 0x400)) { + p->port_config->port = DEFAULT_PORT; report(RPT_WARNING, "%s: Port value must be between 0x200 and 0x400. Using default 0x%03X", drvthis->name, DEFAULT_PORT); } /* Use bi-directional mode of LPT port? Default: yes */ - p->bidirectLPT = drvthis->config_get_bool(drvthis->name, "bidirectional", 0, 1); + p->port_config->bidirectLPT = drvthis->config_get_bool(drvthis->name, "bidirectional", 0, 1); /* Additional delay necessary? Default: no */ - p->delayBus = drvthis->config_get_bool(drvthis->name, "delaybus", 0, 0); + p->port_config->delayBus = drvthis->config_get_bool(drvthis->name, "delaybus", 0, 0); - /* Get permission to parallel port */ - debug(RPT_DEBUG, "T6963: Getting permission to parallel port %d...", p->port); - 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; - } - - /* Set up timing */ - if (timing_init() == -1) { - report(RPT_ERR, "%s: timing_init() failed (%s)", drvthis->name, strerror(errno)); + /* Initialize port and timing */ + debug(RPT_DEBUG, "T6963: Initializing parallel port at 0x%03X", p->port_config->port); + if (t6963_low_init(p->port_config) == -1) { + report(RPT_ERR, "%s: Error initializing port 0x%03X: %s", + drvthis->name, p->port_config->port, strerror(errno)); return -1; } @@ -156,11 +139,11 @@ t6963_init(Driver *drvthis) memset(p->display_buffer1, ' ', p->bytes_per_line * p->height); /* ------------------- I N I T I A L I Z A T I O N --------------- */ - if (p->bidirectLPT == 1) { + if (p->port_config->bidirectLPT == 1) { debug(RPT_INFO, "T6963: Testing bidirectional mode..."); - if (t6963_low_dsp_ready(drvthis, 0x03) == -1) { + if (t6963_low_dsp_ready(p->port_config, 0x03) == -1) { report(RPT_WARNING, "T6963: Bidirectional mode not working (now disabled)"); - p->bidirectLPT = 0; + p->port_config->bidirectLPT = 0; } else { debug(RPT_INFO, "T6963: working!"); @@ -170,15 +153,15 @@ t6963_init(Driver *drvthis) debug(RPT_INFO, "T6963: Sending init to display..."); /* Set text and graphic addresses */ - t6963_low_command_word(drvthis, SET_GRAPHIC_HOME_ADDRESS, GRAPHIC_BASE); - t6963_low_command_word(drvthis, SET_GRAPHIC_AREA, p->bytes_per_line); - t6963_low_command_word(drvthis, SET_TEXT_HOME_ADDRESS, TEXT_BASE); - t6963_low_command_word(drvthis, SET_TEXT_AREA, p->bytes_per_line); + t6963_low_command_word(p->port_config, SET_GRAPHIC_HOME_ADDRESS, GRAPHIC_BASE); + t6963_low_command_word(p->port_config, SET_GRAPHIC_AREA, p->bytes_per_line); + t6963_low_command_word(p->port_config, SET_TEXT_HOME_ADDRESS, TEXT_BASE); + t6963_low_command_word(p->port_config, SET_TEXT_AREA, p->bytes_per_line); /* Enable external character generator */ - t6963_low_command(drvthis, SET_MODE | OR_MODE | EXTERNAL_CG); + t6963_low_command(p->port_config, SET_MODE | OR_MODE | EXTERNAL_CG); /* Set address of CG RAM address start */ - t6963_low_command_word(drvthis, SET_OFFSET_REGISTER, CHARGEN_BASE >> 11); + t6963_low_command_word(p->port_config, SET_OFFSET_REGISTER, CHARGEN_BASE >> 11); /* Load font data */ t6963_set_nchar(drvthis, 0, 256); @@ -190,7 +173,7 @@ t6963_init(Driver *drvthis) t6963_flush(drvthis); /* Turn on display, text on, graphics off, cursor off */ - t6963_low_command(drvthis, SET_DISPLAY_MODE | TEXT_ON); + t6963_low_command(p->port_config, SET_DISPLAY_MODE | TEXT_ON); debug(RPT_INFO, "%s: init() done", drvthis->name); @@ -208,7 +191,10 @@ t6963_close(Driver *drvthis) debug(RPT_INFO, "Shutting down!"); if (p != NULL) { - port_deny_multiple(p->port, 3); + if (p->port_config != NULL) { + t6963_low_close(p->port_config); + free(p->port_config); + } if (p->display_buffer1 != NULL) free(p->display_buffer1); @@ -240,6 +226,30 @@ t6963_height(Driver *drvthis) return p->height; } +/** + * API: Return the width of a character in pixels. + * \note This function actually returns the width of one character (as defined + * in the font, not the actual cell width. Otherwise bar graph + * calculations would take character spacing into account. + */ +MODULE_EXPORT int +t6963_cellwidth(Driver *drvthis) +{ + return GLCD_FONT_WIDTH; +} + +/** + * API: Return the height of a character in pixels. + * \note As with t6963_cellwidth this function returns the height of one + * character as defined by the font instead of the cell size (which is + * the same anyway). + */ +MODULE_EXPORT int +t6963_cellheight(Driver *drvthis) +{ + return GLCD_FONT_HEIGHT; +} + /** * API: Clears the LCD screen (clear display buffer) */ @@ -261,16 +271,16 @@ static void t6963_graphic_clear(Driver *drvthis) { PrivateData *p = drvthis->private_data; - int num = p->bytes_per_line * p->px_heigth; + int num = p->bytes_per_line * p->px_height; int i; debug(RPT_DEBUG, "Clearing Graphic %d bytes", num); - t6963_low_command_word(drvthis, SET_ADDRESS_POINTER, GRAPHIC_BASE); - t6963_low_command(drvthis, AUTO_WRITE); + t6963_low_command_word(p->port_config, SET_ADDRESS_POINTER, GRAPHIC_BASE); + t6963_low_command(p->port_config, AUTO_WRITE); for (i = 0; i < num; i++) - t6963_low_auto_write(drvthis, 0); - t6963_low_command(drvthis, AUTO_RESET); + t6963_low_auto_write(p->port_config, 0); + t6963_low_command(p->port_config, AUTO_RESET); } /** @@ -284,8 +294,8 @@ t6963_flush(Driver *drvthis) debug(RPT_DEBUG, "Flushing %d x %d", p->width, p->height); - t6963_low_command_word(drvthis, SET_ADDRESS_POINTER, TEXT_BASE); - t6963_low_command(drvthis, AUTO_WRITE); + t6963_low_command_word(p->port_config, SET_ADDRESS_POINTER, TEXT_BASE); + t6963_low_command(p->port_config, AUTO_WRITE); /* * Note: There used to be a double buffering algorithm here that @@ -297,16 +307,16 @@ t6963_flush(Driver *drvthis) for (r = 0; r < p->height; r++) { line_address = r * p->width; for (c = 0; c < p->width; c++) { - t6963_low_auto_write(drvthis, p->display_buffer1[line_address + c]); + t6963_low_auto_write(p->port_config, p->display_buffer1[line_address + c]); } /* * If width is not identical with bytes_per_line there must be * one additional empty column on the right. */ if (p->width != p->bytes_per_line) - t6963_low_auto_write(drvthis, ' '); + t6963_low_auto_write(p->port_config, ' '); } - t6963_low_command(drvthis, AUTO_RESET); + t6963_low_command(p->port_config, AUTO_RESET); } /** @@ -371,18 +381,19 @@ t6963_set_nchar(Driver *drvthis, int n, int num) int chr, row; char letter; unsigned char mask = (1 << GLCD_FONT_WIDTH) - 1; + PrivateData *p = drvthis->private_data; debug(RPT_DEBUG, "Loading font"); - t6963_low_command_word(drvthis, SET_ADDRESS_POINTER, CHARGEN_BASE + n * DEFAULT_CELL_HEIGHT); - t6963_low_command(drvthis, AUTO_WRITE); + t6963_low_command_word(p->port_config, SET_ADDRESS_POINTER, CHARGEN_BASE + n * DEFAULT_CELL_HEIGHT); + t6963_low_command(p->port_config, AUTO_WRITE); for (chr = 0; chr < num; chr++) { for (row = 0; row < DEFAULT_CELL_HEIGHT; row++) { letter = glcd_iso8859_1[chr][row] & mask; - t6963_low_auto_write(drvthis, letter); + t6963_low_auto_write(p->port_config, letter); } } - t6963_low_command(drvthis, AUTO_RESET); + t6963_low_command(p->port_config, AUTO_RESET); } /** @@ -405,7 +416,7 @@ t6963_set_char(Driver *drvthis, int n, unsigned char *dat) MODULE_EXPORT void t6963_vbar(Driver *drvthis, int x, int y, int len, int promille, int options) { - lib_vbar_static(drvthis, x, y, len, promille, options, DEFAULT_CELL_HEIGHT, 0x90); + lib_vbar_static(drvthis, x, y, len, promille, options, GLCD_FONT_HEIGHT, 0x90); } /** @@ -442,144 +453,4 @@ t6963_icon(Driver *drvthis, int x, int y, int icon) return (glcd_icon5x8(drvthis, x, y, icon)); } - -/** - * Check display status. - * \param drvthis Pointer to driver structure. - * \param sta Bitmap of expected STA flags - * \return 0 on success, -1 if ready could not be read - */ -static inline int -t6963_low_dsp_ready(Driver *drvthis, u8 sta) -{ - PrivateData *p = drvthis->private_data; - int portcontrol = 0; - - if (p->bidirectLPT == 1) { - int val; - int loop = 0; - - do { - portcontrol = T_CMD | nWR | nRD | nCE; - port_out(T6963_CONTROL_PORT(p->port), portcontrol ^ OUTMASK); - /* lower nRD, nCE, set bi-directional mode */ - portcontrol = T_CMD | nWR | ENBI; - port_out(T6963_CONTROL_PORT(p->port), portcontrol ^ OUTMASK); - /* possible wait required here: tACC = 150 ns max */ - if (p->delayBus) - timing_uPause(1); - val = port_in(T6963_DATA_PORT(p->port)); - portcontrol = T_CMD | nWR | nRD | nCE; - port_out(T6963_CONTROL_PORT(p->port), portcontrol ^ OUTMASK); - loop++; - if (loop == 100) { - report(RPT_WARNING, "Ready check failed, STA=0x%02x", val); - return -1; - } - } while ((val & sta) != sta); - } - else { - portcontrol = T_CMD | nWR | nRD | nCE; - port_out(T6963_CONTROL_PORT(p->port), portcontrol ^ OUTMASK); - portcontrol = T_CMD | nWR; - port_out(T6963_CONTROL_PORT(p->port), portcontrol ^ OUTMASK); - timing_uPause(150); - portcontrol = T_CMD | nWR | nRD | nCE; - port_out(T6963_CONTROL_PORT(p->port), portcontrol ^ OUTMASK); - } - - return 0; -} - - -/** - * Write a single command / or byte to the parallel port. - * \param drvthis Pointer to driver structure. - * \param type Command or Data - * \param byte Data byte. - */ -static inline void -t6963_low_send(Driver *drvthis, u8 type, u8 byte) -{ - PrivateData *p = drvthis->private_data; - int portcontrol = 0; - - portcontrol = type | nWR | nRD | nCE; - port_out(T6963_CONTROL_PORT(p->port), portcontrol ^ OUTMASK); - port_out(T6963_DATA_PORT(p->port), byte); - portcontrol = type | nRD; /* lower nWR, nCE */ - port_out(T6963_CONTROL_PORT(p->port), portcontrol ^ OUTMASK); - /* possible wait required here: tWR */ - if (p->delayBus) - timing_uPause(1); - portcontrol = type | nWR | nRD | nCE; - port_out(T6963_CONTROL_PORT(p->port), portcontrol ^ OUTMASK); -} - - -/** - * Send one data byte to the display. - * \param drvthis Pointer to driver structure. - * \param byte Data byte. - */ -static void -t6963_low_data(Driver *drvthis, u8 byte) -{ - t6963_low_dsp_ready(drvthis, STA0|STA1); - t6963_low_send(drvthis, T_DATA, byte); -} - -/** - * Send one command byte to the display. - * \param drvthis Pointer to driver structure. - * \param byte Command byte. - */ -static void -t6963_low_command(Driver *drvthis, u8 byte) -{ - t6963_low_dsp_ready(drvthis, STA0|STA1); - t6963_low_send(drvthis, T_CMD, byte); -} - -/** - * Write one byte of data to display in AUTO mode (needs a different ready - * check). - * \param drvthis Pointer to driver structure. - * \param byte Data byte. - */ -static void -t6963_low_auto_write(Driver *drvthis, u8 byte) -{ - t6963_low_dsp_ready(drvthis, STA3); - t6963_low_send(drvthis, T_DATA, byte); -} - -/** - * 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. - */ -static void -t6963_low_command_byte(Driver *drvthis, u8 cmd, u8 byte) -{ - t6963_low_data(drvthis, byte); - 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) - */ -static void -t6963_low_command_word(Driver *drvthis, u8 cmd, u16 word) -{ - t6963_low_data(drvthis, word & 0xFF); - t6963_low_data(drvthis, (word >> 8) & 0xFF); - t6963_low_command(drvthis, cmd); -} - /* EOF */ diff --git a/server/drivers/t6963.h b/server/drivers/t6963.h index dda6ef1..885cdd8 100644 --- a/server/drivers/t6963.h +++ b/server/drivers/t6963.h @@ -1,9 +1,6 @@ /*- * Base driver module for Toshiba T6963 based LCD displays. * - * Parts of this file are based on the kernel driver by - * Alexander Frink - * * Copyright (c) 2001 Manuel Stahl * 2011 Markus Dolze * @@ -14,87 +11,13 @@ #ifndef T6963_H #define T6963_H -#define DEFAULT_CELL_WIDTH 6 -#define DEFAULT_CELL_HEIGHT 8 -#define DEFAULT_SIZE "128x64" -#define DEFAULT_PORT 0x378 - -/* - * These are the maximum values the controller supports in single-scan - * setting (note that heigth of 128 is possible with dual-scan setting, too. - * This will not work with this driver, but there is no possibility to check - * this in software. - */ -#define T6963_MAX_WIDTH 80 * DEFAULT_CELL_WIDTH -#define T6963_MAX_HEIGHT 128 - -/* RAM layout base addresses (suitable for 8 KB RAM) */ -#define TEXT_BASE 0x0000 /* 1K, fine for 40x16 or 80x8 */ -#define GRAPHIC_BASE 0x0400 /* 5K, fine for 240x128 */ -#define CHARGEN_BASE 0x1800 /* 2K, required for 256 CC */ - -/* 'Registers setting' commands */ -#define SET_CURSOR_POINTER 0x21 -#define SET_OFFSET_REGISTER 0x22 -#define SET_ADDRESS_POINTER 0x24 - -/* '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 - -/* '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 - -/* '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 - -/* 'Cursor pattern select' command */ -#define SET_CURSOR_PATTERN 0xa0 - -/* '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 - -/* 'Data auto read/write' commands */ -#define AUTO_WRITE 0xb0 -#define AUTO_READ 0xb1 -#define AUTO_RESET 0xb2 - -/* 'Status read' anwer codes */ -#define STA0 0x01 -#define STA1 0x02 -#define STA3 0x08 - -/* 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) - -/* Data types */ -typedef unsigned short u16; -typedef unsigned char u8; - /* API functions */ MODULE_EXPORT int t6963_init (Driver *drvthis); MODULE_EXPORT void t6963_close (Driver *drvthis); MODULE_EXPORT int t6963_width (Driver *drvthis); MODULE_EXPORT int t6963_height (Driver *drvthis); +MODULE_EXPORT int t6963_cellwidth(Driver *drvthis); +MODULE_EXPORT int t6963_cellheight(Driver *drvthis); 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[]); @@ -108,12 +31,5 @@ MODULE_EXPORT void t6963_set_char (Driver *drvthis, int n, unsigned char *dat); /* Internal functions */ static void t6963_graphic_clear(Driver *drvthis); static void t6963_set_nchar(Driver *drvthis, int n, int num); -static inline int t6963_low_dsp_ready(Driver *drvthis, u8 sta); -static void t6963_low_data(Driver *drvthis, u8 byte); -static void t6963_low_auto_write(Driver *drvthis, u8 byte); -static void t6963_low_command(Driver *drvthis, u8 byte); -static void t6963_low_command_byte(Driver *drvthis, u8 cmd, u8 byte); -static void t6963_low_command_word(Driver *drvthis, u8 cmd, u16 word); -static inline void t6963_low_send(Driver * drvthis, u8 type, u8 byte); #endif diff --git a/server/drivers/t6963_low.c b/server/drivers/t6963_low.c new file mode 100644 index 0000000..7b08442 --- /dev/null +++ b/server/drivers/t6963_low.c @@ -0,0 +1,208 @@ +/** \file server/drivers/t6963_io.c + * Low level output routines for Toshiba T6963 based LCD displays connected + * to a parallel port. + * + * 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 + * + 5V --- FS (6x8 font, used for t6963 driver) + * GND --- FS (8x8 font, used for glcd connection type) + *\endverbatim + * + */ + +/*- + * Parts of this file are based on the kernel driver by + * Alexander Frink + * + * Copyright (c) 2001 Manuel Stahl + * 2011 Markus Dolze + * + * This file is released under the GNU General Public License. Refer to the + * COPYING file distributed with this package. + */ + +#include + +#include "port.h" +#include "lpt-port.h" +#include "timing.h" +#include "t6963_low.h" + +/* Define the wiring */ +#define nWR nSTRB +#define nRD nSEL +#define nCE nLF +#define T_CMD INIT +#define T_DATA 0x00 /* ~INIT didn't work here */ + + +/** + * Acquires access to parallel port and initializes timing. The parallel port + * must be an I/O-address between 0x200 and 0x300. + * \param p Pointer to port configuration. + * \return 0 on success, -1 if an error occured. + */ +int +t6963_low_init(T6963_port *p) { + if ((p->port < 0x200) || (p->port > 0x400)) + return -1; + + if (port_access_multiple(p->port, 3)) + return -1; + + if (timing_init() == -1) + return -1; + + return 0; +} + + +/** + * Releases access to the parallel port. + * \param p Pointer to port configuration. + */ +void +t6963_low_close(T6963_port *p) { + if ((p->port >= 0x200) && (p->port <= 0x400)) + port_deny_multiple(p->port, 3); +} + +/** + * Send one data byte to the display. + * \param p Pointer to port configuration. + * \param byte Data byte. + */ +void +t6963_low_data(T6963_port *p, u8 byte) +{ + t6963_low_dsp_ready(p, STA0|STA1); + t6963_low_send(p, T_DATA, byte); +} + +/** + * Send one command byte to the display. + * \param p Pointer to port configuration. + * \param byte Command byte. + */ +void +t6963_low_command(T6963_port *p, u8 byte) +{ + t6963_low_dsp_ready(p, STA0|STA1); + t6963_low_send(p, T_CMD, byte); +} + +/** + * Write one byte of data to display in AUTO mode (needs a different ready + * check). + * \param p Pointer to port configuration. + * \param byte Data byte. + */ +void +t6963_low_auto_write(T6963_port *p, u8 byte) +{ + t6963_low_dsp_ready(p, STA3); + t6963_low_send(p, T_DATA, byte); +} + +/** + * Send one byte of data followed by one command byte to the display. + * \param p Pointer to port configuration. + * \param cmd Command byte. + * \param byte Data value. + */ +void +t6963_low_command_byte(T6963_port *p, u8 cmd, u8 byte) +{ + t6963_low_data(p, byte); + t6963_low_command(p, cmd); +} + +/** + * Send one word (two bytes) of data followed by one command byte to the + * display. Low byte is output first. + * \param p Pointer to port configuration. + * \param cmd Command byte. + * \param word Data value (2 bytes) + */ +void +t6963_low_command_word(T6963_port *p, u8 cmd, u16 word) +{ + t6963_low_data(p, word & 0xFF); + t6963_low_data(p, (word >> 8) & 0xFF); + t6963_low_command(p, cmd); +} + +/** + * Check display status. + * \param p Pointer to port configuration. + * \param sta Bitmap of expected STA flags + * \return 0 on success, -1 if ready could not be read + */ +inline int +t6963_low_dsp_ready(T6963_port *p, u8 sta) +{ + int portcontrol = 0; + + if (p->bidirectLPT == 1) { + int val; + int loop = 0; + + do { + portcontrol = T_CMD | nWR | nRD | nCE; + port_out(T6963_CONTROL_PORT(p->port), portcontrol ^ OUTMASK); + /* lower nRD, nCE, set bi-directional mode */ + portcontrol = T_CMD | nWR | ENBI; + port_out(T6963_CONTROL_PORT(p->port), portcontrol ^ OUTMASK); + /* possible wait required here: tACC = 150 ns max */ + if (p->delayBus) + timing_uPause(1); + val = port_in(T6963_DATA_PORT(p->port)); + portcontrol = T_CMD | nWR | nRD | nCE; + port_out(T6963_CONTROL_PORT(p->port), portcontrol ^ OUTMASK); + loop++; + if (loop == 100) + return -1; + } while ((val & sta) != sta); + } + else { + portcontrol = T_CMD | nWR | nRD | nCE; + port_out(T6963_CONTROL_PORT(p->port), portcontrol ^ OUTMASK); + portcontrol = T_CMD | nWR; + port_out(T6963_CONTROL_PORT(p->port), portcontrol ^ OUTMASK); + timing_uPause(150); + portcontrol = T_CMD | nWR | nRD | nCE; + port_out(T6963_CONTROL_PORT(p->port), portcontrol ^ OUTMASK); + } + + return 0; +} + +/** + * Write a single command / or byte to the parallel port. + * \param p Pointer to port configuration. + * \param type Command or Data + * \param byte Data byte. + */ +inline void +t6963_low_send(T6963_port *p, u8 type, u8 byte) +{ + int portcontrol = 0; + + portcontrol = type | nWR | nRD | nCE; + port_out(T6963_CONTROL_PORT(p->port), portcontrol ^ OUTMASK); + port_out(T6963_DATA_PORT(p->port), byte); + portcontrol = type | nRD; /* lower nWR, nCE */ + port_out(T6963_CONTROL_PORT(p->port), portcontrol ^ OUTMASK); + /* possible wait required here: tWR */ + if (p->delayBus) + timing_uPause(1); + portcontrol = type | nWR | nRD | nCE; + port_out(T6963_CONTROL_PORT(p->port), portcontrol ^ OUTMASK); +} diff --git a/server/drivers/t6963_low.h b/server/drivers/t6963_low.h new file mode 100644 index 0000000..7c12987 --- /dev/null +++ b/server/drivers/t6963_low.h @@ -0,0 +1,112 @@ +/** \file server/drivers/t6963_io.h + * Command set for Toshiba T6963 based LCD displays. + * + * This header file defines the T6963 command set and various controller + * parameters like memory addresses. + */ + +/*- + * Base driver module for Toshiba T6963 based LCD displays. + * + * Parts of this file are based on the kernel driver by + * Alexander Frink + * + * Copyright (c) 2001 Manuel Stahl + * 2011 Markus Dolze + * + * This file is released under the GNU General Public License. Refer to the + * COPYING file distributed with this package. + */ + +#ifndef T6963_IO_H +#define T6963_IO_H + +/* + * These are the maximum values the controller supports in single-scan + * configuration with FontSelector (FS) = 8x8. Dual-scan configuration is + * not supported by this driver. + */ +#define T6963_MAX_WIDTH 640 +#define T6963_MAX_HEIGHT 128 + +/* RAM layout base addresses (suitable for 8 KB RAM) */ +#define TEXT_BASE 0x0000 /* 1K, fine for 40x16 or 80x8 */ +#define GRAPHIC_BASE 0x0400 /* 5K, fine for 240x128 */ +#define CHARGEN_BASE 0x1800 /* 2K, required for 256 CC */ + +/* 'Registers setting' commands */ +#define SET_CURSOR_POINTER 0x21 +#define SET_OFFSET_REGISTER 0x22 +#define SET_ADDRESS_POINTER 0x24 + +/* '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 + +/* '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 + +/* '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 + +/* 'Cursor pattern select' command */ +#define SET_CURSOR_PATTERN 0xa0 + +/* '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 + +/* 'Data auto read/write' commands */ +#define AUTO_WRITE 0xb0 +#define AUTO_READ 0xb1 +#define AUTO_RESET 0xb2 + +/* 'Status read' anwer codes */ +#define STA0 0x01 +#define STA1 0x02 +#define STA3 0x08 + +/* 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) + +/* Shorthand data types */ +typedef unsigned short u16; +typedef unsigned char u8; + +/** Configuration of parallel port */ +typedef struct t6963_port_config { + unsigned int port; + short bidirectLPT; + short delayBus; +} T6963_port; + +/* External usable functions */ +int t6963_low_init(T6963_port *p); +void t6963_low_close(T6963_port *p); +void t6963_low_data(T6963_port *p, u8 byte); +void t6963_low_auto_write(T6963_port *p, u8 byte); +void t6963_low_command(T6963_port *p, u8 byte); +void t6963_low_command_byte(T6963_port *p, u8 cmd, u8 byte); +void t6963_low_command_word(T6963_port *p, u8 cmd, u16 word); +inline int t6963_low_dsp_ready(T6963_port *p, u8 sta); +inline void t6963_low_send(T6963_port *p, u8 type, u8 byte); + +#endif