random

:-)
git clone read: git://git.margiolis.net/random.git
Log | Files | Refs | LICENSE

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);