1/*	$NetBSD: intro.c,v 1.3 2007/11/22 11:28:49 pooka Exp $	*/
2
3/*
4 * El extra-simplo example of the userspace driver framework.
5 *
6 * Eventually there will be a library a la libpuffs (perhaps,
7 * gasp, even the same lib), but for now it's all manual until
8 * I get it figured out.
9 *
10 * So how to run this?
11 * 0) sh MAKEDEV putter (if you don't have a freshly created /dev)
12 * 1) run this program with the argument "/dev/pud"
13 * 2) mknod a char device with the major 377 (see sources below)
14 * 3) echo ascii art and jokes into device created in previous step
15 *    or read the device
16 */
17
18#include <sys/types.h>
19
20#include <dev/pud/pud_msgif.h>
21
22#include <err.h>
23#include <errno.h>
24#include <fcntl.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29
30#include "common.h"
31
32#define DEFALLOC 1024*1024
33#define ECHOSTR1 "Would you like some sauce diable with that?\n"
34#define ECHOSTR2 "Nej tack, you fool, I'm happy with my tournedos Rossini\n"
35#define NSTR 2
36
37const char *curstr = ECHOSTR1;
38
39#ifndef MIN
40#define MIN(a,b) ((a)<(b)?(a):(b))
41#endif
42
43int
44main(int argc, char *argv[])
45{
46	struct pud_req *pdr = malloc(DEFALLOC);
47	struct pud_conf_reg pcr;
48	int fd;
49	ssize_t n;
50
51	if (argc != 2)
52		errx(1, "args");
53
54	/*
55	 * open pud device
56	 */
57	fd = open(argv[1], O_RDWR);
58	if (fd == -1)
59		err(1, "open");
60
61	/*
62	 * register our major number
63	 */
64	memset(&pcr, 0, sizeof(pcr));
65	pcr.pm_pdr.pdr_pth.pth_framelen = sizeof(struct pud_conf_reg);
66	pcr.pm_version = PUD_DEVELVERSION | PUD_VERSION;
67	pcr.pm_pdr.pdr_reqclass = PUD_REQ_CONF;
68	pcr.pm_pdr.pdr_reqtype = PUD_CONF_REG;
69
70	pcr.pm_regdev = makedev(377, 0);
71	pcr.pm_flags = PUD_CONFFLAG_BDEV;
72	strlcpy(pcr.pm_devname, "testdev", sizeof(pcr.pm_devname));
73
74	n = write(fd, &pcr, pcr.pm_pdr.pdr_pth.pth_framelen);
75	if (n == -1)
76		err(1, "configure write");
77
78	/*
79	 * process requests
80	 */
81	for (;;) {
82		n = read(fd, pdr, DEFALLOC);
83		printf("read %d %d\n", n, errno);
84
85		switch (pdr->pdr_reqtype) {
86		case PUD_CDEV_OPEN:
87		case PUD_CDEV_CLOSE:
88			printf("got openclose %d\n", pdr->pdr_reqtype);
89			pdr->pdr_rv = 0;
90			break;
91
92		case PUD_CDEV_READ:
93		/* uh oh case PUD_BDEV_STRATREAD: */
94		{
95			struct pud_creq_read *pc_read;
96			size_t clen;
97
98			pc_read = (void *)pdr;
99			printf("read from offset %llu, resid %zu\n",
100			    (unsigned long long)pc_read->pm_offset,
101			    pc_read->pm_resid);
102
103			clen = MIN(strlen(curstr), pc_read->pm_resid);
104			strncpy(pc_read->pm_data, curstr, clen);
105			if (pdr->pdr_reqclass == PUD_REQ_BDEV) {
106				clen = pc_read->pm_resid;
107				pc_read->pm_resid = 0;
108			} else {
109				pc_read->pm_resid -= clen;
110			}
111			pdr->pdr_pth.pth_framelen =
112			    sizeof(struct pud_creq_read) + clen;
113		}
114			break;
115
116		case PUD_CDEV_WRITE:
117		/* uh uh oh case PUD_BDEV_STRATWRITE: */
118		{
119			struct pud_creq_write *pc_write;
120
121			pc_write = (void *)pdr;
122			printf("write to offset %llu, resid %zu\n",
123			    (unsigned long long)pc_write->pm_offset,
124			    pc_write->pm_resid);
125
126			pc_write->pm_data[pc_write->pm_resid] = '\0';
127			printf("got via write: %s", pc_write->pm_data);
128			pdr->pdr_pth.pth_framelen =
129			    sizeof(struct pud_creq_write);
130			pc_write->pm_resid = 0;
131		}
132			break;
133
134		case PUD_CDEV_IOCTL:
135		{
136			struct pud_req_ioctl *pc_ioctl;
137			int *iocval;
138
139			pc_ioctl = (void *)pdr;
140			switch (pc_ioctl->pm_iocmd) {
141			case INTROTOGGLE:
142			case INTROTOGGLE_R:
143				iocval = (int *)pc_ioctl->pm_data;
144				if (*iocval < 0 || *iocval > 2) {
145					pdr->pdr_rv = ERANGE;
146					break;
147				}
148
149				if (*iocval == 1)
150					curstr = ECHOSTR1;
151				else
152					curstr = ECHOSTR2;
153
154				*iocval = 0;
155				break;
156			default:
157				abort();
158			}
159		}
160			break;
161
162		default:
163			abort();
164		}
165
166		n = write(fd, pdr, pdr->pdr_pth.pth_framelen);
167		printf("wrote %d %d\n", n, errno);
168	}
169}
170