xref: /netbsd-src/share/examples/pud/intro/intro.c (revision cf9f5c8530982075f56250ec6a6bd48841a206dc)
1 /*	$NetBSD: intro.c,v 1.2 2007/11/21 18:11:17 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 #define DEFALLOC 1024*1024
31 #define ECHOSTR "Would you like some sauce diable with that?\n"
32 
33 #ifndef MIN
34 #define MIN(a,b) ((a)<(b)?(a):(b))
35 #endif
36 
37 int
38 main(int argc, char *argv[])
39 {
40 	struct pud_req *pdr = malloc(DEFALLOC);
41 	struct pud_conf_reg pcr;
42 	int fd;
43 	ssize_t n;
44 
45 	if (argc != 2)
46 		errx(1, "args");
47 
48 	/*
49 	 * open pud device
50 	 */
51 	fd = open(argv[1], O_RDWR);
52 	if (fd == -1)
53 		err(1, "open");
54 
55 	/*
56 	 * register our major number
57 	 */
58 	memset(&pcr, 0, sizeof(pcr));
59 	pcr.pm_pdr.pdr_pth.pth_framelen = sizeof(struct pud_conf_reg);
60 	pcr.pm_pdr.pdr_reqclass = PUD_REQ_CONF;
61 	pcr.pm_pdr.pdr_reqtype = PUD_CONF_REG;
62 
63 	pcr.pm_regdev = makedev(377, 0);
64 	pcr.pm_flags = PUD_CONFFLAG_BDEV;
65 	strlcpy(pcr.pm_devname, "testdev", sizeof(pcr.pm_devname));
66 
67 	n = write(fd, &pcr, pcr.pm_pdr.pdr_pth.pth_framelen);
68 	if (n == -1)
69 		err(1, "configure write");
70 
71 	/*
72 	 * process requests
73 	 */
74 	for (;;) {
75 		n = read(fd, pdr, DEFALLOC);
76 		printf("read %d %d\n", n, errno);
77 
78 		switch (pdr->pdr_reqtype) {
79 		case PUD_CDEV_OPEN:
80 		case PUD_CDEV_CLOSE:
81 			printf("got openclose %d\n", pdr->pdr_reqtype);
82 			pdr->pdr_rv = 0;
83 			break;
84 
85 		case PUD_CDEV_READ:
86 		/* uh oh case PUD_BDEV_STRATREAD: */
87 		{
88 			struct pud_creq_read *pc_read;
89 			size_t clen;
90 
91 			pc_read = (void *)pdr;
92 			printf("read from offset %llu, resid %zu\n",
93 			    (unsigned long long)pc_read->pm_offset,
94 			    pc_read->pm_resid);
95 
96 			clen = MIN(strlen(ECHOSTR), pc_read->pm_resid);
97 			strncpy(pc_read->pm_data, ECHOSTR, clen);
98 			if (pdr->pdr_reqclass == PUD_REQ_BDEV) {
99 				clen = pc_read->pm_resid;
100 				pc_read->pm_resid = 0;
101 			} else {
102 				pc_read->pm_resid -= clen;
103 			}
104 			pdr->pdr_pth.pth_framelen =
105 			    sizeof(struct pud_creq_read) + clen;
106 		}
107 			break;
108 
109 		case PUD_CDEV_WRITE:
110 		/* uh uh oh case PUD_BDEV_STRATWRITE: */
111 		{
112 			struct pud_creq_write *pc_write;
113 
114 			pc_write = (void *)pdr;
115 			printf("write to offset %llu, resid %zu\n",
116 			    (unsigned long long)pc_write->pm_offset,
117 			    pc_write->pm_resid);
118 
119 			pc_write->pm_data[pc_write->pm_resid] = '\0';
120 			printf("got via write: %s", pc_write->pm_data);
121 			pdr->pdr_pth.pth_framelen =
122 			    sizeof(struct pud_creq_write);
123 			pc_write->pm_resid = 0;
124 		}
125 			break;
126 
127 		default:
128 			abort();
129 		}
130 
131 		n = write(fd, pdr, pdr->pdr_pth.pth_framelen);
132 		printf("wrote %d %d\n", n, errno);
133 	}
134 }
135