xref: /dflybsd-src/share/examples/ppi/ppilcd.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
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