0.1.1
by Reinhard Tartler
Import upstream version 0.11.0~svn1143 |
1 |
/* $Id: drv_picoLCD.c 1143 2011-02-12 22:46:19Z mzuther $
|
2 |
* $URL: https://ssl.bulix.org/svn/lcd4linux/trunk/drv_picoLCD.c $
|
|
718
by Reinhard Tartler
import new upstream |
3 |
*
|
4 |
* driver for picoLCD displays from mini-box.com
|
|
5 |
*
|
|
0.1.1
by Reinhard Tartler
Import upstream version 0.11.0~svn1143 |
6 |
* Copyright (C) 2005 Michael Reinelt <michael@reinelt.co.at>
|
718
by Reinhard Tartler
import new upstream |
7 |
* Copyright (C) 2005, 2006, 2007 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
|
8 |
*
|
|
9 |
* Copyright (C) 2007 Nicu Pavel, Mini-Box.com <npavel@mini-box.com>
|
|
10 |
*
|
|
11 |
* This file is part of LCD4Linux.
|
|
12 |
*
|
|
13 |
* LCD4Linux is free software; you can redistribute it and/or modify
|
|
14 |
* it under the terms of the GNU General Public License as published by
|
|
15 |
* the Free Software Foundation; either version 2, or (at your option)
|
|
16 |
* any later version.
|
|
17 |
*
|
|
18 |
* LCD4Linux is distributed in the hope that it will be useful,
|
|
19 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
20 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
21 |
* GNU General Public License for more details.
|
|
22 |
*
|
|
23 |
* You should have received a copy of the GNU General Public License
|
|
24 |
* along with this program; if not, write to the Free Software
|
|
25 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
26 |
*
|
|
27 |
*/
|
|
28 |
||
29 |
/*
|
|
30 |
*
|
|
31 |
* exported fuctions:
|
|
32 |
*
|
|
33 |
* struct DRIVER drv_picoLCD
|
|
34 |
*
|
|
35 |
*/
|
|
36 |
||
37 |
#include "config.h" |
|
38 |
||
39 |
#include <stdlib.h> |
|
40 |
#include <stdio.h> |
|
41 |
#include <string.h> |
|
42 |
#include <errno.h> |
|
43 |
#include <unistd.h> |
|
44 |
#include <termios.h> |
|
45 |
#include <fcntl.h> |
|
46 |
#include <sys/ioctl.h> |
|
47 |
#include <sys/time.h> |
|
48 |
||
49 |
#include <usb.h> |
|
50 |
||
51 |
#include "debug.h" |
|
52 |
#include "cfg.h" |
|
53 |
#include "qprintf.h" |
|
54 |
#include "udelay.h" |
|
55 |
#include "plugin.h" |
|
56 |
#include "widget.h" |
|
57 |
#include "widget_text.h" |
|
58 |
#include "widget_icon.h" |
|
59 |
#include "widget_bar.h" |
|
60 |
#include "drv.h" |
|
61 |
#include "drv_generic_text.h" |
|
62 |
#include "drv_generic_gpio.h" |
|
63 |
#include "drv_generic_keypad.h" |
|
64 |
||
65 |
||
66 |
||
67 |
#define picoLCD_VENDOR 0x04d8
|
|
68 |
#define picoLCD_DEVICE 0x0002
|
|
69 |
||
70 |
static char Name[] = "picoLCD"; |
|
71 |
||
72 |
static unsigned int gpo = 0; |
|
73 |
||
74 |
static char *Buffer; |
|
75 |
static char *BufPtr; |
|
76 |
||
77 |
static usb_dev_handle *lcd; |
|
78 |
||
79 |
||
80 |
||
81 |
/****************************************/
|
|
82 |
/*** hardware dependant functions ***/
|
|
83 |
/****************************************/
|
|
84 |
||
85 |
static int drv_pL_open(void) |
|
86 |
{
|
|
87 |
struct usb_bus *busses, *bus; |
|
88 |
struct usb_device *dev; |
|
89 |
char driver[1024]; |
|
90 |
char product[1024]; |
|
91 |
char manufacturer[1024]; |
|
92 |
char serialnumber[1024]; |
|
93 |
int ret; |
|
94 |
||
95 |
lcd = NULL; |
|
96 |
||
97 |
info("%s: scanning for picoLCD...", Name); |
|
98 |
||
0.1.1
by Reinhard Tartler
Import upstream version 0.11.0~svn1143 |
99 |
usb_set_debug(0); |
718
by Reinhard Tartler
import new upstream |
100 |
|
101 |
usb_init(); |
|
102 |
usb_find_busses(); |
|
103 |
usb_find_devices(); |
|
104 |
busses = usb_get_busses(); |
|
105 |
||
106 |
for (bus = busses; bus; bus = bus->next) { |
|
107 |
for (dev = bus->devices; dev; dev = dev->next) { |
|
108 |
if ((dev->descriptor.idVendor == picoLCD_VENDOR) && (dev->descriptor.idProduct == picoLCD_DEVICE)) { |
|
109 |
||
110 |
info("%s: found picoLCD on bus %s device %s", Name, bus->dirname, dev->filename); |
|
111 |
||
112 |
lcd = usb_open(dev); |
|
113 |
||
114 |
ret = usb_get_driver_np(lcd, 0, driver, sizeof(driver)); |
|
115 |
||
116 |
if (ret == 0) { |
|
117 |
info("%s: interface 0 already claimed by '%s'", Name, driver); |
|
118 |
info("%s: attempting to detach driver...", Name); |
|
119 |
if (usb_detach_kernel_driver_np(lcd, 0) < 0) { |
|
120 |
error("%s: usb_detach_kernel_driver_np() failed!", Name); |
|
121 |
return -1; |
|
122 |
}
|
|
123 |
}
|
|
124 |
||
125 |
usb_set_configuration(lcd, 1); |
|
126 |
usleep(100); |
|
127 |
||
128 |
if (usb_claim_interface(lcd, 0) < 0) { |
|
129 |
error("%s: usb_claim_interface() failed!", Name); |
|
130 |
return -1; |
|
131 |
}
|
|
132 |
||
133 |
usb_set_altinterface(lcd, 0); |
|
134 |
||
135 |
usb_get_string_simple(lcd, dev->descriptor.iProduct, product, sizeof(product)); |
|
136 |
usb_get_string_simple(lcd, dev->descriptor.iManufacturer, manufacturer, sizeof(manufacturer)); |
|
137 |
usb_get_string_simple(lcd, dev->descriptor.iSerialNumber, serialnumber, sizeof(serialnumber)); |
|
138 |
||
139 |
info("%s: Manufacturer='%s' Product='%s' SerialNumber='%s'", Name, manufacturer, product, serialnumber); |
|
140 |
||
141 |
return 0; |
|
142 |
}
|
|
143 |
}
|
|
144 |
}
|
|
145 |
error("%s: could not find a picoLCD", Name); |
|
146 |
return -1; |
|
147 |
}
|
|
148 |
||
149 |
||
150 |
static int drv_pL_close(void) |
|
151 |
{
|
|
152 |
usb_release_interface(lcd, 0); |
|
153 |
usb_close(lcd); |
|
154 |
||
155 |
return 0; |
|
156 |
}
|
|
157 |
||
158 |
||
159 |
static void drv_pL_send(unsigned char *data, int size) |
|
160 |
{
|
|
161 |
usb_interrupt_write(lcd, USB_ENDPOINT_OUT + 1, (char *) data, size, 1000); |
|
162 |
}
|
|
163 |
||
0.1.1
by Reinhard Tartler
Import upstream version 0.11.0~svn1143 |
164 |
static int drv_pL_read(unsigned char *data, int size) |
165 |
{
|
|
166 |
return usb_interrupt_read(lcd, USB_ENDPOINT_OUT + 1, (char *) data, size, 1000); |
|
167 |
}
|
|
168 |
||
169 |
||
718
by Reinhard Tartler
import new upstream |
170 |
|
171 |
static void drv_pL_clear(void) |
|
172 |
{
|
|
173 |
unsigned char cmd[1] = { 0x94 }; /* clear display */ |
|
174 |
drv_pL_send(cmd, 1); |
|
175 |
}
|
|
176 |
||
177 |
static int drv_pL_contrast(int contrast) |
|
178 |
{
|
|
179 |
unsigned char cmd[2] = { 0x92 }; /* set contrast */ |
|
180 |
||
181 |
if (contrast < 0) |
|
182 |
contrast = 0; |
|
183 |
if (contrast > 255) |
|
184 |
contrast = 255; |
|
185 |
||
186 |
cmd[1] = contrast; |
|
187 |
drv_pL_send(cmd, 2); |
|
188 |
||
189 |
return contrast; |
|
190 |
}
|
|
191 |
||
192 |
||
193 |
static int drv_pL_backlight(int backlight) |
|
194 |
{
|
|
195 |
unsigned char cmd[2] = { 0x91 }; /* set backlight */ |
|
196 |
||
197 |
if (backlight < 0) |
|
198 |
backlight = 0; |
|
199 |
if (backlight > 1) |
|
200 |
backlight = 1; |
|
201 |
||
202 |
cmd[1] = backlight; |
|
203 |
drv_pL_send(cmd, 2); |
|
204 |
||
205 |
return backlight; |
|
206 |
}
|
|
207 |
||
0.1.1
by Reinhard Tartler
Import upstream version 0.11.0~svn1143 |
208 |
#define _USBLCD_MAX_DATA_LEN 24
|
209 |
#define IN_REPORT_KEY_STATE 0x11
|
|
210 |
static int drv_pL_gpi( __attribute__ ((unused)) |
|
211 |
int num) |
|
212 |
{
|
|
213 |
int ret; |
|
214 |
unsigned char read_packet[_USBLCD_MAX_DATA_LEN]; |
|
215 |
ret = drv_pL_read(read_packet, _USBLCD_MAX_DATA_LEN); |
|
216 |
if ((ret > 0) && (read_packet[0] == IN_REPORT_KEY_STATE)) { |
|
217 |
debug("picoLCD: pressed key= 0x%02x\n", read_packet[1]); |
|
218 |
return read_packet[1]; |
|
219 |
}
|
|
220 |
return 0; |
|
221 |
}
|
|
222 |
||
718
by Reinhard Tartler
import new upstream |
223 |
static int drv_pL_gpo(int num, int val) |
224 |
{
|
|
225 |
unsigned char cmd[2] = { 0x81 }; /* set GPO */ |
|
226 |
||
227 |
if (num < 0) |
|
228 |
num = 0; |
|
229 |
if (num > 7) |
|
230 |
num = 7; |
|
231 |
||
232 |
if (val < 0) |
|
233 |
val = 0; |
|
234 |
if (val > 1) |
|
235 |
val = 1; |
|
236 |
||
237 |
/* set led bit to 1 or 0 */
|
|
238 |
if (val) |
|
239 |
gpo |= 1 << num; |
|
240 |
else
|
|
241 |
gpo &= ~(1 << num); |
|
242 |
||
243 |
cmd[1] = gpo; |
|
244 |
drv_pL_send(cmd, 2); |
|
245 |
||
246 |
return val; |
|
247 |
}
|
|
248 |
||
249 |
||
250 |
static void drv_pL_write(const int row, const int col, const char *data, int len) |
|
251 |
{
|
|
252 |
unsigned char cmd[64]; |
|
253 |
int i; |
|
254 |
||
255 |
cmd[0] = 0x98; /* goto/write */ |
|
256 |
cmd[1] = row; |
|
257 |
cmd[2] = col; |
|
258 |
cmd[3] = len; |
|
259 |
||
260 |
i = 4; |
|
261 |
while (len--) { |
|
262 |
cmd[i++] = *data++; |
|
263 |
}
|
|
264 |
||
265 |
drv_pL_send(cmd, i); |
|
266 |
}
|
|
267 |
||
268 |
static void drv_pL_defchar(const int ascii, const unsigned char *matrix) |
|
269 |
{
|
|
270 |
unsigned char cmd[10] = { 0x9c }; /* define character */ |
|
271 |
int i; |
|
272 |
||
273 |
cmd[1] = ascii; |
|
274 |
for (i = 0; i < 8; i++) { |
|
275 |
cmd[i + 2] = *matrix++ & 0x1f; |
|
276 |
}
|
|
277 |
||
278 |
drv_pL_send(cmd, 10); |
|
279 |
}
|
|
280 |
||
281 |
||
282 |
static int drv_pL_start(const char *section, const int quiet) |
|
283 |
{
|
|
284 |
int rows = -1, cols = -1; |
|
285 |
int value; |
|
286 |
char *s; |
|
287 |
||
288 |
s = cfg_get(section, "Size", NULL); |
|
289 |
if (s == NULL || *s == '\0') { |
|
290 |
error("%s: no '%s.Size' entry from %s", Name, section, cfg_source()); |
|
291 |
return -1; |
|
292 |
}
|
|
293 |
if (sscanf(s, "%dx%d", &cols, &rows) != 2 || rows < 1 || cols < 1) { |
|
294 |
error("%s: bad %s.Size '%s' from %s", Name, section, s, cfg_source()); |
|
295 |
free(s); |
|
296 |
return -1; |
|
297 |
}
|
|
298 |
||
299 |
DROWS = rows; |
|
300 |
DCOLS = cols; |
|
301 |
||
302 |
if (drv_pL_open() < 0) { |
|
303 |
return -1; |
|
304 |
}
|
|
305 |
||
306 |
/* Init the command buffer */
|
|
307 |
Buffer = (char *) malloc(1024); |
|
308 |
if (Buffer == NULL) { |
|
0.1.1
by Reinhard Tartler
Import upstream version 0.11.0~svn1143 |
309 |
error("%s: command buffer could not be allocated: malloc() failed", Name); |
718
by Reinhard Tartler
import new upstream |
310 |
return -1; |
311 |
}
|
|
312 |
BufPtr = Buffer; |
|
313 |
||
314 |
if (cfg_number(section, "Contrast", 0, 0, 255, &value) > 0) { |
|
315 |
info("Setting contrast to %d", value); |
|
316 |
drv_pL_contrast(value); |
|
317 |
}
|
|
318 |
||
319 |
if (cfg_number(section, "Backlight", 0, 0, 1, &value) > 0) { |
|
320 |
info("Setting backlight to %d", value); |
|
321 |
drv_pL_backlight(value); |
|
322 |
}
|
|
323 |
||
324 |
drv_pL_clear(); /* clear display */ |
|
325 |
||
326 |
if (!quiet) { |
|
327 |
char buffer[40]; |
|
328 |
qprintf(buffer, sizeof(buffer), "%s %dx%d", Name, DCOLS, DROWS); |
|
329 |
if (drv_generic_text_greet(buffer, "http://www.picolcd.com")) { |
|
330 |
sleep(3); |
|
331 |
drv_pL_clear(); |
|
332 |
}
|
|
333 |
}
|
|
334 |
||
335 |
return 0; |
|
336 |
}
|
|
337 |
||
338 |
||
339 |
/****************************************/
|
|
340 |
/*** plugins ***/
|
|
341 |
/****************************************/
|
|
342 |
||
343 |
static void plugin_contrast(RESULT * result, RESULT * arg1) |
|
344 |
{
|
|
345 |
double contrast; |
|
346 |
||
347 |
contrast = drv_pL_contrast(R2N(arg1)); |
|
348 |
SetResult(&result, R_NUMBER, &contrast); |
|
349 |
}
|
|
350 |
||
351 |
static void plugin_backlight(RESULT * result, RESULT * arg1) |
|
352 |
{
|
|
353 |
double backlight; |
|
354 |
||
355 |
backlight = drv_pL_backlight(R2N(arg1)); |
|
356 |
SetResult(&result, R_NUMBER, &backlight); |
|
357 |
}
|
|
358 |
||
359 |
static void plugin_gpo(RESULT * result, RESULT * argv[]) |
|
360 |
{
|
|
361 |
double gpo; |
|
362 |
gpo = drv_pL_gpo(R2N(argv[0]), R2N(argv[1])); |
|
363 |
SetResult(&result, R_NUMBER, &gpo); |
|
364 |
}
|
|
365 |
||
366 |
/****************************************/
|
|
367 |
/*** widget callbacks ***/
|
|
368 |
/****************************************/
|
|
369 |
||
370 |
||
371 |
/* using drv_generic_text_draw(W) */
|
|
372 |
/* using drv_generic_text_icon_draw(W) */
|
|
373 |
/* using drv_generic_text_bar_draw(W) */
|
|
374 |
||
375 |
||
376 |
/****************************************/
|
|
377 |
/*** exported functions ***/
|
|
378 |
/****************************************/
|
|
379 |
||
380 |
||
381 |
/* list models */
|
|
382 |
int drv_pL_list(void) |
|
383 |
{
|
|
0.1.1
by Reinhard Tartler
Import upstream version 0.11.0~svn1143 |
384 |
printf("picoLCD 20x2 Text LCD"); |
718
by Reinhard Tartler
import new upstream |
385 |
return 0; |
386 |
}
|
|
387 |
||
388 |
||
389 |
/* initialize driver & display */
|
|
390 |
int drv_pL_init(const char *section, const int quiet) |
|
391 |
{
|
|
392 |
WIDGET_CLASS wc; |
|
393 |
int ret; |
|
394 |
||
0.1.1
by Reinhard Tartler
Import upstream version 0.11.0~svn1143 |
395 |
info("%s: %s", Name, "$Rev: 1143 $"); |
718
by Reinhard Tartler
import new upstream |
396 |
|
397 |
/* display preferences */
|
|
398 |
XRES = 5; /* pixel width of one char */ |
|
399 |
YRES = 8; /* pixel height of one char */ |
|
400 |
CHARS = 8; /* number of user-defineable characters */ |
|
401 |
CHAR0 = 0; /* ASCII of first user-defineable char */ |
|
402 |
GPOS = 8; |
|
0.1.1
by Reinhard Tartler
Import upstream version 0.11.0~svn1143 |
403 |
GPIS = 1; |
718
by Reinhard Tartler
import new upstream |
404 |
INVALIDATE = 1; |
405 |
GOTO_COST = 2; /* number of bytes a goto command requires */ |
|
406 |
||
407 |
/* real worker functions */
|
|
408 |
drv_generic_text_real_write = drv_pL_write; |
|
409 |
drv_generic_text_real_defchar = drv_pL_defchar; |
|
410 |
drv_generic_gpio_real_set = drv_pL_gpo; |
|
0.1.1
by Reinhard Tartler
Import upstream version 0.11.0~svn1143 |
411 |
drv_generic_gpio_real_get = drv_pL_gpi; |
718
by Reinhard Tartler
import new upstream |
412 |
|
413 |
/* start display */
|
|
414 |
if ((ret = drv_pL_start(section, quiet)) != 0) |
|
415 |
return ret; |
|
416 |
||
417 |
/* initialize generic text driver */
|
|
418 |
if ((ret = drv_generic_text_init(section, Name)) != 0) |
|
419 |
return ret; |
|
420 |
||
421 |
/* initialize generic icon driver */
|
|
422 |
if ((ret = drv_generic_text_icon_init()) != 0) |
|
423 |
return ret; |
|
424 |
||
425 |
/* initialize generic bar driver */
|
|
426 |
if ((ret = drv_generic_text_bar_init(0)) != 0) |
|
427 |
return ret; |
|
428 |
||
429 |
drv_generic_text_bar_add_segment(0, 0, 255, 32); |
|
430 |
||
431 |
/* GPO's init */
|
|
432 |
if ((ret = drv_generic_gpio_init(section, Name)) != 0) |
|
433 |
return ret; |
|
434 |
||
435 |
/* register text widget */
|
|
436 |
wc = Widget_Text; |
|
437 |
wc.draw = drv_generic_text_draw; |
|
438 |
widget_register(&wc); |
|
439 |
||
440 |
/* register icon widget */
|
|
441 |
wc = Widget_Icon; |
|
442 |
wc.draw = drv_generic_text_icon_draw; |
|
443 |
widget_register(&wc); |
|
444 |
||
445 |
/* register bar widget */
|
|
446 |
wc = Widget_Bar; |
|
447 |
wc.draw = drv_generic_text_bar_draw; |
|
448 |
widget_register(&wc); |
|
449 |
||
450 |
/* register plugins */
|
|
451 |
AddFunction("LCD::contrast", -1, plugin_contrast); |
|
452 |
AddFunction("LCD::backlight", -1, plugin_backlight); |
|
453 |
AddFunction("LCD::gpo", -1, plugin_gpo); |
|
454 |
||
455 |
return 0; |
|
456 |
}
|
|
457 |
||
458 |
||
459 |
/* close driver & display */
|
|
460 |
int drv_pL_quit(const int quiet) |
|
461 |
{
|
|
462 |
||
463 |
info("%s: shutting down.", Name); |
|
464 |
||
465 |
drv_generic_text_quit(); |
|
466 |
||
467 |
/* clear display */
|
|
468 |
drv_pL_clear(); |
|
469 |
||
470 |
/* say goodbye... */
|
|
471 |
if (!quiet) { |
|
472 |
drv_generic_text_greet("goodbye!", NULL); |
|
473 |
}
|
|
474 |
||
475 |
drv_pL_close(); |
|
476 |
||
477 |
if (Buffer) { |
|
478 |
free(Buffer); |
|
479 |
Buffer = NULL; |
|
480 |
BufPtr = Buffer; |
|
481 |
}
|
|
482 |
||
483 |
return (0); |
|
484 |
}
|
|
485 |
||
486 |
||
487 |
DRIVER drv_picoLCD = { |
|
721
by Reinhard Tartler
new upstream version |
488 |
.name = Name, |
489 |
.list = drv_pL_list, |
|
490 |
.init = drv_pL_init, |
|
491 |
.quit = drv_pL_quit, |
|
718
by Reinhard Tartler
import new upstream |
492 |
};
|