1b1303e6eSMike Smith /*
2b1303e6eSMike Smith * Control LCD module hung off parallel port using the
3b1303e6eSMike Smith * ppi 'geek port' interface.
4b1303e6eSMike Smith */
5b1303e6eSMike Smith
6b1303e6eSMike Smith #include <stdio.h>
7b1303e6eSMike Smith #include <stdlib.h>
8b1303e6eSMike Smith #include <string.h>
9b1303e6eSMike Smith #include <ctype.h>
10b1303e6eSMike Smith #include <fcntl.h>
11b1303e6eSMike Smith #include <unistd.h>
12b1303e6eSMike Smith #include <err.h>
13b1303e6eSMike Smith #include <sysexits.h>
14b1303e6eSMike Smith
155b5df07dSRuslan Ermilov #include <dev/ppbus/ppbconf.h>
165b5df07dSRuslan Ermilov #include <dev/ppbus/ppi.h>
17b1303e6eSMike Smith
18b1303e6eSMike Smith #define debug(lev, fmt, args...) if (debuglevel >= lev) fprintf(stderr, fmt "\n" , ## args);
19b1303e6eSMike Smith
20b1303e6eSMike Smith static void usage(void);
21b1303e6eSMike Smith static char *progname;
22b1303e6eSMike Smith
23b1303e6eSMike Smith #define DEFAULT_DEVICE "/dev/ppi0"
24b1303e6eSMike Smith
25b1303e6eSMike Smith /* Driver functions */
26b1303e6eSMike Smith static void hd44780_prepare(char *devname, char *options);
27b1303e6eSMike Smith static void hd44780_finish(void);
28b1303e6eSMike Smith static void hd44780_command(int cmd);
29b1303e6eSMike Smith static void hd44780_putc(int c);
30b1303e6eSMike Smith
31b1303e6eSMike Smith /*
32b1303e6eSMike Smith * Commands
33b1303e6eSMike Smith * Note that unrecognised command escapes are passed through with
34b1303e6eSMike Smith * the command value set to the ASCII value of the escaped character.
35b1303e6eSMike Smith */
36b1303e6eSMike Smith #define CMD_RESET 0
37b1303e6eSMike Smith #define CMD_BKSP 1
38b1303e6eSMike Smith #define CMD_CLR 2
39b1303e6eSMike Smith #define CMD_NL 3
40b1303e6eSMike Smith #define CMD_CR 4
41b1303e6eSMike Smith #define CMD_HOME 5
42b1303e6eSMike Smith
43b1303e6eSMike Smith #define MAX_DRVOPT 10 /* maximum driver-specific options */
44b1303e6eSMike Smith
45b1303e6eSMike Smith struct lcd_driver
46b1303e6eSMike Smith {
47b1303e6eSMike Smith char *l_code;
48b1303e6eSMike Smith char *l_name;
49b1303e6eSMike Smith char *l_options[MAX_DRVOPT];
50b1303e6eSMike Smith void (* l_prepare)(char *name, char *options);
51b1303e6eSMike Smith void (* l_finish)(void);
52b1303e6eSMike Smith void (* l_command)(int cmd);
53b1303e6eSMike Smith void (* l_putc)(int c);
54b1303e6eSMike Smith };
55b1303e6eSMike Smith
56b1303e6eSMike Smith static struct lcd_driver lcd_drivertab[] = {
57b1303e6eSMike Smith {
58b1303e6eSMike Smith "hd44780",
59b1303e6eSMike Smith "Hitachi HD44780 and compatibles",
60b1303e6eSMike Smith {
61b1303e6eSMike Smith "Reset options:",
62b1303e6eSMike Smith " 1 1-line display (default 2)",
63b1303e6eSMike Smith " B Cursor blink enable",
64b1303e6eSMike Smith " C Cursor enable",
65b1303e6eSMike Smith " F Large font select",
66b1303e6eSMike Smith NULL
67b1303e6eSMike Smith },
68b1303e6eSMike Smith hd44780_prepare,
69b1303e6eSMike Smith hd44780_finish,
70b1303e6eSMike Smith hd44780_command,
71b1303e6eSMike Smith hd44780_putc
72b1303e6eSMike Smith },
73b1303e6eSMike Smith {
74b1303e6eSMike Smith NULL,
75b1303e6eSMike Smith NULL,
76b1303e6eSMike Smith {
77b1303e6eSMike Smith NULL
78b1303e6eSMike Smith },
79b1303e6eSMike Smith NULL,
80b1303e6eSMike Smith NULL
81b1303e6eSMike Smith }
82b1303e6eSMike Smith };
83b1303e6eSMike Smith
84b1303e6eSMike Smith static void do_char(struct lcd_driver *driver, char ch);
85b1303e6eSMike Smith
86b1303e6eSMike Smith int debuglevel = 0;
87b1303e6eSMike Smith int vflag = 0;
88b1303e6eSMike Smith
89a343b088SNick Hibma int
main(int argc,char * argv[])90b1303e6eSMike Smith main(int argc, char *argv[])
91b1303e6eSMike Smith {
92b1303e6eSMike Smith extern char *optarg;
93b1303e6eSMike Smith extern int optind;
94b1303e6eSMike Smith struct lcd_driver *driver = &lcd_drivertab[0];
95b1303e6eSMike Smith char *drivertype, *cp;
96b1303e6eSMike Smith char *devname = DEFAULT_DEVICE;
97b1303e6eSMike Smith char *drvopts = NULL;
98b1303e6eSMike Smith int ch, i;
99b1303e6eSMike Smith
100b1303e6eSMike Smith if ((progname = strrchr(argv[0], '/'))) {
101b1303e6eSMike Smith progname++;
102b1303e6eSMike Smith } else {
103b1303e6eSMike Smith progname = argv[0];
104b1303e6eSMike Smith }
105b1303e6eSMike Smith
106b1303e6eSMike Smith drivertype = getenv("LCD_TYPE");
107b1303e6eSMike Smith
10812a524f9SWarner Losh while ((ch = getopt(argc, argv, "Dd:f:o:v")) != -1) {
109b1303e6eSMike Smith switch(ch) {
110b1303e6eSMike Smith case 'D':
111b1303e6eSMike Smith debuglevel++;
112b1303e6eSMike Smith break;
113b1303e6eSMike Smith case 'd':
114b1303e6eSMike Smith drivertype = optarg;
115b1303e6eSMike Smith break;
116b1303e6eSMike Smith case 'f':
117b1303e6eSMike Smith devname = optarg;
118b1303e6eSMike Smith break;
119b1303e6eSMike Smith case 'o':
120b1303e6eSMike Smith drvopts = optarg;
121b1303e6eSMike Smith break;
122b1303e6eSMike Smith case 'v':
123b1303e6eSMike Smith vflag = 1;
124b1303e6eSMike Smith break;
125b1303e6eSMike Smith default:
126b1303e6eSMike Smith usage();
127b1303e6eSMike Smith }
128b1303e6eSMike Smith }
129b1303e6eSMike Smith argc -= optind;
130b1303e6eSMike Smith argv += optind;
131b1303e6eSMike Smith
132b1303e6eSMike Smith /* If an LCD type was specified, look it up */
133b1303e6eSMike Smith if (drivertype != NULL) {
134b1303e6eSMike Smith driver = NULL;
135b1303e6eSMike Smith for (i = 0; lcd_drivertab[i].l_code != NULL; i++) {
136b1303e6eSMike Smith if (!strcmp(drivertype, lcd_drivertab[i].l_code)) {
137b1303e6eSMike Smith driver = &lcd_drivertab[i];
138b1303e6eSMike Smith break;
139b1303e6eSMike Smith }
140b1303e6eSMike Smith }
141b1303e6eSMike Smith if (driver == NULL) {
142b1303e6eSMike Smith warnx("LCD driver '%s' not known", drivertype);
143b1303e6eSMike Smith usage();
144b1303e6eSMike Smith }
145b1303e6eSMike Smith }
146b1303e6eSMike Smith debug(1, "Driver selected for %s", driver->l_name);
147b1303e6eSMike Smith driver->l_prepare(devname, drvopts);
148b1303e6eSMike Smith atexit(driver->l_finish);
149b1303e6eSMike Smith
150b1303e6eSMike Smith if (argc > 0) {
151b1303e6eSMike Smith debug(2, "reading input from %d argument%s", argc, (argc > 1) ? "s" : "");
152b1303e6eSMike Smith for (i = 0; i < argc; i++)
153b1303e6eSMike Smith for (cp = argv[i]; *cp; cp++)
154b1303e6eSMike Smith do_char(driver, *cp);
155b1303e6eSMike Smith } else {
156b1303e6eSMike Smith debug(2, "reading input from stdin");
157b1303e6eSMike Smith setvbuf(stdin, NULL, _IONBF, 0);
158b1303e6eSMike Smith while ((ch = fgetc(stdin)) != EOF)
159b1303e6eSMike Smith do_char(driver, (char)ch);
160b1303e6eSMike Smith }
161b1303e6eSMike Smith exit(EX_OK);
162b1303e6eSMike Smith }
163b1303e6eSMike Smith
164b1303e6eSMike Smith static void
usage(void)165b1303e6eSMike Smith usage(void)
166b1303e6eSMike Smith {
167b1303e6eSMike Smith int i, j;
168b1303e6eSMike Smith
169b1303e6eSMike Smith fprintf(stderr, "usage: %s [-v] [-d drivername] [-f device] [-o options] [args...]\n", progname);
170b1303e6eSMike Smith fprintf(stderr, " -D Increase debugging\n");
171b1303e6eSMike Smith fprintf(stderr, " -f Specify device, default is '%s'\n", DEFAULT_DEVICE);
172b1303e6eSMike Smith fprintf(stderr, " -d Specify driver, one of:\n");
173b1303e6eSMike Smith for (i = 0; lcd_drivertab[i].l_code != NULL; i++) {
174b1303e6eSMike Smith fprintf(stderr, " %-10s (%s)%s\n",
175b1303e6eSMike Smith lcd_drivertab[i].l_code, lcd_drivertab[i].l_name, (i == 0) ? " *default*" : "");
176b1303e6eSMike Smith if (lcd_drivertab[i].l_options[0] != NULL) {
177b1303e6eSMike Smith
178b1303e6eSMike Smith for (j = 0; lcd_drivertab[i].l_options[j] != NULL; j++)
179b1303e6eSMike Smith fprintf(stderr, " %s\n", lcd_drivertab[i].l_options[j]);
180b1303e6eSMike Smith }
181b1303e6eSMike Smith }
182b1303e6eSMike Smith fprintf(stderr, " -o Specify driver option string\n");
183b1303e6eSMike Smith fprintf(stderr, " args Message strings. Embedded escapes supported:\n");
184b1303e6eSMike Smith fprintf(stderr, " \\b Backspace\n");
185b1303e6eSMike Smith fprintf(stderr, " \\f Clear display, home cursor\n");
186b1303e6eSMike Smith fprintf(stderr, " \\n Newline\n");
187b1303e6eSMike Smith fprintf(stderr, " \\r Carriage return\n");
188b1303e6eSMike Smith fprintf(stderr, " \\R Reset display\n");
189b1303e6eSMike Smith fprintf(stderr, " \\v Home cursor\n");
190b1303e6eSMike Smith fprintf(stderr, " \\\\ Literal \\\n");
191b1303e6eSMike Smith fprintf(stderr, " If args not supplied, strings are read from standard input\n");
192b1303e6eSMike Smith exit(EX_USAGE);
193b1303e6eSMike Smith }
194b1303e6eSMike Smith
195b1303e6eSMike Smith static void
do_char(struct lcd_driver * driver,char ch)196b1303e6eSMike Smith do_char(struct lcd_driver *driver, char ch)
197b1303e6eSMike Smith {
198b1303e6eSMike Smith static int esc = 0;
199b1303e6eSMike Smith
200b1303e6eSMike Smith if (esc) {
201b1303e6eSMike Smith switch(ch) {
202b1303e6eSMike Smith case 'b':
203b1303e6eSMike Smith driver->l_command(CMD_BKSP);
204b1303e6eSMike Smith break;
205b1303e6eSMike Smith case 'f':
206b1303e6eSMike Smith driver->l_command(CMD_CLR);
207b1303e6eSMike Smith break;
208b1303e6eSMike Smith case 'n':
209b1303e6eSMike Smith driver->l_command(CMD_NL);
210b1303e6eSMike Smith break;
211b1303e6eSMike Smith case 'r':
212b1303e6eSMike Smith driver->l_command(CMD_CR);
213b1303e6eSMike Smith break;
214b1303e6eSMike Smith case 'R':
215b1303e6eSMike Smith driver->l_command(CMD_RESET);
216b1303e6eSMike Smith break;
217b1303e6eSMike Smith case 'v':
218b1303e6eSMike Smith driver->l_command(CMD_HOME);
219b1303e6eSMike Smith break;
220b1303e6eSMike Smith case '\\':
221b1303e6eSMike Smith driver->l_putc('\\');
222b1303e6eSMike Smith break;
223b1303e6eSMike Smith default:
224b1303e6eSMike Smith driver->l_command(ch);
225b1303e6eSMike Smith break;
226b1303e6eSMike Smith }
227b1303e6eSMike Smith esc = 0;
228b1303e6eSMike Smith } else {
229b1303e6eSMike Smith if (ch == '\\') {
230b1303e6eSMike Smith esc = 1;
231b1303e6eSMike Smith } else {
232b1303e6eSMike Smith if (vflag || isprint(ch))
233b1303e6eSMike Smith driver->l_putc(ch);
234b1303e6eSMike Smith }
235b1303e6eSMike Smith }
236b1303e6eSMike Smith }
237b1303e6eSMike Smith
238b1303e6eSMike Smith
239b1303e6eSMike Smith /******************************************************************************
240b1303e6eSMike Smith * Driver for the Hitachi HD44780. This is probably *the* most common driver
241b1303e6eSMike Smith * to be found on one- and two-line alphanumeric LCDs.
242b1303e6eSMike Smith *
243b1303e6eSMike Smith * This driver assumes the following connections :
244b1303e6eSMike Smith *
245b1303e6eSMike Smith * Parallel Port LCD Module
246b1303e6eSMike Smith * --------------------------------
247b1303e6eSMike Smith * Strobe (1) Enable (6)
248b1303e6eSMike Smith * Data (2-9) Data (7-14)
2496c7c20ceSIan Dowse * Select In (17) RS (4)
250b1303e6eSMike Smith * Auto Feed (14) R/W (5)
251b1303e6eSMike Smith *
252b1303e6eSMike Smith * In addition, power must be supplied to the module, normally with
253b1303e6eSMike Smith * a circuit similar to this:
254b1303e6eSMike Smith *
255b1303e6eSMike Smith * VCC (+5V) O------o-------o--------O Module pin 2
256b1303e6eSMike Smith * | | +
257b1303e6eSMike Smith * / ---
258b1303e6eSMike Smith * \ --- 1uF
259b1303e6eSMike Smith * / | -
260b1303e6eSMike Smith * \ <-----o--------O Module pin 3
261b1303e6eSMike Smith * /
262b1303e6eSMike Smith * \
263b1303e6eSMike Smith * |
264b1303e6eSMike Smith * GND O------o----------------O Module pin 1
265b1303e6eSMike Smith *
266b1303e6eSMike Smith * The ground line should also be connected to the parallel port, on
267b1303e6eSMike Smith * one of the ground pins (eg. pin 25).
268b1303e6eSMike Smith *
269b1303e6eSMike Smith * Note that the pinning on some LCD modules has the odd and even pins
270*7a2b450fSEitan Adler * arranged as though reversed; check carefully before connecting a module
271b1303e6eSMike Smith * as it is possible to toast the HD44780 if the power is reversed.
272b1303e6eSMike Smith */
273b1303e6eSMike Smith
274b1303e6eSMike Smith static int hd_fd;
275b1303e6eSMike Smith static u_int8_t hd_cbits;
276b1303e6eSMike Smith static int hd_lines = 2;
277b1303e6eSMike Smith static int hd_blink = 0;
278b1303e6eSMike Smith static int hd_cursor = 0;
279b1303e6eSMike Smith static int hd_font = 0;
280b1303e6eSMike Smith
281b1303e6eSMike Smith #define HD_COMMAND SELECTIN
282b1303e6eSMike Smith #define HD_DATA 0
283b1303e6eSMike Smith #define HD_READ 0
284b1303e6eSMike Smith #define HD_WRITE AUTOFEED
285b1303e6eSMike Smith
286b1303e6eSMike Smith #define HD_BF 0x80 /* internal busy flag */
287b1303e6eSMike Smith #define HD_ADDRMASK 0x7f /* DDRAM address mask */
288b1303e6eSMike Smith
289b1303e6eSMike Smith #define hd_sctrl(v) {u_int8_t _val; _val = hd_cbits | v; ioctl(hd_fd, PPISCTRL, &_val);}
290b1303e6eSMike Smith #define hd_sdata(v) {u_int8_t _val; _val = v; ioctl(hd_fd, PPISDATA, &_val);}
291b1303e6eSMike Smith #define hd_gdata(v) ioctl(hd_fd, PPIGDATA, &v)
292b1303e6eSMike Smith
293b1303e6eSMike Smith static void
hd44780_output(int type,int data)294b1303e6eSMike Smith hd44780_output(int type, int data)
295b1303e6eSMike Smith {
296b1303e6eSMike Smith debug(3, "%s -> 0x%02x", (type == HD_COMMAND) ? "cmd " : "data", data);
297b1303e6eSMike Smith hd_sctrl(type | HD_WRITE | STROBE); /* set direction, address */
298b1303e6eSMike Smith hd_sctrl(type | HD_WRITE); /* raise E */
299b1303e6eSMike Smith hd_sdata((u_int8_t) data); /* drive data */
300b1303e6eSMike Smith hd_sctrl(type | HD_WRITE | STROBE); /* lower E */
301b1303e6eSMike Smith }
302b1303e6eSMike Smith
303b1303e6eSMike Smith static int
hd44780_input(int type)304b1303e6eSMike Smith hd44780_input(int type)
305b1303e6eSMike Smith {
306b1303e6eSMike Smith u_int8_t val;
307b1303e6eSMike Smith
308b1303e6eSMike Smith hd_sctrl(type | HD_READ | STROBE); /* set direction, address */
309b1303e6eSMike Smith hd_sctrl(type | HD_READ); /* raise E */
310b1303e6eSMike Smith hd_gdata(val); /* read data */
311b1303e6eSMike Smith hd_sctrl(type | HD_READ | STROBE); /* lower E */
312b1303e6eSMike Smith
313b1303e6eSMike Smith debug(3, "0x%02x -> %s", val, (type == HD_COMMAND) ? "cmd " : "data");
314b1303e6eSMike Smith return(val);
315b1303e6eSMike Smith }
316b1303e6eSMike Smith
317b1303e6eSMike Smith static void
hd44780_prepare(char * devname,char * options)318b1303e6eSMike Smith hd44780_prepare(char *devname, char *options)
319b1303e6eSMike Smith {
320b1303e6eSMike Smith char *cp = options;
321b1303e6eSMike Smith
322b1303e6eSMike Smith if ((hd_fd = open(devname, O_RDWR, 0)) == -1)
323b1303e6eSMike Smith err(EX_OSFILE, "can't open '%s'", devname);
324b1303e6eSMike Smith
325b1303e6eSMike Smith /* parse options */
326b1303e6eSMike Smith while (cp && *cp) {
327b1303e6eSMike Smith switch (*cp++) {
328b1303e6eSMike Smith case '1':
329b1303e6eSMike Smith hd_lines = 1;
330b1303e6eSMike Smith break;
331b1303e6eSMike Smith case 'B':
332b1303e6eSMike Smith hd_blink = 1;
333b1303e6eSMike Smith break;
334b1303e6eSMike Smith case 'C':
335b1303e6eSMike Smith hd_cursor = 1;
336b1303e6eSMike Smith break;
337b1303e6eSMike Smith case 'F':
338b1303e6eSMike Smith hd_font = 1;
339b1303e6eSMike Smith break;
340b1303e6eSMike Smith default:
341b1303e6eSMike Smith errx(EX_USAGE, "hd44780: unknown option code '%c'", *(cp-1));
342b1303e6eSMike Smith }
343b1303e6eSMike Smith }
344b1303e6eSMike Smith
345b1303e6eSMike Smith /* Put LCD in idle state */
346b1303e6eSMike Smith if (ioctl(hd_fd, PPIGCTRL, &hd_cbits)) /* save other control bits */
347b1303e6eSMike Smith err(EX_IOERR, "ioctl PPIGCTRL failed (not a ppi device?)");
348b1303e6eSMike Smith hd_cbits &= ~(STROBE | SELECTIN | AUTOFEED); /* set strobe, RS, R/W low */
349b1303e6eSMike Smith debug(2, "static control bits 0x%x", hd_cbits);
350b1303e6eSMike Smith hd_sctrl(STROBE);
351b1303e6eSMike Smith hd_sdata(0);
352b1303e6eSMike Smith
353b1303e6eSMike Smith }
354b1303e6eSMike Smith
355b1303e6eSMike Smith static void
hd44780_finish(void)356b1303e6eSMike Smith hd44780_finish(void)
357b1303e6eSMike Smith {
358b1303e6eSMike Smith close(hd_fd);
359b1303e6eSMike Smith }
360b1303e6eSMike Smith
361b1303e6eSMike Smith static void
hd44780_command(int cmd)362b1303e6eSMike Smith hd44780_command(int cmd)
363b1303e6eSMike Smith {
364b1303e6eSMike Smith u_int8_t val;
365b1303e6eSMike Smith
366b1303e6eSMike Smith switch (cmd) {
367b1303e6eSMike Smith case CMD_RESET: /* full manual reset and reconfigure as per datasheet */
368b1303e6eSMike Smith debug(1, "hd44780: reset to %d lines, %s font,%s%s cursor",
369b1303e6eSMike Smith hd_lines, hd_font ? "5x10" : "5x7", hd_cursor ? "" : " no", hd_blink ? " blinking" : "");
370b1303e6eSMike Smith val = 0x30;
371b1303e6eSMike Smith if (hd_lines == 2)
372b1303e6eSMike Smith val |= 0x08;
373b1303e6eSMike Smith if (hd_font)
374b1303e6eSMike Smith val |= 0x04;
375b1303e6eSMike Smith hd44780_output(HD_COMMAND, val);
376b1303e6eSMike Smith usleep(10000);
377b1303e6eSMike Smith hd44780_output(HD_COMMAND, val);
378b1303e6eSMike Smith usleep(1000);
379b1303e6eSMike Smith hd44780_output(HD_COMMAND, val);
380b1303e6eSMike Smith usleep(1000);
381b1303e6eSMike Smith val = 0x08; /* display off */
382b1303e6eSMike Smith hd44780_output(HD_COMMAND, val);
383b1303e6eSMike Smith usleep(1000);
384b1303e6eSMike Smith val |= 0x04; /* display on */
385b1303e6eSMike Smith if (hd_cursor)
386b1303e6eSMike Smith val |= 0x02;
387b1303e6eSMike Smith if (hd_blink)
388b1303e6eSMike Smith val |= 0x01;
389b1303e6eSMike Smith hd44780_output(HD_COMMAND, val);
390b1303e6eSMike Smith usleep(1000);
391b1303e6eSMike Smith hd44780_output(HD_COMMAND, 0x06); /* shift cursor by increment */
392b1303e6eSMike Smith usleep(1000);
393b1303e6eSMike Smith /* FALLTHROUGH */
394b1303e6eSMike Smith
395b1303e6eSMike Smith case CMD_CLR:
396b1303e6eSMike Smith hd44780_output(HD_COMMAND, 0x01);
397b1303e6eSMike Smith usleep(2000);
398b1303e6eSMike Smith break;
399b1303e6eSMike Smith
400b1303e6eSMike Smith case CMD_BKSP:
401b1303e6eSMike Smith hd44780_output(HD_DATA, 0x10); /* shift cursor left one */
402b1303e6eSMike Smith break;
403b1303e6eSMike Smith
404b1303e6eSMike Smith case CMD_NL:
405b1303e6eSMike Smith if (hd_lines == 2)
406b1303e6eSMike Smith hd44780_output(HD_COMMAND, 0xc0); /* beginning of second line */
407b1303e6eSMike Smith break;
408b1303e6eSMike Smith
409b1303e6eSMike Smith case CMD_CR:
410b1303e6eSMike Smith /* XXX will not work in 4-line mode, or where readback fails */
411b1303e6eSMike Smith val = hd44780_input(HD_COMMAND) & 0x3f; /* mask character position, save line pos */
412b1303e6eSMike Smith hd44780_output(HD_COMMAND, 0x80 | val);
413b1303e6eSMike Smith break;
414b1303e6eSMike Smith
415b1303e6eSMike Smith case CMD_HOME:
416b1303e6eSMike Smith hd44780_output(HD_COMMAND, 0x02);
417b1303e6eSMike Smith usleep(2000);
418b1303e6eSMike Smith break;
419b1303e6eSMike Smith
420b1303e6eSMike Smith default:
421b1303e6eSMike Smith if (isprint(cmd)) {
422b1303e6eSMike Smith warnx("unknown command %c", cmd);
423b1303e6eSMike Smith } else {
424b1303e6eSMike Smith warnx("unknown command 0x%x", cmd);
425b1303e6eSMike Smith }
426b1303e6eSMike Smith }
427b1303e6eSMike Smith usleep(40);
428b1303e6eSMike Smith }
429b1303e6eSMike Smith
430b1303e6eSMike Smith static void
hd44780_putc(int c)431b1303e6eSMike Smith hd44780_putc(int c)
432b1303e6eSMike Smith {
433b1303e6eSMike Smith hd44780_output(HD_DATA, c);
434b1303e6eSMike Smith usleep(40);
435b1303e6eSMike Smith }
436b1303e6eSMike Smith
437