xref: /netbsd-src/share/examples/pud/intro/intro.c (revision a4b032e2c8dedbb826547920ffe49398315801c3)
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 
37 const char *curstr = ECHOSTR1;
38 
39 #ifndef MIN
40 #define MIN(a,b) ((a)<(b)?(a):(b))
41 #endif
42 
43 int
44 main(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_pdr.pdr_reqclass = PUD_REQ_CONF;
67 	pcr.pm_pdr.pdr_reqtype = PUD_CONF_REG;
68 
69 	pcr.pm_regdev = makedev(377, 0);
70 	pcr.pm_flags = PUD_CONFFLAG_BDEV;
71 	strlcpy(pcr.pm_devname, "testdev", sizeof(pcr.pm_devname));
72 
73 	n = write(fd, &pcr, pcr.pm_pdr.pdr_pth.pth_framelen);
74 	if (n == -1)
75 		err(1, "configure write");
76 
77 	/*
78 	 * process requests
79 	 */
80 	for (;;) {
81 		n = read(fd, pdr, DEFALLOC);
82 		printf("read %d %d\n", n, errno);
83 
84 		switch (pdr->pdr_reqtype) {
85 		case PUD_CDEV_OPEN:
86 		case PUD_CDEV_CLOSE:
87 			printf("got openclose %d\n", pdr->pdr_reqtype);
88 			pdr->pdr_rv = 0;
89 			break;
90 
91 		case PUD_CDEV_READ:
92 		/* uh oh case PUD_BDEV_STRATREAD: */
93 		{
94 			struct pud_creq_read *pc_read;
95 			size_t clen;
96 
97 			pc_read = (void *)pdr;
98 			printf("read from offset %llu, resid %zu\n",
99 			    (unsigned long long)pc_read->pm_offset,
100 			    pc_read->pm_resid);
101 
102 			clen = MIN(strlen(curstr), pc_read->pm_resid);
103 			strncpy(pc_read->pm_data, curstr, clen);
104 			if (pdr->pdr_reqclass == PUD_REQ_BDEV) {
105 				clen = pc_read->pm_resid;
106 				pc_read->pm_resid = 0;
107 			} else {
108 				pc_read->pm_resid -= clen;
109 			}
110 			pdr->pdr_pth.pth_framelen =
111 			    sizeof(struct pud_creq_read) + clen;
112 		}
113 			break;
114 
115 		case PUD_CDEV_WRITE:
116 		/* uh uh oh case PUD_BDEV_STRATWRITE: */
117 		{
118 			struct pud_creq_write *pc_write;
119 
120 			pc_write = (void *)pdr;
121 			printf("write to offset %llu, resid %zu\n",
122 			    (unsigned long long)pc_write->pm_offset,
123 			    pc_write->pm_resid);
124 
125 			pc_write->pm_data[pc_write->pm_resid] = '\0';
126 			printf("got via write: %s", pc_write->pm_data);
127 			pdr->pdr_pth.pth_framelen =
128 			    sizeof(struct pud_creq_write);
129 			pc_write->pm_resid = 0;
130 		}
131 			break;
132 
133 		case PUD_CDEV_IOCTL:
134 		{
135 			struct pud_req_ioctl *pc_ioctl;
136 			int *iocval;
137 
138 			pc_ioctl = (void *)pdr;
139 			switch (pc_ioctl->pm_iocmd) {
140 			case INTROTOGGLE:
141 			case INTROTOGGLE_R:
142 				iocval = (int *)pc_ioctl->pm_data;
143 				if (*iocval < 0 || *iocval > 2) {
144 					pdr->pdr_rv = ERANGE;
145 					break;
146 				}
147 
148 				if (*iocval == 1)
149 					curstr = ECHOSTR1;
150 				else
151 					curstr = ECHOSTR2;
152 
153 				*iocval = 0;
154 				break;
155 			default:
156 				abort();
157 			}
158 		}
159 			break;
160 
161 		default:
162 			abort();
163 		}
164 
165 		n = write(fd, pdr, pdr->pdr_pth.pth_framelen);
166 		printf("wrote %d %d\n", n, errno);
167 	}
168 }
169