186d7f5d3SJohn Marino /*
286d7f5d3SJohn Marino * Control LCD module hung off parallel port using the
386d7f5d3SJohn Marino * ppi 'geek port' interface.
486d7f5d3SJohn Marino *
586d7f5d3SJohn Marino * $FreeBSD: src/share/examples/ppi/ppilcd.c,v 1.2.2.1 2003/01/05 19:45:29 semenu Exp $
686d7f5d3SJohn Marino * $DragonFly: src/share/examples/ppi/ppilcd.c,v 1.3 2008/07/10 18:29:51 swildner Exp $
786d7f5d3SJohn Marino */
886d7f5d3SJohn Marino
986d7f5d3SJohn Marino #include <stdio.h>
1086d7f5d3SJohn Marino #include <stdlib.h>
1186d7f5d3SJohn Marino #include <string.h>
1286d7f5d3SJohn Marino #include <ctype.h>
1386d7f5d3SJohn Marino #include <fcntl.h>
1486d7f5d3SJohn Marino #include <unistd.h>
1586d7f5d3SJohn Marino #include <err.h>
1686d7f5d3SJohn Marino #include <sysexits.h>
1786d7f5d3SJohn Marino
1886d7f5d3SJohn Marino #include <dev/ppbus/ppbconf.h>
1986d7f5d3SJohn Marino #include <dev/ppbus/ppi.h>
2086d7f5d3SJohn Marino
2186d7f5d3SJohn Marino #define debug(lev, fmt, args...) if (debuglevel >= lev) fprintf(stderr, fmt "\n" , ## args);
2286d7f5d3SJohn Marino
2386d7f5d3SJohn Marino static void usage(void);
2486d7f5d3SJohn Marino static char *progname;
2586d7f5d3SJohn Marino
2686d7f5d3SJohn Marino #define DEFAULT_DEVICE "/dev/ppi0"
2786d7f5d3SJohn Marino
2886d7f5d3SJohn Marino /* Driver functions */
2986d7f5d3SJohn Marino static void hd44780_prepare(char *devname, char *options);
3086d7f5d3SJohn Marino static void hd44780_finish(void);
3186d7f5d3SJohn Marino static void hd44780_command(int cmd);
3286d7f5d3SJohn Marino static void hd44780_putc(int c);
3386d7f5d3SJohn Marino
3486d7f5d3SJohn Marino /*
3586d7f5d3SJohn Marino * Commands
3686d7f5d3SJohn Marino * Note that unrecognised command escapes are passed through with
3786d7f5d3SJohn Marino * the command value set to the ASCII value of the escaped character.
3886d7f5d3SJohn Marino */
3986d7f5d3SJohn Marino #define CMD_RESET 0
4086d7f5d3SJohn Marino #define CMD_BKSP 1
4186d7f5d3SJohn Marino #define CMD_CLR 2
4286d7f5d3SJohn Marino #define CMD_NL 3
4386d7f5d3SJohn Marino #define CMD_CR 4
4486d7f5d3SJohn Marino #define CMD_HOME 5
4586d7f5d3SJohn Marino
4686d7f5d3SJohn Marino #define MAX_DRVOPT 10 /* maximum driver-specific options */
4786d7f5d3SJohn Marino
4886d7f5d3SJohn Marino struct lcd_driver
4986d7f5d3SJohn Marino {
5086d7f5d3SJohn Marino char *l_code;
5186d7f5d3SJohn Marino char *l_name;
5286d7f5d3SJohn Marino char *l_options[MAX_DRVOPT];
5386d7f5d3SJohn Marino void (* l_prepare)(char *name, char *options);
5486d7f5d3SJohn Marino void (* l_finish)(void);
5586d7f5d3SJohn Marino void (* l_command)(int cmd);
5686d7f5d3SJohn Marino void (* l_putc)(int c);
5786d7f5d3SJohn Marino };
5886d7f5d3SJohn Marino
5986d7f5d3SJohn Marino static struct lcd_driver lcd_drivertab[] = {
6086d7f5d3SJohn Marino {
6186d7f5d3SJohn Marino "hd44780",
6286d7f5d3SJohn Marino "Hitachi HD44780 and compatibles",
6386d7f5d3SJohn Marino {
6486d7f5d3SJohn Marino "Reset options:",
6586d7f5d3SJohn Marino " 1 1-line display (default 2)",
6686d7f5d3SJohn Marino " B Cursor blink enable",
6786d7f5d3SJohn Marino " C Cursor enable",
6886d7f5d3SJohn Marino " F Large font select",
6986d7f5d3SJohn Marino NULL
7086d7f5d3SJohn Marino },
7186d7f5d3SJohn Marino hd44780_prepare,
7286d7f5d3SJohn Marino hd44780_finish,
7386d7f5d3SJohn Marino hd44780_command,
7486d7f5d3SJohn Marino hd44780_putc
7586d7f5d3SJohn Marino },
7686d7f5d3SJohn Marino {
7786d7f5d3SJohn Marino NULL,
7886d7f5d3SJohn Marino NULL,
7986d7f5d3SJohn Marino {
8086d7f5d3SJohn Marino NULL
8186d7f5d3SJohn Marino },
8286d7f5d3SJohn Marino NULL,
8386d7f5d3SJohn Marino NULL
8486d7f5d3SJohn Marino }
8586d7f5d3SJohn Marino };
8686d7f5d3SJohn Marino
8786d7f5d3SJohn Marino static void do_char(struct lcd_driver *driver, char ch);
8886d7f5d3SJohn Marino
8986d7f5d3SJohn Marino int debuglevel = 0;
9086d7f5d3SJohn Marino int vflag = 0;
9186d7f5d3SJohn Marino
9286d7f5d3SJohn Marino int
main(int argc,char * argv[])9386d7f5d3SJohn Marino main(int argc, char *argv[])
9486d7f5d3SJohn Marino {
9586d7f5d3SJohn Marino extern char *optarg;
9686d7f5d3SJohn Marino extern int optind;
9786d7f5d3SJohn Marino struct lcd_driver *driver = &lcd_drivertab[0];
9886d7f5d3SJohn Marino char *drivertype, *cp;
9986d7f5d3SJohn Marino char *devname = DEFAULT_DEVICE;
10086d7f5d3SJohn Marino char *drvopts = NULL;
10186d7f5d3SJohn Marino int ch, i;
10286d7f5d3SJohn Marino
10386d7f5d3SJohn Marino if ((progname = strrchr(argv[0], '/'))) {
10486d7f5d3SJohn Marino progname++;
10586d7f5d3SJohn Marino } else {
10686d7f5d3SJohn Marino progname = argv[0];
10786d7f5d3SJohn Marino }
10886d7f5d3SJohn Marino
10986d7f5d3SJohn Marino drivertype = getenv("LCD_TYPE");
11086d7f5d3SJohn Marino
11186d7f5d3SJohn Marino while ((ch = getopt(argc, argv, "Dd:f:o:v")) != -1) {
11286d7f5d3SJohn Marino switch(ch) {
11386d7f5d3SJohn Marino case 'D':
11486d7f5d3SJohn Marino debuglevel++;
11586d7f5d3SJohn Marino break;
11686d7f5d3SJohn Marino case 'd':
11786d7f5d3SJohn Marino drivertype = optarg;
11886d7f5d3SJohn Marino break;
11986d7f5d3SJohn Marino case 'f':
12086d7f5d3SJohn Marino devname = optarg;
12186d7f5d3SJohn Marino break;
12286d7f5d3SJohn Marino case 'o':
12386d7f5d3SJohn Marino drvopts = optarg;
12486d7f5d3SJohn Marino break;
12586d7f5d3SJohn Marino case 'v':
12686d7f5d3SJohn Marino vflag = 1;
12786d7f5d3SJohn Marino break;
12886d7f5d3SJohn Marino default:
12986d7f5d3SJohn Marino usage();
13086d7f5d3SJohn Marino }
13186d7f5d3SJohn Marino }
13286d7f5d3SJohn Marino argc -= optind;
13386d7f5d3SJohn Marino argv += optind;
13486d7f5d3SJohn Marino
13586d7f5d3SJohn Marino /* If an LCD type was specified, look it up */
13686d7f5d3SJohn Marino if (drivertype != NULL) {
13786d7f5d3SJohn Marino driver = NULL;
13886d7f5d3SJohn Marino for (i = 0; lcd_drivertab[i].l_code != NULL; i++) {
13986d7f5d3SJohn Marino if (!strcmp(drivertype, lcd_drivertab[i].l_code)) {
14086d7f5d3SJohn Marino driver = &lcd_drivertab[i];
14186d7f5d3SJohn Marino break;
14286d7f5d3SJohn Marino }
14386d7f5d3SJohn Marino }
14486d7f5d3SJohn Marino if (driver == NULL) {
14586d7f5d3SJohn Marino warnx("LCD driver '%s' not known", drivertype);
14686d7f5d3SJohn Marino usage();
14786d7f5d3SJohn Marino }
14886d7f5d3SJohn Marino }
14986d7f5d3SJohn Marino debug(1, "Driver selected for %s", driver->l_name);
15086d7f5d3SJohn Marino driver->l_prepare(devname, drvopts);
15186d7f5d3SJohn Marino atexit(driver->l_finish);
15286d7f5d3SJohn Marino
15386d7f5d3SJohn Marino if (argc > 0) {
15486d7f5d3SJohn Marino debug(2, "reading input from %d argument%s", argc, (argc > 1) ? "s" : "");
15586d7f5d3SJohn Marino for (i = 0; i < argc; i++)
15686d7f5d3SJohn Marino for (cp = argv[i]; *cp; cp++)
15786d7f5d3SJohn Marino do_char(driver, *cp);
15886d7f5d3SJohn Marino } else {
15986d7f5d3SJohn Marino debug(2, "reading input from stdin");
16086d7f5d3SJohn Marino setvbuf(stdin, NULL, _IONBF, 0);
16186d7f5d3SJohn Marino while ((ch = fgetc(stdin)) != EOF)
16286d7f5d3SJohn Marino do_char(driver, (char)ch);
16386d7f5d3SJohn Marino }
16486d7f5d3SJohn Marino exit(EX_OK);
16586d7f5d3SJohn Marino }
16686d7f5d3SJohn Marino
16786d7f5d3SJohn Marino static void
usage(void)16886d7f5d3SJohn Marino usage(void)
16986d7f5d3SJohn Marino {
17086d7f5d3SJohn Marino int i, j;
17186d7f5d3SJohn Marino
17286d7f5d3SJohn Marino fprintf(stderr, "usage: %s [-v] [-d drivername] [-f device] [-o options] [args...]\n", progname);
17386d7f5d3SJohn Marino fprintf(stderr, " -D Increase debugging\n");
17486d7f5d3SJohn Marino fprintf(stderr, " -f Specify device, default is '%s'\n", DEFAULT_DEVICE);
17586d7f5d3SJohn Marino fprintf(stderr, " -d Specify driver, one of:\n");
17686d7f5d3SJohn Marino for (i = 0; lcd_drivertab[i].l_code != NULL; i++) {
17786d7f5d3SJohn Marino fprintf(stderr, " %-10s (%s)%s\n",
17886d7f5d3SJohn Marino lcd_drivertab[i].l_code, lcd_drivertab[i].l_name, (i == 0) ? " *default*" : "");
17986d7f5d3SJohn Marino if (lcd_drivertab[i].l_options[0] != NULL) {
18086d7f5d3SJohn Marino
18186d7f5d3SJohn Marino for (j = 0; lcd_drivertab[i].l_options[j] != NULL; j++)
18286d7f5d3SJohn Marino fprintf(stderr, " %s\n", lcd_drivertab[i].l_options[j]);
18386d7f5d3SJohn Marino }
18486d7f5d3SJohn Marino }
18586d7f5d3SJohn Marino fprintf(stderr, " -o Specify driver option string\n");
18686d7f5d3SJohn Marino fprintf(stderr, " args Message strings. Embedded escapes supported:\n");
18786d7f5d3SJohn Marino fprintf(stderr, " \\b Backspace\n");
18886d7f5d3SJohn Marino fprintf(stderr, " \\f Clear display, home cursor\n");
18986d7f5d3SJohn Marino fprintf(stderr, " \\n Newline\n");
19086d7f5d3SJohn Marino fprintf(stderr, " \\r Carriage return\n");
19186d7f5d3SJohn Marino fprintf(stderr, " \\R Reset display\n");
19286d7f5d3SJohn Marino fprintf(stderr, " \\v Home cursor\n");
19386d7f5d3SJohn Marino fprintf(stderr, " \\\\ Literal \\\n");
19486d7f5d3SJohn Marino fprintf(stderr, " If args not supplied, strings are read from standard input\n");
19586d7f5d3SJohn Marino exit(EX_USAGE);
19686d7f5d3SJohn Marino }
19786d7f5d3SJohn Marino
19886d7f5d3SJohn Marino static void
do_char(struct lcd_driver * driver,char ch)19986d7f5d3SJohn Marino do_char(struct lcd_driver *driver, char ch)
20086d7f5d3SJohn Marino {
20186d7f5d3SJohn Marino static int esc = 0;
20286d7f5d3SJohn Marino
20386d7f5d3SJohn Marino if (esc) {
20486d7f5d3SJohn Marino switch(ch) {
20586d7f5d3SJohn Marino case 'b':
20686d7f5d3SJohn Marino driver->l_command(CMD_BKSP);
20786d7f5d3SJohn Marino break;
20886d7f5d3SJohn Marino case 'f':
20986d7f5d3SJohn Marino driver->l_command(CMD_CLR);
21086d7f5d3SJohn Marino break;
21186d7f5d3SJohn Marino case 'n':
21286d7f5d3SJohn Marino driver->l_command(CMD_NL);
21386d7f5d3SJohn Marino break;
21486d7f5d3SJohn Marino case 'r':
21586d7f5d3SJohn Marino driver->l_command(CMD_CR);
21686d7f5d3SJohn Marino break;
21786d7f5d3SJohn Marino case 'R':
21886d7f5d3SJohn Marino driver->l_command(CMD_RESET);
21986d7f5d3SJohn Marino break;
22086d7f5d3SJohn Marino case 'v':
22186d7f5d3SJohn Marino driver->l_command(CMD_HOME);
22286d7f5d3SJohn Marino break;
22386d7f5d3SJohn Marino case '\\':
22486d7f5d3SJohn Marino driver->l_putc('\\');
22586d7f5d3SJohn Marino break;
22686d7f5d3SJohn Marino default:
22786d7f5d3SJohn Marino driver->l_command(ch);
22886d7f5d3SJohn Marino break;
22986d7f5d3SJohn Marino }
23086d7f5d3SJohn Marino esc = 0;
23186d7f5d3SJohn Marino } else {
23286d7f5d3SJohn Marino if (ch == '\\') {
23386d7f5d3SJohn Marino esc = 1;
23486d7f5d3SJohn Marino } else {
23586d7f5d3SJohn Marino if (vflag || isprint(ch))
23686d7f5d3SJohn Marino driver->l_putc(ch);
23786d7f5d3SJohn Marino }
23886d7f5d3SJohn Marino }
23986d7f5d3SJohn Marino }
24086d7f5d3SJohn Marino
24186d7f5d3SJohn Marino
24286d7f5d3SJohn Marino /******************************************************************************
24386d7f5d3SJohn Marino * Driver for the Hitachi HD44780. This is probably *the* most common driver
24486d7f5d3SJohn Marino * to be found on one- and two-line alphanumeric LCDs.
24586d7f5d3SJohn Marino *
24686d7f5d3SJohn Marino * This driver assumes the following connections :
24786d7f5d3SJohn Marino *
24886d7f5d3SJohn Marino * Parallel Port LCD Module
24986d7f5d3SJohn Marino * --------------------------------
25086d7f5d3SJohn Marino * Strobe (1) Enable (6)
25186d7f5d3SJohn Marino * Data (2-9) Data (7-14)
25286d7f5d3SJohn Marino * Select(13) RS (4)
25386d7f5d3SJohn Marino * Auto Feed (14) R/W (5)
25486d7f5d3SJohn Marino *
25586d7f5d3SJohn Marino * In addition, power must be supplied to the module, normally with
25686d7f5d3SJohn Marino * a circuit similar to this:
25786d7f5d3SJohn Marino *
25886d7f5d3SJohn Marino * VCC (+5V) O------o-------o--------O Module pin 2
25986d7f5d3SJohn Marino * | | +
26086d7f5d3SJohn Marino * / ---
26186d7f5d3SJohn Marino * \ --- 1uF
26286d7f5d3SJohn Marino * / | -
26386d7f5d3SJohn Marino * \ <-----o--------O Module pin 3
26486d7f5d3SJohn Marino * /
26586d7f5d3SJohn Marino * \
26686d7f5d3SJohn Marino * |
26786d7f5d3SJohn Marino * GND O------o----------------O Module pin 1
26886d7f5d3SJohn Marino *
26986d7f5d3SJohn Marino * The ground line should also be connected to the parallel port, on
27086d7f5d3SJohn Marino * one of the ground pins (eg. pin 25).
27186d7f5d3SJohn Marino *
27286d7f5d3SJohn Marino * Note that the pinning on some LCD modules has the odd and even pins
27386d7f5d3SJohn Marino * arranged as though reversed; check carefully before conecting a module
27486d7f5d3SJohn Marino * as it is possible to toast the HD44780 if the power is reversed.
27586d7f5d3SJohn Marino */
27686d7f5d3SJohn Marino
27786d7f5d3SJohn Marino static int hd_fd;
27886d7f5d3SJohn Marino static u_int8_t hd_cbits;
27986d7f5d3SJohn Marino static int hd_lines = 2;
28086d7f5d3SJohn Marino static int hd_blink = 0;
28186d7f5d3SJohn Marino static int hd_cursor = 0;
28286d7f5d3SJohn Marino static int hd_font = 0;
28386d7f5d3SJohn Marino
28486d7f5d3SJohn Marino #define HD_COMMAND SELECTIN
28586d7f5d3SJohn Marino #define HD_DATA 0
28686d7f5d3SJohn Marino #define HD_READ 0
28786d7f5d3SJohn Marino #define HD_WRITE AUTOFEED
28886d7f5d3SJohn Marino
28986d7f5d3SJohn Marino #define HD_BF 0x80 /* internal busy flag */
29086d7f5d3SJohn Marino #define HD_ADDRMASK 0x7f /* DDRAM address mask */
29186d7f5d3SJohn Marino
29286d7f5d3SJohn Marino #define hd_sctrl(v) {u_int8_t _val; _val = hd_cbits | v; ioctl(hd_fd, PPISCTRL, &_val);}
29386d7f5d3SJohn Marino #define hd_sdata(v) {u_int8_t _val; _val = v; ioctl(hd_fd, PPISDATA, &_val);}
29486d7f5d3SJohn Marino #define hd_gdata(v) ioctl(hd_fd, PPIGDATA, &v)
29586d7f5d3SJohn Marino
29686d7f5d3SJohn Marino static void
hd44780_output(int type,int data)29786d7f5d3SJohn Marino hd44780_output(int type, int data)
29886d7f5d3SJohn Marino {
29986d7f5d3SJohn Marino debug(3, "%s -> 0x%02x", (type == HD_COMMAND) ? "cmd " : "data", data);
30086d7f5d3SJohn Marino hd_sctrl(type | HD_WRITE | STROBE); /* set direction, address */
30186d7f5d3SJohn Marino hd_sctrl(type | HD_WRITE); /* raise E */
30286d7f5d3SJohn Marino hd_sdata((u_int8_t) data); /* drive data */
30386d7f5d3SJohn Marino hd_sctrl(type | HD_WRITE | STROBE); /* lower E */
30486d7f5d3SJohn Marino }
30586d7f5d3SJohn Marino
30686d7f5d3SJohn Marino static int
hd44780_input(int type)30786d7f5d3SJohn Marino hd44780_input(int type)
30886d7f5d3SJohn Marino {
30986d7f5d3SJohn Marino u_int8_t val;
31086d7f5d3SJohn Marino
31186d7f5d3SJohn Marino hd_sctrl(type | HD_READ | STROBE); /* set direction, address */
31286d7f5d3SJohn Marino hd_sctrl(type | HD_READ); /* raise E */
31386d7f5d3SJohn Marino hd_gdata(val); /* read data */
31486d7f5d3SJohn Marino hd_sctrl(type | HD_READ | STROBE); /* lower E */
31586d7f5d3SJohn Marino
31686d7f5d3SJohn Marino debug(3, "0x%02x -> %s", val, (type == HD_COMMAND) ? "cmd " : "data");
31786d7f5d3SJohn Marino return(val);
31886d7f5d3SJohn Marino }
31986d7f5d3SJohn Marino
32086d7f5d3SJohn Marino static void
hd44780_prepare(char * devname,char * options)32186d7f5d3SJohn Marino hd44780_prepare(char *devname, char *options)
32286d7f5d3SJohn Marino {
32386d7f5d3SJohn Marino char *cp = options;
32486d7f5d3SJohn Marino
32586d7f5d3SJohn Marino if ((hd_fd = open(devname, O_RDWR, 0)) == -1)
32686d7f5d3SJohn Marino err(EX_OSFILE, "can't open '%s'", devname);
32786d7f5d3SJohn Marino
32886d7f5d3SJohn Marino /* parse options */
32986d7f5d3SJohn Marino while (cp && *cp) {
33086d7f5d3SJohn Marino switch (*cp++) {
33186d7f5d3SJohn Marino case '1':
33286d7f5d3SJohn Marino hd_lines = 1;
33386d7f5d3SJohn Marino break;
33486d7f5d3SJohn Marino case 'B':
33586d7f5d3SJohn Marino hd_blink = 1;
33686d7f5d3SJohn Marino break;
33786d7f5d3SJohn Marino case 'C':
33886d7f5d3SJohn Marino hd_cursor = 1;
33986d7f5d3SJohn Marino break;
34086d7f5d3SJohn Marino case 'F':
34186d7f5d3SJohn Marino hd_font = 1;
34286d7f5d3SJohn Marino break;
34386d7f5d3SJohn Marino default:
34486d7f5d3SJohn Marino errx(EX_USAGE, "hd44780: unknown option code '%c'", *(cp-1));
34586d7f5d3SJohn Marino }
34686d7f5d3SJohn Marino }
34786d7f5d3SJohn Marino
34886d7f5d3SJohn Marino /* Put LCD in idle state */
34986d7f5d3SJohn Marino if (ioctl(hd_fd, PPIGCTRL, &hd_cbits)) /* save other control bits */
35086d7f5d3SJohn Marino err(EX_IOERR, "ioctl PPIGCTRL failed (not a ppi device?)");
35186d7f5d3SJohn Marino hd_cbits &= ~(STROBE | SELECTIN | AUTOFEED); /* set strobe, RS, R/W low */
35286d7f5d3SJohn Marino debug(2, "static control bits 0x%x", hd_cbits);
35386d7f5d3SJohn Marino hd_sctrl(STROBE);
35486d7f5d3SJohn Marino hd_sdata(0);
35586d7f5d3SJohn Marino
35686d7f5d3SJohn Marino }
35786d7f5d3SJohn Marino
35886d7f5d3SJohn Marino static void
hd44780_finish(void)35986d7f5d3SJohn Marino hd44780_finish(void)
36086d7f5d3SJohn Marino {
36186d7f5d3SJohn Marino close(hd_fd);
36286d7f5d3SJohn Marino }
36386d7f5d3SJohn Marino
36486d7f5d3SJohn Marino static void
hd44780_command(int cmd)36586d7f5d3SJohn Marino hd44780_command(int cmd)
36686d7f5d3SJohn Marino {
36786d7f5d3SJohn Marino u_int8_t val;
36886d7f5d3SJohn Marino
36986d7f5d3SJohn Marino switch (cmd) {
37086d7f5d3SJohn Marino case CMD_RESET: /* full manual reset and reconfigure as per datasheet */
37186d7f5d3SJohn Marino debug(1, "hd44780: reset to %d lines, %s font,%s%s cursor",
37286d7f5d3SJohn Marino hd_lines, hd_font ? "5x10" : "5x7", hd_cursor ? "" : " no", hd_blink ? " blinking" : "");
37386d7f5d3SJohn Marino val = 0x30;
37486d7f5d3SJohn Marino if (hd_lines == 2)
37586d7f5d3SJohn Marino val |= 0x08;
37686d7f5d3SJohn Marino if (hd_font)
37786d7f5d3SJohn Marino val |= 0x04;
37886d7f5d3SJohn Marino hd44780_output(HD_COMMAND, val);
37986d7f5d3SJohn Marino usleep(10000);
38086d7f5d3SJohn Marino hd44780_output(HD_COMMAND, val);
38186d7f5d3SJohn Marino usleep(1000);
38286d7f5d3SJohn Marino hd44780_output(HD_COMMAND, val);
38386d7f5d3SJohn Marino usleep(1000);
38486d7f5d3SJohn Marino val = 0x08; /* display off */
38586d7f5d3SJohn Marino hd44780_output(HD_COMMAND, val);
38686d7f5d3SJohn Marino usleep(1000);
38786d7f5d3SJohn Marino val |= 0x04; /* display on */
38886d7f5d3SJohn Marino if (hd_cursor)
38986d7f5d3SJohn Marino val |= 0x02;
39086d7f5d3SJohn Marino if (hd_blink)
39186d7f5d3SJohn Marino val |= 0x01;
39286d7f5d3SJohn Marino hd44780_output(HD_COMMAND, val);
39386d7f5d3SJohn Marino usleep(1000);
39486d7f5d3SJohn Marino hd44780_output(HD_COMMAND, 0x06); /* shift cursor by increment */
39586d7f5d3SJohn Marino usleep(1000);
39686d7f5d3SJohn Marino /* FALLTHROUGH */
39786d7f5d3SJohn Marino
39886d7f5d3SJohn Marino case CMD_CLR:
39986d7f5d3SJohn Marino hd44780_output(HD_COMMAND, 0x01);
40086d7f5d3SJohn Marino usleep(2000);
40186d7f5d3SJohn Marino break;
40286d7f5d3SJohn Marino
40386d7f5d3SJohn Marino case CMD_BKSP:
40486d7f5d3SJohn Marino hd44780_output(HD_DATA, 0x10); /* shift cursor left one */
40586d7f5d3SJohn Marino break;
40686d7f5d3SJohn Marino
40786d7f5d3SJohn Marino case CMD_NL:
40886d7f5d3SJohn Marino if (hd_lines == 2)
40986d7f5d3SJohn Marino hd44780_output(HD_COMMAND, 0xc0); /* beginning of second line */
41086d7f5d3SJohn Marino break;
41186d7f5d3SJohn Marino
41286d7f5d3SJohn Marino case CMD_CR:
41386d7f5d3SJohn Marino /* XXX will not work in 4-line mode, or where readback fails */
41486d7f5d3SJohn Marino val = hd44780_input(HD_COMMAND) & 0x3f; /* mask character position, save line pos */
41586d7f5d3SJohn Marino hd44780_output(HD_COMMAND, 0x80 | val);
41686d7f5d3SJohn Marino break;
41786d7f5d3SJohn Marino
41886d7f5d3SJohn Marino case CMD_HOME:
41986d7f5d3SJohn Marino hd44780_output(HD_COMMAND, 0x02);
42086d7f5d3SJohn Marino usleep(2000);
42186d7f5d3SJohn Marino break;
42286d7f5d3SJohn Marino
42386d7f5d3SJohn Marino default:
42486d7f5d3SJohn Marino if (isprint(cmd)) {
42586d7f5d3SJohn Marino warnx("unknown command %c", cmd);
42686d7f5d3SJohn Marino } else {
42786d7f5d3SJohn Marino warnx("unknown command 0x%x", cmd);
42886d7f5d3SJohn Marino }
42986d7f5d3SJohn Marino }
43086d7f5d3SJohn Marino usleep(40);
43186d7f5d3SJohn Marino }
43286d7f5d3SJohn Marino
43386d7f5d3SJohn Marino static void
hd44780_putc(int c)43486d7f5d3SJohn Marino hd44780_putc(int c)
43586d7f5d3SJohn Marino {
43686d7f5d3SJohn Marino hd44780_output(HD_DATA, c);
43786d7f5d3SJohn Marino usleep(40);
43886d7f5d3SJohn Marino }
43986d7f5d3SJohn Marino
440