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