mydev.c (3249B)
1 #include <sys/types.h> 2 #include <sys/param.h> 3 #include <sys/conf.h> 4 #include <sys/systm.h> 5 #include <sys/kernel.h> 6 #include <sys/module.h> 7 #include <sys/malloc.h> 8 #include <sys/uio.h> 9 10 #include "mydev.h" 11 12 #define BUFSIZE (1 << 16) 13 14 MALLOC_DECLARE(M_MYDEV); 15 MALLOC_DEFINE(M_MYDEV, "mydev", "test device"); 16 17 typedef struct { 18 char buf[BUFSIZE + 1]; 19 size_t len; 20 } foo_t; 21 22 static d_open_t mydev_open; 23 static d_close_t mydev_close; 24 static d_read_t mydev_read; 25 static d_write_t mydev_write; 26 static d_ioctl_t mydev_ioctl; 27 static int mydev_modevent(module_t, int, void *); 28 29 static struct cdevsw mydev_cdevsw = { 30 .d_name = "mydev", 31 .d_version = D_VERSION, 32 .d_flags = D_TRACKCLOSE, 33 .d_open = mydev_open, 34 .d_close = mydev_close, 35 .d_read = mydev_read, 36 .d_write = mydev_write, 37 .d_ioctl = mydev_ioctl, 38 }; 39 40 static struct cdev *mydev_cdev; 41 static foo_t *foo; 42 43 static int 44 mydev_open(struct cdev *dev, int flags, int devtype, struct thread *td) 45 { 46 uprintf("mydev: device opened\n"); 47 48 return (0); 49 } 50 51 static int 52 mydev_close(struct cdev *dev, int flags, int devtype, struct thread *td) 53 { 54 uprintf("mydev: device closed\n"); 55 56 return (0); 57 } 58 59 static int 60 mydev_read(struct cdev *dev, struct uio *uio, int ioflag) 61 { 62 size_t amnt; 63 int v, error = 0; 64 65 /* 66 * Determine how many bytes we have to read. We'll either read the 67 * remaining bytes (uio->uio_resid) or the number of bytes requested by 68 * the caller. 69 */ 70 v = uio->uio_offset >= foo->len + 1 ? 0 : foo->len + 1 - uio->uio_offset; 71 amnt = MIN(uio->uio_resid, v); 72 73 /* Move the bytes from foo->buf to uio. */ 74 if ((error = uiomove(foo->buf, amnt, uio)) != 0) 75 uprintf("uiomove failed\n"); 76 77 if (!foo->len) 78 uprintf("nothing to read\n"); 79 80 return (error); 81 } 82 83 static int 84 mydev_write(struct cdev *dev, struct uio *uio, int ioflag) 85 { 86 size_t amnt; 87 int error = 0; 88 89 /* Do not allow random access. */ 90 if (uio->uio_offset != 0 && (uio->uio_offset != foo->len)) 91 return (EINVAL); 92 93 /* We're not appending, reset length. */ 94 else if (uio->uio_offset == 0) 95 foo->len = 0; 96 97 amnt = MIN(uio->uio_resid, (BUFSIZE - foo->len)); 98 if ((error = uiomove(foo->buf + uio->uio_offset, amnt, uio)) != 0) 99 uprintf("uiomove failed"); 100 101 foo->len = uio->uio_offset; 102 foo->buf[foo->len] = '\0'; 103 104 return (error); 105 } 106 107 static int 108 mydev_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, 109 struct thread *td) 110 { 111 bar_t *bp; 112 int error = 0; 113 114 switch (cmd) { 115 case MYDEVIOC_READ: 116 bp = (bar_t *)addr; 117 bp->x = 100; 118 bp->y = 300; 119 break; 120 case MYDEVIOC_WRITE: 121 bp = (bar_t *)addr; 122 uprintf("/dev/mydev: x=%d, y=%d\n", bp->x, bp->y); 123 break; 124 case MYDEVIOC_RDWR: 125 bp = (bar_t *)addr; 126 bp->x += 15; 127 bp->y += 30; 128 break; 129 default: 130 error = ENOTTY; 131 break; 132 } 133 134 return (error); 135 } 136 137 static int 138 mydev_modevent(module_t mod, int type, void *arg) 139 { 140 int error = 0; 141 142 switch (type) { 143 case MOD_LOAD: 144 mydev_cdev = make_dev(&mydev_cdevsw, 0, UID_ROOT, GID_WHEEL, 145 0666, "mydev"); 146 foo = malloc(sizeof(foo_t), M_MYDEV, M_WAITOK | M_ZERO); 147 foo->buf[0] = '\0'; 148 foo->len = 0; 149 break; 150 case MOD_UNLOAD: /* FALLTHROUGH */ 151 case MOD_SHUTDOWN: 152 free(foo, M_MYDEV); 153 destroy_dev(mydev_cdev); 154 break; 155 default: 156 error = EOPNOTSUPP; 157 break; 158 } 159 160 return (error); 161 } 162 163 DEV_MODULE(mydev, mydev_modevent, NULL);