1 /*        $NetBSD: intro.c,v 1.4 2007/11/28 16:59:02 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
main(int argc,char * argv[])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_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