commit 18693b9b2654b84d0913df54ed27c57510120f9f
parent 159798155e8ac5a3543bd29aed523ba0f2b4b831
Author: Christos Margiolis <christos@margiolis.net>
Date: Mon, 6 Mar 2023 16:37:20 +0200
improve mydev
Diffstat:
3 files changed, 87 insertions(+), 36 deletions(-)
diff --git a/mydev_freebsd/mydev.c b/mydev_freebsd/mydev.c
@@ -1,12 +1,24 @@
+#include <sys/types.h>
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
+#include <sys/malloc.h>
#include <sys/uio.h>
#include "mydev.h"
+#define BUFSIZE (1 << 16)
+
+MALLOC_DECLARE(M_MYDEV);
+MALLOC_DEFINE(M_MYDEV, "mydev", "test device");
+
+typedef struct {
+ char buf[BUFSIZE + 1];
+ size_t len;
+} foo_t;
+
static d_open_t mydev_open;
static d_close_t mydev_close;
static d_read_t mydev_read;
@@ -26,6 +38,7 @@ static struct cdevsw mydev_cdevsw = {
};
static struct cdev *mydev_cdev;
+static foo_t *foo;
static int
mydev_open(struct cdev *dev, int flags, int devtype, struct thread *td)
@@ -46,11 +59,23 @@ mydev_close(struct cdev *dev, int flags, int devtype, struct thread *td)
static int
mydev_read(struct cdev *dev, struct uio *uio, int ioflag)
{
- char buf[32];
- int error = 0;
+ size_t amnt;
+ int v, error = 0;
+
+ /*
+ * Determine how many bytes we have to read. We'll either read the
+ * remaining bytes (uio->uio_resid) or the number of bytes requested by
+ * the caller.
+ */
+ v = uio->uio_offset >= foo->len + 1 ? 0 : foo->len + 1 - uio->uio_offset;
+ amnt = MIN(uio->uio_resid, v);
- strlcpy(buf, "reading from mydev", sizeof(buf));
- error = uiomove(buf, sizeof(buf), uio);
+ /* Move the bytes from foo->buf to uio. */
+ if ((error = uiomove(foo->buf, amnt, uio)) != 0)
+ uprintf("uiomove failed\n");
+
+ if (!foo->len)
+ uprintf("nothing to read\n");
return (error);
}
@@ -58,9 +83,23 @@ mydev_read(struct cdev *dev, struct uio *uio, int ioflag)
static int
mydev_write(struct cdev *dev, struct uio *uio, int ioflag)
{
+ size_t amnt;
int error = 0;
- uprintf("mydev: %s\n", (char *)uio->uio_iov->iov_base);
+ /* Do not allow random access. */
+ if (uio->uio_offset != 0 && (uio->uio_offset != foo->len))
+ return (EINVAL);
+
+ /* We're not appending, reset length. */
+ else if (uio->uio_offset == 0)
+ foo->len = 0;
+
+ amnt = MIN(uio->uio_resid, (BUFSIZE - foo->len));
+ if ((error = uiomove(foo->buf + uio->uio_offset, amnt, uio)) != 0)
+ uprintf("uiomove failed");
+
+ foo->len = uio->uio_offset;
+ foo->buf[foo->len] = '\0';
return (error);
}
@@ -69,24 +108,23 @@ static int
mydev_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
struct thread *td)
{
- foo_t *fp;
+ bar_t *bp;
int error = 0;
switch (cmd) {
case MYDEVIOC_READ:
- fp = (foo_t *)addr;
- fp->x = 10;
- fp->y = 20;
+ bp = (bar_t *)addr;
+ bp->x = 100;
+ bp->y = 300;
break;
case MYDEVIOC_WRITE:
- fp = (foo_t *)addr;
- uprintf("mydev: x=%d, y=%d\n", fp->x, fp->y);
+ bp = (bar_t *)addr;
+ uprintf("/dev/mydev: x=%d, y=%d\n", bp->x, bp->y);
break;
case MYDEVIOC_RDWR:
- fp = (foo_t *)addr;
- uprintf("mydev: received: x=%d, y=%d\n", fp->x, fp->y);
- fp->x += 5;
- fp->y += 5;
+ bp = (bar_t *)addr;
+ bp->x += 15;
+ bp->y += 30;
break;
default:
error = ENOTTY;
@@ -105,9 +143,13 @@ mydev_modevent(module_t mod, int type, void *arg)
case MOD_LOAD:
mydev_cdev = make_dev(&mydev_cdevsw, 0, UID_ROOT, GID_WHEEL,
0666, "mydev");
+ foo = malloc(sizeof(foo_t), M_MYDEV, M_WAITOK | M_ZERO);
+ foo->buf[0] = '\0';
+ foo->len = 0;
break;
case MOD_UNLOAD: /* FALLTHROUGH */
case MOD_SHUTDOWN:
+ free(foo, M_MYDEV);
destroy_dev(mydev_cdev);
break;
default:
diff --git a/mydev_freebsd/mydev.h b/mydev_freebsd/mydev.h
@@ -1,15 +1,16 @@
#ifndef _MYDEV_H_
#define _MYDEV_H_
+#include <sys/types.h>
#include <sys/ioccom.h>
typedef struct {
int x;
int y;
-} foo_t;
+} bar_t;
-#define MYDEVIOC_READ _IOR('a', 1, foo_t)
-#define MYDEVIOC_WRITE _IOW('a', 2, foo_t)
-#define MYDEVIOC_RDWR _IOWR('a', 3, foo_t)
+#define MYDEVIOC_READ _IOR('a', 1, bar_t)
+#define MYDEVIOC_WRITE _IOW('a', 2, bar_t)
+#define MYDEVIOC_RDWR _IOWR('a', 3, bar_t)
#endif /* _MYDEV_H_ */
diff --git a/mydev_freebsd/mydev_test.c b/mydev_freebsd/mydev_test.c
@@ -10,35 +10,43 @@
int
main(int argc, char *argv[])
{
- foo_t foo;
- char buf[32];
- int dev;
+ bar_t bar;
+ char buf[BUFSIZ];
+ int fd;
- if ((dev = open("/dev/mydev", O_RDWR)) < 0)
+ if ((fd = open("/dev/mydev", O_RDWR)) < 0)
err(1, "open(/dev/mydev)");
- if (ioctl(dev, MYDEVIOC_READ, &foo) != 0)
+ if (ioctl(fd, MYDEVIOC_READ, &bar) != 0)
err(1, "ioctl(MYDEVIOC_READ)");
- printf("%s: x=%d, y=%d\n", getprogname(), foo.x, foo.y);
+ printf("%s: ioctl(MYDEVIOC_READ)\t-> x=%d, y=%d\n",
+ getprogname(), bar.x, bar.y);
- foo.x = 1;
- foo.y = 2;
- if (ioctl(dev, MYDEVIOC_WRITE, &foo) != 0)
+ printf("%s: ioctl(MYDEVIOC_WRITE)\t-> ", getprogname());
+ fflush(stdout);
+
+ bar.x = 10;
+ bar.y = 20;
+ if (ioctl(fd, MYDEVIOC_WRITE, &bar) != 0)
err(1, "ioctl(MYDEVIOC_WRITE)");
- if (ioctl(dev, MYDEVIOC_RDWR, &foo) != 0)
+ if (ioctl(fd, MYDEVIOC_RDWR, &bar) != 0)
err(1, "ioctl(MYDEVIOC_RDWR)");
- printf("%s received: x=%d, y=%d\n", getprogname(), foo.x, foo.y);
+ printf("%s: ioctl(MYDEVIOC_RDWR)\t-> x=%d, y=%d\n",
+ getprogname(), bar.x, bar.y);
- if (read(dev, buf, sizeof(buf)) < 0)
- err(1, "read");
- printf("%s: %s\n", getprogname(), buf);
+ (void)strlcpy(buf, "hello from test program", sizeof(buf));
- strlcpy(buf, "writing to mydev", sizeof(buf));
- if (write(dev, buf, sizeof(buf)) < 0)
+ printf("%s: write()\t\t\t-> %s\n", getprogname(), buf);
+ fflush(stdout);
+
+ if (write(fd, buf, sizeof(buf)) < 0)
err(1, "write");
+ if (read(fd, buf, sizeof(buf)) < 0)
+ err(1, "read");
+ printf("%s: read()\t\t\t-> %s\n", getprogname(), buf);
- close(dev);
+ close(fd);
return (0);
}