1
/* $Id: drv_Sample.c 975 2009-01-18 11:16:20Z michael $
2
* $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/drv_Sample.c $
4
* Shuttle SG33G5M VFD lcd4linux driver
6
* Copyright (C) 2009 Matthieu Crapet <mcrapet@gmail.com>
7
* based on the USBLCD driver.
9
* Shuttle SG33G5M VFD (20x1 character display. Each character cell is 5x8 pixels)
10
* - The display is driven by Princeton Technologies PT6314 VFD controller
11
* - Cypress CY7C63723C (receives USB commands and talk to VFD controller)
13
* LCD "prococol" : each message has a length of 8 bytes
14
* - 1 nibble: command (0x1, 0x3, 0x7, 0x9, 0xD)
15
* - 0x1 : clear text and icons (len=1)
16
* - 0x7 : icons (len=4)
17
* - 0x9 : text (len=7)
18
* - 0xD : set clock data (len=7)
19
* - 0x3 : display clock (internal feature) (len=1)
20
* - 1 nibble: message length (0-7)
21
* - 7 bytes : message data
23
* This file is part of LCD4Linux.
25
* LCD4Linux is free software; you can redistribute it and/or modify
26
* it under the terms of the GNU General Public License as published by
27
* the Free Software Foundation; either version 2, or (at your option)
30
* LCD4Linux is distributed in the hope that it will be useful,
31
* but WITHOUT ANY WARRANTY; without even the implied warranty of
32
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33
* GNU General Public License for more details.
35
* You should have received a copy of the GNU General Public License
36
* along with this program; if not, write to the Free Software
37
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
45
* struct DRIVER drv_ShuttleVFD
60
#error "ShuttleVFD: libusb required"
69
#include "widget_text.h"
70
#include "widget_bar.h" // for DIRECTION
72
#include "drv_generic_text.h"
73
#include "drv_generic_gpio.h"
77
* Some hardware definitions
80
#define SHUTTLE_VFD_VENDOR_ID 0x051C
81
#define SHUTTLE_VFD_PRODUCT_ID1 0x0003
82
#define SHUTTLE_VFD_PRODUCT_ID2 0x0005 // IR-receiver included
83
#define SHUTTLE_VFD_INTERFACE_NUM 1
85
// VFD physical dimensions
86
#define SHUTTLE_VFD_WIDTH 20
87
#define SHUTTLE_VFD_HEIGHT 1
89
// VFD USB control message
90
#define SHUTTLE_VFD_PACKET_SIZE 8
91
#define SHUTTLE_VFD_DATA_SIZE (SHUTTLE_VFD_PACKET_SIZE-1)
92
#define SHUTTLE_VFD_SUCCESS_SLEEP_USEC 25600
95
/* Global static data */
96
static char Name[] = "ShuttleVFD";
97
static usb_dev_handle *lcd;
98
static unsigned char buffer[SHUTTLE_VFD_PACKET_SIZE];
100
/* Issues with the display module:
101
* - Can't set cursor position. Must save full buffer here.
102
* - Can't get icons status (on or off). Must save status here.
103
* - Clear command also clear text AND icons.
105
static unsigned char fb[SHUTTLE_VFD_WIDTH * SHUTTLE_VFD_HEIGHT];
106
static unsigned icons;
109
/****************************************/
110
/*** hardware dependant functions ***/
111
/****************************************/
113
/* look for device on USB bus */
114
static int drv_ShuttleVFD_open(void)
117
struct usb_device *dev;
119
int vendor_id = SHUTTLE_VFD_VENDOR_ID;
120
int interface = SHUTTLE_VFD_INTERFACE_NUM;
128
for (bus = usb_get_busses(); bus != NULL; bus = bus->next) {
129
for (dev = bus->devices; dev != NULL; dev = dev->next) {
130
if (dev->descriptor.idVendor == vendor_id && ((dev->descriptor.idProduct == SHUTTLE_VFD_PRODUCT_ID1) ||
131
(dev->descriptor.idProduct == SHUTTLE_VFD_PRODUCT_ID2))) {
133
unsigned int v = dev->descriptor.bcdDevice;
135
info("%s: found ShuttleVFD V%1d%1d.%1d%1d on bus %s device %s", Name,
136
(v & 0xF000) >> 12, (v & 0xF00) >> 8, (v & 0xF0) >> 4, (v & 0xF), bus->dirname, dev->filename);
144
if (usb_claim_interface(lcd, interface) < 0) {
146
error("%s: usb_claim_interface() failed!", Name);
147
error("%s: root permissions maybe required?", Name);
151
error("%s: could not find ShuttleVFD", Name);
159
static int drv_ShuttleVFD_close(void)
161
int interface = SHUTTLE_VFD_INTERFACE_NUM;
163
usb_release_interface(lcd, interface);
169
static void drv_ShuttleVFD_send(unsigned char packet[SHUTTLE_VFD_PACKET_SIZE])
171
if (usb_control_msg(lcd, 0x21, // requesttype
175
(char *) packet, SHUTTLE_VFD_PACKET_SIZE, 100) == SHUTTLE_VFD_PACKET_SIZE) {
177
udelay(SHUTTLE_VFD_SUCCESS_SLEEP_USEC);
179
debug("usb_control_msg failed");
184
/* Clear full display and icons. */
185
static void drv_ShuttleVFD_clear(void)
187
// Update local framebuffer mirror
188
memset(fb, ' ', SHUTTLE_VFD_HEIGHT * SHUTTLE_VFD_WIDTH);
190
buffer[0] = (1 << 4) + 1;
192
drv_ShuttleVFD_send(buffer);
196
static void drv_ShuttleVFD_reset_cursor(void)
198
buffer[0] = (1 << 4) + 1;
200
drv_ShuttleVFD_send(buffer);
204
/* text mode displays only */
205
static void drv_ShuttleVFD_write(const int row, const int col, const char *data, int len)
210
// Update local framebuffer mirror
211
memcpy(fb + (row * SHUTTLE_VFD_WIDTH) + col, data, len);
214
len = SHUTTLE_VFD_WIDTH;
216
drv_ShuttleVFD_reset_cursor();
220
buffer[0] = (9 << 4) + 7;
222
buffer[0] = (9 << 4) + len;
224
for (i = 0; i < 7 && len--; i++) {
225
buffer[i + 1] = *p++;
228
drv_ShuttleVFD_send(buffer);
233
static void drv_ShuttleVFD_defchar(const int ascii, const unsigned char *matrix)
236
debug("%s: not available (ascii=%d)", Name, ascii);
240
static int drv_ShuttleVFD_start(const char *section)
244
port = cfg_get(section, "Port", NULL);
246
if (port == NULL || *port == '\0') {
247
error("%s: no '%s.Port' entry from %s", Name, section, cfg_source());
251
if (strcasecmp(port, "libusb") != 0) {
252
error("%s: libusb expected", Name);
253
error("%s: compile lcd4linux with libusb support!", Name);
257
DROWS = SHUTTLE_VFD_HEIGHT;
258
DCOLS = SHUTTLE_VFD_WIDTH;
260
/* open communication with the display */
261
if (drv_ShuttleVFD_open() < 0) {
265
drv_ShuttleVFD_clear(); /* clear display */
270
/* VFD Icons. Add +1 in lcd4linux.conf (GPO1..GPIO27)
292
static int drv_ShuttleVFD_icons_set(const int num, const int val)
296
if (num < 0 || num >= 27) {
297
info("%s: num %d out of range (1..27)", Name, num);
300
// Special case for volume (icon n°16)
302
value = (num - 15 + 1) << 15;
311
buffer[0] = (7 << 4) + 4;
312
buffer[1] = (value >> 15) & 0x1F;
313
buffer[2] = (value >> 10) & 0x1F;
314
buffer[3] = (value >> 5) & 0x1F;
315
buffer[4] = value & 0x1F; // each data byte is stored on 5 bits
316
drv_ShuttleVFD_send(buffer);
322
/****************************************/
324
/****************************************/
329
/****************************************/
330
/*** widget callbacks ***/
331
/****************************************/
333
/* using drv_generic_text_draw(W) */
334
/* using drv_generic_gpio_draw(W) */
337
/****************************************/
338
/*** exported functions ***/
339
/****************************************/
342
/* supported Shuttle models */
343
int drv_ShuttleVFD_list(void)
345
printf("Shuttle SG33G5M, Shuttle PF27 upgrade kit");
350
/* initialize driver & text display */
351
int drv_ShuttleVFD_init(const char *section, const int quiet)
356
info("%s: %s", Name, "$Rev: 975 $");
358
/* display preferences */
359
XRES = 5; /* pixel width of one char */
360
YRES = 8; /* pixel height of one char */
361
CHARS = 0; /* number of user-defineable characters */
362
CHAR0 = 0; /* ASCII of first user-defineable char */
363
GOTO_COST = 2; /* number of bytes a goto command requires */
364
GPOS = 15 + 12; /* Fancy icons on top of display */
366
/* real worker functions */
367
drv_generic_text_real_write = drv_ShuttleVFD_write;
368
drv_generic_text_real_defchar = drv_ShuttleVFD_defchar;
369
drv_generic_gpio_real_set = drv_ShuttleVFD_icons_set;
372
if ((ret = drv_ShuttleVFD_start(section)) != 0)
377
qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, DCOLS, DROWS);
378
if (drv_generic_text_greet(buffer, "Shuttle")) {
380
drv_ShuttleVFD_clear();
384
/* initialize generic text driver */
385
if ((ret = drv_generic_text_init(section, Name)) != 0)
388
/* initialize generic GPIO driver */
389
if ((ret = drv_generic_gpio_init(section, Name)) != 0)
392
/* register text widget */
394
wc.draw = drv_generic_text_draw;
395
widget_register(&wc);
401
/* close driver & text display */
402
int drv_ShuttleVFD_quit(const int quiet)
404
info("%s: shutting down.", Name);
407
drv_ShuttleVFD_clear();
411
drv_generic_text_greet("goodbye!", NULL);
414
drv_generic_text_quit();
415
drv_generic_gpio_quit();
417
debug("closing connection");
418
drv_ShuttleVFD_close();
424
DRIVER drv_ShuttleVFD = {
426
.list = drv_ShuttleVFD_list,
427
.init = drv_ShuttleVFD_init,
428
.quit = drv_ShuttleVFD_quit,