Character device driver

  • In this section, you are going to learn

  • How to write a Character Device Driver module ?

#

Version

Freebsd

14.1.0

  • Create directory using mkdir command

test:~$ pwd
/home/test/

test:~$ mkdir char_device_drivers

test:~$ cd char_device_drivers

test:~$ pwd
home/test/char_device_drivers
  • Architecture

test:~$
test:~$

Source path :

c1

Bin path :

c2

List of C files

c3

NM output :

c4

Load file :

c5

  1#include <sys/types.h>
  2#include <sys/systm.h>  /* uprintf */
  3#include <sys/param.h>  /* defines used in kernel.h */
  4#include <sys/module.h>
  5#include <sys/kernel.h> /* types used in module initialization */
  6#include <sys/conf.h>   /* cdevsw struct */
  7#include <sys/uio.h>    /* uio struct */
  8#include <sys/malloc.h>
  9
 10#define BUFFERSIZE 255
 11
 12/* Function prototypes */
 13static d_open_t      echo_open;
 14static d_close_t     echo_close;
 15static d_read_t      echo_read;
 16static d_write_t     echo_write;
 17
 18/* Character device entry points */
 19static struct cdevsw echo_cdevsw = {
 20	.d_version = D_VERSION,
 21	.d_open = echo_open,
 22	.d_close = echo_close,
 23	.d_read = echo_read,
 24	.d_write = echo_write,
 25	.d_name = "echo",
 26};
 27
 28struct s_echo {
 29	char msg[BUFFERSIZE + 1];
 30	int len;
 31};
 32
 33/* vars */
 34static struct cdev *echo_dev;
 35static struct s_echo *echomsg;
 36
 37MALLOC_DECLARE(M_ECHOBUF);
 38MALLOC_DEFINE(M_ECHOBUF, "echobuffer", "buffer for echo module");
 39
 40static int
 41echo_loader(struct module *m __unused, int what, void *arg __unused)
 42{
 43	int error = 0;
 44
 45	switch (what) {
 46	case MOD_LOAD:                /* kldload */
 47		error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK,
 48		    &echo_dev,
 49		    &echo_cdevsw,
 50		    0,
 51		    UID_ROOT,
 52		    GID_WHEEL,
 53		    0600,
 54		    "echo");
 55		if (error != 0)
 56			break;
 57
 58		echomsg = malloc(sizeof(*echomsg), M_ECHOBUF, M_WAITOK |
 59		    M_ZERO);
 60		printf("Echo device loaded.\n");
 61		break;
 62	case MOD_UNLOAD:
 63		destroy_dev(echo_dev);
 64		free(echomsg, M_ECHOBUF);
 65		printf("Echo device unloaded.\n");
 66		break;
 67	default:
 68		error = EOPNOTSUPP;
 69		break;
 70	}
 71	return (error);
 72}
 73
 74static int
 75echo_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused,
 76    struct thread *td __unused)
 77{
 78	int error = 0;
 79
 80	uprintf("Opened device \"echo\" successfully.\n");
 81	return (error);
 82}
 83
 84static int
 85echo_close(struct cdev *dev __unused, int fflag __unused, int devtype __unused,
 86    struct thread *td __unused)
 87{
 88
 89	uprintf("\nClosing device \"echo\".\n");
 90	return (0);
 91}
 92
 93static int
 94echo_read(struct cdev *dev __unused, struct uio *uio, int ioflag __unused)
 95{
 96	size_t amt;
 97	int error;
 98
 99	amt = MIN(uio->uio_resid, uio->uio_offset >= echomsg->len + 1 ? 0 :
100	    echomsg->len + 1 - uio->uio_offset);
101
102	if ((error = uiomove(echomsg->msg, amt, uio)) != 0)
103		uprintf("uiomove failed!\n");
104
105	return (error);
106}
107
108static int
109echo_write(struct cdev *dev __unused, struct uio *uio, int ioflag __unused)
110{
111	size_t amt;
112	int error;
113
114	if (uio->uio_offset != 0 && (uio->uio_offset != echomsg->len))
115		return (EINVAL);
116
117	/* This is a new message, reset length */
118	if (uio->uio_offset == 0)
119		echomsg->len = 0;
120
121	/* Copy the string in from user memory to kernel memory */
122	amt = MIN(uio->uio_resid, (BUFFERSIZE - echomsg->len));
123
124	error = uiomove(echomsg->msg + uio->uio_offset, amt, uio);
125
126	/* Now we need to null terminate and record the length */
127	echomsg->len = uio->uio_offset;
128	echomsg->msg[echomsg->len] = 0;
129
130	if (error != 0)
131		uprintf("Write failed: bad address!\n");
132	return (error);
133}
134
135DEV_MODULE(echo, echo_loader, NULL);
1SRCS=char.c
2KMOD=echo
3
4.include <bsd.kmod.mk>
1test:~$ pwd
2home/test/char_device_drivers
3
4
5test:~$ ls
6char.c  Makefile  README
7
8
9test:~$ make
1test:~$ kldload -v ./echo.ko
1test:~$ dmesg
2Echo device loaded.
  • Writing data to the driver (/dev/echo)

1test:~$ echo -n "Test Data" > /dev/echo
2Opened device "echo" successfully.
3
4Closing device "echo".
  • Reading data from the driver (/dev/echo)

1test:~$ cat /dev/echo
2Opened device "echo" successfully.
3Test Data
4Closing device "echo".
1test:~$ kldunload echo
1test:~$ dmesg
2Echo device unloaded.
  • Open nl80211.c file with vim, add prints in all .doit functions in nl80211_small_ops

test:~$
  • Open nl80211.c file with vim, add prints in all .doit functions in nl80211_small_ops

test:~$
test:~$
test:~$