intro.c revision 1.3 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