diff --git a/en_US.ISO8859-1/books/arch-handbook/driverbasics/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/driverbasics/chapter.sgml index 29cf0a05cb..52d27534ad 100644 --- a/en_US.ISO8859-1/books/arch-handbook/driverbasics/chapter.sgml +++ b/en_US.ISO8859-1/books/arch-handbook/driverbasics/chapter.sgml @@ -1,362 +1,379 @@ - - Writing FreeBSD Device Drivers - - This chapter was written by Murray Stokely with selections from - a variety of sources including the intro(4) man page by Joerg - Wunsch. - - - Introduction - - This chapter provides a brief introduction to writing device - drivers for FreeBSD. A device in this context is a term used - mostly for hardware-related stuff that belongs to the system, - like disks, printers, or a graphics display with its keyboard. - A device driver is the software component of the operating - system that controls a specific device. There are also - so-called pseudo-devices where a device driver emulates the - behaviour of a device in software without any particular - underlying hardware. Device drivers can be compiled into the - system statically or loaded on demand through the dynamic - kernel linker facility `kld'. - - Most devices in a Unix-like operating system are - accessed through device-nodes, sometimes also called special - files. These files are usually located under the directory - /dev in the file system hierarchy. Until - devfs is fully integrated into FreeBSD, each device node must - be created statically and independent of the existence of the - associated device driver. Most device nodes on the system are - created by running MAKEDEV. - - Device drivers can roughly be broken down into two - categories; character and network device drivers. - - - - Dynamic Kernel Linker Facility - KLD - The kld interface allows system administrators to - dynamically add and remove functionality from a running - system. This allows device driver writers to load their new - changes into a running kernel without constantly rebooting to - test changes. - - The kld interface is used through the following - administrator commands : - - kldload - loads a new kernel + + Writing FreeBSD Device Drivers + + This chapter was written by &.murray with selections + from a variety of sources including the intro(4) man page by Joerg + Wunsch. + + + Introduction + This chapter provides a brief introduction to writing device + drivers for FreeBSD. A device in this context is a term used + mostly for hardware-related stuff that belongs to the system, + like disks, printers, or a graphics display with its keyboard. + A device driver is the software component of the operating + system that controls a specific device. There are also + so-called pseudo-devices where a device driver emulates the + behaviour of a device in software without any particular + underlying hardware. Device drivers can be compiled into the + system statically or loaded on demand through the dynamic kernel + linker facility `kld'. + + Most devices in a Unix-like operating system are accessed + through device-nodes, sometimes also called special files. + These files are usually located under the directory + /dev in the file system hierarchy. Until + devfs is fully integrated into FreeBSD, each device node must be + created statically and independent of the existence of the + associated device driver. Most device nodes on the system are + created by running MAKEDEV. + + Device drivers can roughly be broken down into two + categories; character and network device drivers. + + + + + Dynamic Kernel Linker Facility - KLD + + The kld interface allows system administrators to + dynamically add and remove functionality from a running system. + This allows device driver writers to load their new changes into + a running kernel without constantly rebooting to test + changes. + + The kld interface is used through the following + administrator commands : + + + kldload - loads a new kernel module - kldunload - unloads a kernel + kldunload - unloads a kernel module - kldstat - lists the currently loadded + kldstat - lists the currently loadded modules - - + + + + Skeleton Layout of a kernel module - Skeleton Layout of a kernel module /* * KLD Skeleton * Inspired by Andrew Reiter's Daemonnews article */ #include <sys/types.h> #include <sys/module.h> #include <sys/systm.h> /* uprintf */ #include <sys/errno.h> #include <sys/param.h> /* defines used in kernel.h */ #include <sys/kernel.h> /* types used in module initialization */ /* * Load handler that deals with the loading and unloading of a KLD. */ static int skel_loader(struct module *m, int what, void *arg) { int err = 0; switch (what) { case MOD_LOAD: /* kldload */ uprintf("Skeleton KLD loaded.\n"); break; case MOD_UNLOAD: uprintf("Skeleton KLD unloaded.\n"); break; default: err = EINVAL; break; } return(err); } /* Declare this module to the rest of the kernel */ DECLARE_MODULE(skeleton, skel_loader, SI_SUB_KLD, SI_ORDER_ANY); - - Makefile - FreeBSD provides a makefile include that you can use - to quickly compile your kernel addition. - SRCS=skeleton.c + + Makefile + + FreeBSD provides a makefile include that you can use to + quickly compile your kernel addition. + + SRCS=skeleton.c KMOD=skeleton .include <bsd.kmod.mk> - - Simply running make with - this makefile will create a file - skeleton.ko that can be loaded into - your system by typing : - -&prompt.root kldload -v ./skeleton.ko + Simply running make with this makefile + will create a file skeleton.ko that can + be loaded into your system by typing : + &prompt.root + kldload -v ./skeleton.ko - - - - - - Accessing a device driver - Unix provides a common set of system calls for user - applications to use. The upper layers of the kernel dispatch - these calls to the corresponding device driver when a user - accesses a device node. The /dev/MAKEDEV - script makes most of the device nodes for your system but if - you are doing your own driver development it may be necessary - to create your own device nodes with mknod - - - - Creating static device nodes - The mknod command requires four - arguments to create a device node. You must specify the - name of this device node, the type of device, the major number - of the device, and the minor number of the device. - - - - Dynamic device nodes - The device filesystem, or devfs, provides access to the + + + + + + Accessing a device driver + + Unix provides a common set of system calls for user + applications to use. The upper layers of the kernel dispatch + these calls to the corresponding device driver when a user + accesses a device node. The /dev/MAKEDEV + script makes most of the device nodes for your system but if you + are doing your own driver development it may be necessary to + create your own device nodes with mknod + + + + Creating static device nodes + + The mknod command requires four + arguments to create a device node. You must specify the name + of this device node, the type of device, the major number of + the device, and the minor number of the device. + + + + Dynamic device nodes + + The device filesystem, or devfs, provides access to the kernel's device namespace in the global filesystem namespace. This eliminates the problems of potentially having a device driver without a static device node, or a device node without - an installed device driver. Devfs is still a work in progress, - but it is already working quite nice. - - - - - - Character Devices - A character device driver is one that transfers data - directly to and from a user process. This is the most common - type of device driver and there are plenty of simple examples - in the source tree. - This simple example pseudo-device remembers whatever values you write - to it and can then supply them back to you when you read from - it. + an installed device driver. Devfs is still a work in + progress, but it is already working quite nice. + + + + + + Character Devices + + A character device driver is one that transfers data + directly to and from a user process. This is the most common + type of device driver and there are plenty of simple examples in + the source tree. + + This simple example pseudo-device remembers whatever values + you write to it and can then supply them back to you when you + read from it. + /* * Simple `echo' pseudo-device KLD * * Murray Stokely */ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #include <sys/types.h> #include <sys/module.h> #include <sys/systm.h> /* uprintf */ #include <sys/errno.h> #include <sys/param.h> /* defines used in kernel.h */ #include <sys/kernel.h> /* types used in module initialization */ #include <sys/conf.h> /* cdevsw struct */ #include <sys/uio.h> /* uio struct */ #include <sys/malloc.h> #define BUFFERSIZE 256 /* Function prototypes */ d_open_t echo_open; d_close_t echo_close; d_read_t echo_read; d_write_t echo_write; /* Character device entry points */ static struct cdevsw echo_cdevsw = { echo_open, echo_close, echo_read, echo_write, noioctl, nopoll, nommap, nostrategy, "echo", 33, /* reserved for lkms - /usr/src/sys/conf/majors */ nodump, nopsize, D_TTY, -1 }; typedef struct s_echo { char msg[BUFFERSIZE]; int len; } t_echo; /* vars */ static dev_t sdev; static int len; static int count; static t_echo *echomsg; MALLOC_DECLARE(M_ECHOBUF); MALLOC_DEFINE(M_ECHOBUF, "echobuffer", "buffer for echo module"); /* * This function acts is called by the kld[un]load(2) system calls to * determine what actions to take when a module is loaded or unloaded. */ static int echo_loader(struct module *m, int what, void *arg) { int err = 0; switch (what) { case MOD_LOAD: /* kldload */ sdev = make_dev(&echo_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "echo"); /* kmalloc memory for use by this driver */ /* malloc(256,M_ECHOBUF,M_WAITOK); */ MALLOC(echomsg, t_echo *, sizeof(t_echo), M_ECHOBUF, M_WAITOK); printf("Echo device loaded.\n"); break; case MOD_UNLOAD: destroy_dev(sdev); FREE(echomsg,M_ECHOBUF); printf("Echo device unloaded.\n"); break; default: err = EINVAL; break; } return(err); } int echo_open(dev_t dev, int oflags, int devtype, struct proc *p) { int err = 0; uprintf("Opened device \"echo\" successfully.\n"); return(err); } int echo_close(dev_t dev, int fflag, int devtype, struct proc *p) { uprintf("Closing device \"echo.\"\n"); return(0); } /* * The read function just takes the buf that was saved via * echo_write() and returns it to userland for accessing. * uio(9) */ int echo_read(dev_t dev, struct uio *uio, int ioflag) { int err = 0; int amt; /* How big is this read operation? Either as big as the user wants, or as big as the remaining data */ amt = MIN(uio->uio_resid, (echomsg->len - uio->uio_offset > 0) ? echomsg->len - uio->uio_offset : 0); if ((err = uiomove(echomsg->msg + uio->uio_offset,amt,uio)) != 0) { uprintf("uiomove failed!\n"); } return err; } /* * echo_write takes in a character string and saves it * to buf for later accessing. */ int echo_write(dev_t dev, struct uio *uio, int ioflag) { int err = 0; /* Copy the string in from user memory to kernel memory */ err = copyin(uio->uio_iov->iov_base, echomsg->msg, MIN(uio->uio_iov->iov_len,BUFFERSIZE)); /* Now we need to null terminate */ *(echomsg->msg + MIN(uio->uio_iov->iov_len,BUFFERSIZE)) = 0; /* Record the length */ echomsg->len = MIN(uio->uio_iov->iov_len,BUFFERSIZE); if (err != 0) { uprintf("Write failed: bad address!\n"); } count++; return(err); } DEV_MODULE(echo,echo_loader,NULL); -To install this driver you will first need to make a node on - your filesystem with a command such as : + To install this driver you will first need to make a node on + your filesystem with a command such as : + &prompt.root mknod /dev/echo c 33 0 -With this driver loaded you should now be able to type something - like : + + With this driver loaded you should now be able to type + something like : + &prompt.root echo -n "Test Data" > /dev/echo &prompt.root cat /dev/echo Test Data - Real hardware devices in the next chapter.. - Additional Resources - - Real hardware devices in the next chapter.. + + Additional Resources + + Dynamic Kernel Linker (KLD) Facility Programming Tutorial - Daemonnews October 2000 - How to Write Kernel Drivers with NEWBUS - Daemonnews July 2000 - - - - - - Network Drivers - Drivers for network devices do not use device nodes in - ord to be accessed. Their selection is based on other - decisions made inside the kernel and instead of calling - open(), use of a network device is generally introduced by - using the system call socket(2). - man ifnet(), loopback device, Bill Pauls drivers, etc.. - - - + + + + + + Network Drivers + + Drivers for network devices do not use device nodes in order + to be accessed. Their selection is based on other decisions + made inside the kernel and instead of calling open(), use of a + network device is generally introduced by using the system call + socket(2). + + man ifnet(), loopback device, Bill Paul's drivers, + etc.. + + + + diff --git a/en_US.ISO8859-1/books/developers-handbook/driverbasics/chapter.sgml b/en_US.ISO8859-1/books/developers-handbook/driverbasics/chapter.sgml index 29cf0a05cb..52d27534ad 100644 --- a/en_US.ISO8859-1/books/developers-handbook/driverbasics/chapter.sgml +++ b/en_US.ISO8859-1/books/developers-handbook/driverbasics/chapter.sgml @@ -1,362 +1,379 @@ - - Writing FreeBSD Device Drivers - - This chapter was written by Murray Stokely with selections from - a variety of sources including the intro(4) man page by Joerg - Wunsch. - - - Introduction - - This chapter provides a brief introduction to writing device - drivers for FreeBSD. A device in this context is a term used - mostly for hardware-related stuff that belongs to the system, - like disks, printers, or a graphics display with its keyboard. - A device driver is the software component of the operating - system that controls a specific device. There are also - so-called pseudo-devices where a device driver emulates the - behaviour of a device in software without any particular - underlying hardware. Device drivers can be compiled into the - system statically or loaded on demand through the dynamic - kernel linker facility `kld'. - - Most devices in a Unix-like operating system are - accessed through device-nodes, sometimes also called special - files. These files are usually located under the directory - /dev in the file system hierarchy. Until - devfs is fully integrated into FreeBSD, each device node must - be created statically and independent of the existence of the - associated device driver. Most device nodes on the system are - created by running MAKEDEV. - - Device drivers can roughly be broken down into two - categories; character and network device drivers. - - - - Dynamic Kernel Linker Facility - KLD - The kld interface allows system administrators to - dynamically add and remove functionality from a running - system. This allows device driver writers to load their new - changes into a running kernel without constantly rebooting to - test changes. - - The kld interface is used through the following - administrator commands : - - kldload - loads a new kernel + + Writing FreeBSD Device Drivers + + This chapter was written by &.murray with selections + from a variety of sources including the intro(4) man page by Joerg + Wunsch. + + + Introduction + This chapter provides a brief introduction to writing device + drivers for FreeBSD. A device in this context is a term used + mostly for hardware-related stuff that belongs to the system, + like disks, printers, or a graphics display with its keyboard. + A device driver is the software component of the operating + system that controls a specific device. There are also + so-called pseudo-devices where a device driver emulates the + behaviour of a device in software without any particular + underlying hardware. Device drivers can be compiled into the + system statically or loaded on demand through the dynamic kernel + linker facility `kld'. + + Most devices in a Unix-like operating system are accessed + through device-nodes, sometimes also called special files. + These files are usually located under the directory + /dev in the file system hierarchy. Until + devfs is fully integrated into FreeBSD, each device node must be + created statically and independent of the existence of the + associated device driver. Most device nodes on the system are + created by running MAKEDEV. + + Device drivers can roughly be broken down into two + categories; character and network device drivers. + + + + + Dynamic Kernel Linker Facility - KLD + + The kld interface allows system administrators to + dynamically add and remove functionality from a running system. + This allows device driver writers to load their new changes into + a running kernel without constantly rebooting to test + changes. + + The kld interface is used through the following + administrator commands : + + + kldload - loads a new kernel module - kldunload - unloads a kernel + kldunload - unloads a kernel module - kldstat - lists the currently loadded + kldstat - lists the currently loadded modules - - + + + + Skeleton Layout of a kernel module - Skeleton Layout of a kernel module /* * KLD Skeleton * Inspired by Andrew Reiter's Daemonnews article */ #include <sys/types.h> #include <sys/module.h> #include <sys/systm.h> /* uprintf */ #include <sys/errno.h> #include <sys/param.h> /* defines used in kernel.h */ #include <sys/kernel.h> /* types used in module initialization */ /* * Load handler that deals with the loading and unloading of a KLD. */ static int skel_loader(struct module *m, int what, void *arg) { int err = 0; switch (what) { case MOD_LOAD: /* kldload */ uprintf("Skeleton KLD loaded.\n"); break; case MOD_UNLOAD: uprintf("Skeleton KLD unloaded.\n"); break; default: err = EINVAL; break; } return(err); } /* Declare this module to the rest of the kernel */ DECLARE_MODULE(skeleton, skel_loader, SI_SUB_KLD, SI_ORDER_ANY); - - Makefile - FreeBSD provides a makefile include that you can use - to quickly compile your kernel addition. - SRCS=skeleton.c + + Makefile + + FreeBSD provides a makefile include that you can use to + quickly compile your kernel addition. + + SRCS=skeleton.c KMOD=skeleton .include <bsd.kmod.mk> - - Simply running make with - this makefile will create a file - skeleton.ko that can be loaded into - your system by typing : - -&prompt.root kldload -v ./skeleton.ko + Simply running make with this makefile + will create a file skeleton.ko that can + be loaded into your system by typing : + &prompt.root + kldload -v ./skeleton.ko - - - - - - Accessing a device driver - Unix provides a common set of system calls for user - applications to use. The upper layers of the kernel dispatch - these calls to the corresponding device driver when a user - accesses a device node. The /dev/MAKEDEV - script makes most of the device nodes for your system but if - you are doing your own driver development it may be necessary - to create your own device nodes with mknod - - - - Creating static device nodes - The mknod command requires four - arguments to create a device node. You must specify the - name of this device node, the type of device, the major number - of the device, and the minor number of the device. - - - - Dynamic device nodes - The device filesystem, or devfs, provides access to the + + + + + + Accessing a device driver + + Unix provides a common set of system calls for user + applications to use. The upper layers of the kernel dispatch + these calls to the corresponding device driver when a user + accesses a device node. The /dev/MAKEDEV + script makes most of the device nodes for your system but if you + are doing your own driver development it may be necessary to + create your own device nodes with mknod + + + + Creating static device nodes + + The mknod command requires four + arguments to create a device node. You must specify the name + of this device node, the type of device, the major number of + the device, and the minor number of the device. + + + + Dynamic device nodes + + The device filesystem, or devfs, provides access to the kernel's device namespace in the global filesystem namespace. This eliminates the problems of potentially having a device driver without a static device node, or a device node without - an installed device driver. Devfs is still a work in progress, - but it is already working quite nice. - - - - - - Character Devices - A character device driver is one that transfers data - directly to and from a user process. This is the most common - type of device driver and there are plenty of simple examples - in the source tree. - This simple example pseudo-device remembers whatever values you write - to it and can then supply them back to you when you read from - it. + an installed device driver. Devfs is still a work in + progress, but it is already working quite nice. + + + + + + Character Devices + + A character device driver is one that transfers data + directly to and from a user process. This is the most common + type of device driver and there are plenty of simple examples in + the source tree. + + This simple example pseudo-device remembers whatever values + you write to it and can then supply them back to you when you + read from it. + /* * Simple `echo' pseudo-device KLD * * Murray Stokely */ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #include <sys/types.h> #include <sys/module.h> #include <sys/systm.h> /* uprintf */ #include <sys/errno.h> #include <sys/param.h> /* defines used in kernel.h */ #include <sys/kernel.h> /* types used in module initialization */ #include <sys/conf.h> /* cdevsw struct */ #include <sys/uio.h> /* uio struct */ #include <sys/malloc.h> #define BUFFERSIZE 256 /* Function prototypes */ d_open_t echo_open; d_close_t echo_close; d_read_t echo_read; d_write_t echo_write; /* Character device entry points */ static struct cdevsw echo_cdevsw = { echo_open, echo_close, echo_read, echo_write, noioctl, nopoll, nommap, nostrategy, "echo", 33, /* reserved for lkms - /usr/src/sys/conf/majors */ nodump, nopsize, D_TTY, -1 }; typedef struct s_echo { char msg[BUFFERSIZE]; int len; } t_echo; /* vars */ static dev_t sdev; static int len; static int count; static t_echo *echomsg; MALLOC_DECLARE(M_ECHOBUF); MALLOC_DEFINE(M_ECHOBUF, "echobuffer", "buffer for echo module"); /* * This function acts is called by the kld[un]load(2) system calls to * determine what actions to take when a module is loaded or unloaded. */ static int echo_loader(struct module *m, int what, void *arg) { int err = 0; switch (what) { case MOD_LOAD: /* kldload */ sdev = make_dev(&echo_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "echo"); /* kmalloc memory for use by this driver */ /* malloc(256,M_ECHOBUF,M_WAITOK); */ MALLOC(echomsg, t_echo *, sizeof(t_echo), M_ECHOBUF, M_WAITOK); printf("Echo device loaded.\n"); break; case MOD_UNLOAD: destroy_dev(sdev); FREE(echomsg,M_ECHOBUF); printf("Echo device unloaded.\n"); break; default: err = EINVAL; break; } return(err); } int echo_open(dev_t dev, int oflags, int devtype, struct proc *p) { int err = 0; uprintf("Opened device \"echo\" successfully.\n"); return(err); } int echo_close(dev_t dev, int fflag, int devtype, struct proc *p) { uprintf("Closing device \"echo.\"\n"); return(0); } /* * The read function just takes the buf that was saved via * echo_write() and returns it to userland for accessing. * uio(9) */ int echo_read(dev_t dev, struct uio *uio, int ioflag) { int err = 0; int amt; /* How big is this read operation? Either as big as the user wants, or as big as the remaining data */ amt = MIN(uio->uio_resid, (echomsg->len - uio->uio_offset > 0) ? echomsg->len - uio->uio_offset : 0); if ((err = uiomove(echomsg->msg + uio->uio_offset,amt,uio)) != 0) { uprintf("uiomove failed!\n"); } return err; } /* * echo_write takes in a character string and saves it * to buf for later accessing. */ int echo_write(dev_t dev, struct uio *uio, int ioflag) { int err = 0; /* Copy the string in from user memory to kernel memory */ err = copyin(uio->uio_iov->iov_base, echomsg->msg, MIN(uio->uio_iov->iov_len,BUFFERSIZE)); /* Now we need to null terminate */ *(echomsg->msg + MIN(uio->uio_iov->iov_len,BUFFERSIZE)) = 0; /* Record the length */ echomsg->len = MIN(uio->uio_iov->iov_len,BUFFERSIZE); if (err != 0) { uprintf("Write failed: bad address!\n"); } count++; return(err); } DEV_MODULE(echo,echo_loader,NULL); -To install this driver you will first need to make a node on - your filesystem with a command such as : + To install this driver you will first need to make a node on + your filesystem with a command such as : + &prompt.root mknod /dev/echo c 33 0 -With this driver loaded you should now be able to type something - like : + + With this driver loaded you should now be able to type + something like : + &prompt.root echo -n "Test Data" > /dev/echo &prompt.root cat /dev/echo Test Data - Real hardware devices in the next chapter.. - Additional Resources - - Real hardware devices in the next chapter.. + + Additional Resources + + Dynamic Kernel Linker (KLD) Facility Programming Tutorial - Daemonnews October 2000 - How to Write Kernel Drivers with NEWBUS - Daemonnews July 2000 - - - - - - Network Drivers - Drivers for network devices do not use device nodes in - ord to be accessed. Their selection is based on other - decisions made inside the kernel and instead of calling - open(), use of a network device is generally introduced by - using the system call socket(2). - man ifnet(), loopback device, Bill Pauls drivers, etc.. - - - + + + + + + Network Drivers + + Drivers for network devices do not use device nodes in order + to be accessed. Their selection is based on other decisions + made inside the kernel and instead of calling open(), use of a + network device is generally introduced by using the system call + socket(2). + + man ifnet(), loopback device, Bill Paul's drivers, + etc.. + + + + diff --git a/en_US.ISO_8859-1/books/developers-handbook/driverbasics/chapter.sgml b/en_US.ISO_8859-1/books/developers-handbook/driverbasics/chapter.sgml index 29cf0a05cb..52d27534ad 100644 --- a/en_US.ISO_8859-1/books/developers-handbook/driverbasics/chapter.sgml +++ b/en_US.ISO_8859-1/books/developers-handbook/driverbasics/chapter.sgml @@ -1,362 +1,379 @@ - - Writing FreeBSD Device Drivers - - This chapter was written by Murray Stokely with selections from - a variety of sources including the intro(4) man page by Joerg - Wunsch. - - - Introduction - - This chapter provides a brief introduction to writing device - drivers for FreeBSD. A device in this context is a term used - mostly for hardware-related stuff that belongs to the system, - like disks, printers, or a graphics display with its keyboard. - A device driver is the software component of the operating - system that controls a specific device. There are also - so-called pseudo-devices where a device driver emulates the - behaviour of a device in software without any particular - underlying hardware. Device drivers can be compiled into the - system statically or loaded on demand through the dynamic - kernel linker facility `kld'. - - Most devices in a Unix-like operating system are - accessed through device-nodes, sometimes also called special - files. These files are usually located under the directory - /dev in the file system hierarchy. Until - devfs is fully integrated into FreeBSD, each device node must - be created statically and independent of the existence of the - associated device driver. Most device nodes on the system are - created by running MAKEDEV. - - Device drivers can roughly be broken down into two - categories; character and network device drivers. - - - - Dynamic Kernel Linker Facility - KLD - The kld interface allows system administrators to - dynamically add and remove functionality from a running - system. This allows device driver writers to load their new - changes into a running kernel without constantly rebooting to - test changes. - - The kld interface is used through the following - administrator commands : - - kldload - loads a new kernel + + Writing FreeBSD Device Drivers + + This chapter was written by &.murray with selections + from a variety of sources including the intro(4) man page by Joerg + Wunsch. + + + Introduction + This chapter provides a brief introduction to writing device + drivers for FreeBSD. A device in this context is a term used + mostly for hardware-related stuff that belongs to the system, + like disks, printers, or a graphics display with its keyboard. + A device driver is the software component of the operating + system that controls a specific device. There are also + so-called pseudo-devices where a device driver emulates the + behaviour of a device in software without any particular + underlying hardware. Device drivers can be compiled into the + system statically or loaded on demand through the dynamic kernel + linker facility `kld'. + + Most devices in a Unix-like operating system are accessed + through device-nodes, sometimes also called special files. + These files are usually located under the directory + /dev in the file system hierarchy. Until + devfs is fully integrated into FreeBSD, each device node must be + created statically and independent of the existence of the + associated device driver. Most device nodes on the system are + created by running MAKEDEV. + + Device drivers can roughly be broken down into two + categories; character and network device drivers. + + + + + Dynamic Kernel Linker Facility - KLD + + The kld interface allows system administrators to + dynamically add and remove functionality from a running system. + This allows device driver writers to load their new changes into + a running kernel without constantly rebooting to test + changes. + + The kld interface is used through the following + administrator commands : + + + kldload - loads a new kernel module - kldunload - unloads a kernel + kldunload - unloads a kernel module - kldstat - lists the currently loadded + kldstat - lists the currently loadded modules - - + + + + Skeleton Layout of a kernel module - Skeleton Layout of a kernel module /* * KLD Skeleton * Inspired by Andrew Reiter's Daemonnews article */ #include <sys/types.h> #include <sys/module.h> #include <sys/systm.h> /* uprintf */ #include <sys/errno.h> #include <sys/param.h> /* defines used in kernel.h */ #include <sys/kernel.h> /* types used in module initialization */ /* * Load handler that deals with the loading and unloading of a KLD. */ static int skel_loader(struct module *m, int what, void *arg) { int err = 0; switch (what) { case MOD_LOAD: /* kldload */ uprintf("Skeleton KLD loaded.\n"); break; case MOD_UNLOAD: uprintf("Skeleton KLD unloaded.\n"); break; default: err = EINVAL; break; } return(err); } /* Declare this module to the rest of the kernel */ DECLARE_MODULE(skeleton, skel_loader, SI_SUB_KLD, SI_ORDER_ANY); - - Makefile - FreeBSD provides a makefile include that you can use - to quickly compile your kernel addition. - SRCS=skeleton.c + + Makefile + + FreeBSD provides a makefile include that you can use to + quickly compile your kernel addition. + + SRCS=skeleton.c KMOD=skeleton .include <bsd.kmod.mk> - - Simply running make with - this makefile will create a file - skeleton.ko that can be loaded into - your system by typing : - -&prompt.root kldload -v ./skeleton.ko + Simply running make with this makefile + will create a file skeleton.ko that can + be loaded into your system by typing : + &prompt.root + kldload -v ./skeleton.ko - - - - - - Accessing a device driver - Unix provides a common set of system calls for user - applications to use. The upper layers of the kernel dispatch - these calls to the corresponding device driver when a user - accesses a device node. The /dev/MAKEDEV - script makes most of the device nodes for your system but if - you are doing your own driver development it may be necessary - to create your own device nodes with mknod - - - - Creating static device nodes - The mknod command requires four - arguments to create a device node. You must specify the - name of this device node, the type of device, the major number - of the device, and the minor number of the device. - - - - Dynamic device nodes - The device filesystem, or devfs, provides access to the + + + + + + Accessing a device driver + + Unix provides a common set of system calls for user + applications to use. The upper layers of the kernel dispatch + these calls to the corresponding device driver when a user + accesses a device node. The /dev/MAKEDEV + script makes most of the device nodes for your system but if you + are doing your own driver development it may be necessary to + create your own device nodes with mknod + + + + Creating static device nodes + + The mknod command requires four + arguments to create a device node. You must specify the name + of this device node, the type of device, the major number of + the device, and the minor number of the device. + + + + Dynamic device nodes + + The device filesystem, or devfs, provides access to the kernel's device namespace in the global filesystem namespace. This eliminates the problems of potentially having a device driver without a static device node, or a device node without - an installed device driver. Devfs is still a work in progress, - but it is already working quite nice. - - - - - - Character Devices - A character device driver is one that transfers data - directly to and from a user process. This is the most common - type of device driver and there are plenty of simple examples - in the source tree. - This simple example pseudo-device remembers whatever values you write - to it and can then supply them back to you when you read from - it. + an installed device driver. Devfs is still a work in + progress, but it is already working quite nice. + + + + + + Character Devices + + A character device driver is one that transfers data + directly to and from a user process. This is the most common + type of device driver and there are plenty of simple examples in + the source tree. + + This simple example pseudo-device remembers whatever values + you write to it and can then supply them back to you when you + read from it. + /* * Simple `echo' pseudo-device KLD * * Murray Stokely */ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #include <sys/types.h> #include <sys/module.h> #include <sys/systm.h> /* uprintf */ #include <sys/errno.h> #include <sys/param.h> /* defines used in kernel.h */ #include <sys/kernel.h> /* types used in module initialization */ #include <sys/conf.h> /* cdevsw struct */ #include <sys/uio.h> /* uio struct */ #include <sys/malloc.h> #define BUFFERSIZE 256 /* Function prototypes */ d_open_t echo_open; d_close_t echo_close; d_read_t echo_read; d_write_t echo_write; /* Character device entry points */ static struct cdevsw echo_cdevsw = { echo_open, echo_close, echo_read, echo_write, noioctl, nopoll, nommap, nostrategy, "echo", 33, /* reserved for lkms - /usr/src/sys/conf/majors */ nodump, nopsize, D_TTY, -1 }; typedef struct s_echo { char msg[BUFFERSIZE]; int len; } t_echo; /* vars */ static dev_t sdev; static int len; static int count; static t_echo *echomsg; MALLOC_DECLARE(M_ECHOBUF); MALLOC_DEFINE(M_ECHOBUF, "echobuffer", "buffer for echo module"); /* * This function acts is called by the kld[un]load(2) system calls to * determine what actions to take when a module is loaded or unloaded. */ static int echo_loader(struct module *m, int what, void *arg) { int err = 0; switch (what) { case MOD_LOAD: /* kldload */ sdev = make_dev(&echo_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "echo"); /* kmalloc memory for use by this driver */ /* malloc(256,M_ECHOBUF,M_WAITOK); */ MALLOC(echomsg, t_echo *, sizeof(t_echo), M_ECHOBUF, M_WAITOK); printf("Echo device loaded.\n"); break; case MOD_UNLOAD: destroy_dev(sdev); FREE(echomsg,M_ECHOBUF); printf("Echo device unloaded.\n"); break; default: err = EINVAL; break; } return(err); } int echo_open(dev_t dev, int oflags, int devtype, struct proc *p) { int err = 0; uprintf("Opened device \"echo\" successfully.\n"); return(err); } int echo_close(dev_t dev, int fflag, int devtype, struct proc *p) { uprintf("Closing device \"echo.\"\n"); return(0); } /* * The read function just takes the buf that was saved via * echo_write() and returns it to userland for accessing. * uio(9) */ int echo_read(dev_t dev, struct uio *uio, int ioflag) { int err = 0; int amt; /* How big is this read operation? Either as big as the user wants, or as big as the remaining data */ amt = MIN(uio->uio_resid, (echomsg->len - uio->uio_offset > 0) ? echomsg->len - uio->uio_offset : 0); if ((err = uiomove(echomsg->msg + uio->uio_offset,amt,uio)) != 0) { uprintf("uiomove failed!\n"); } return err; } /* * echo_write takes in a character string and saves it * to buf for later accessing. */ int echo_write(dev_t dev, struct uio *uio, int ioflag) { int err = 0; /* Copy the string in from user memory to kernel memory */ err = copyin(uio->uio_iov->iov_base, echomsg->msg, MIN(uio->uio_iov->iov_len,BUFFERSIZE)); /* Now we need to null terminate */ *(echomsg->msg + MIN(uio->uio_iov->iov_len,BUFFERSIZE)) = 0; /* Record the length */ echomsg->len = MIN(uio->uio_iov->iov_len,BUFFERSIZE); if (err != 0) { uprintf("Write failed: bad address!\n"); } count++; return(err); } DEV_MODULE(echo,echo_loader,NULL); -To install this driver you will first need to make a node on - your filesystem with a command such as : + To install this driver you will first need to make a node on + your filesystem with a command such as : + &prompt.root mknod /dev/echo c 33 0 -With this driver loaded you should now be able to type something - like : + + With this driver loaded you should now be able to type + something like : + &prompt.root echo -n "Test Data" > /dev/echo &prompt.root cat /dev/echo Test Data - Real hardware devices in the next chapter.. - Additional Resources - - Real hardware devices in the next chapter.. + + Additional Resources + + Dynamic Kernel Linker (KLD) Facility Programming Tutorial - Daemonnews October 2000 - How to Write Kernel Drivers with NEWBUS - Daemonnews July 2000 - - - - - - Network Drivers - Drivers for network devices do not use device nodes in - ord to be accessed. Their selection is based on other - decisions made inside the kernel and instead of calling - open(), use of a network device is generally introduced by - using the system call socket(2). - man ifnet(), loopback device, Bill Pauls drivers, etc.. - - - + + + + + + Network Drivers + + Drivers for network devices do not use device nodes in order + to be accessed. Their selection is based on other decisions + made inside the kernel and instead of calling open(), use of a + network device is generally introduced by using the system call + socket(2). + + man ifnet(), loopback device, Bill Paul's drivers, + etc.. + + + +