diff options
Diffstat (limited to 'en_US.ISO8859-1/books/arch-handbook/driverbasics/chapter.sgml')
-rw-r--r-- | en_US.ISO8859-1/books/arch-handbook/driverbasics/chapter.sgml | 390 |
1 files changed, 0 insertions, 390 deletions
diff --git a/en_US.ISO8859-1/books/arch-handbook/driverbasics/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/driverbasics/chapter.sgml deleted file mode 100644 index d24c06c5c4..0000000000 --- a/en_US.ISO8859-1/books/arch-handbook/driverbasics/chapter.sgml +++ /dev/null @@ -1,390 +0,0 @@ -<!-- - The FreeBSD Documentation Project - - $FreeBSD$ ---> - -<chapter id="driverbasics"> - <title>Writing FreeBSD Device Drivers</title> - - <para>This chapter was written by &a.murray; with selections from a - variety of sources including the intro(4) manual page by - &a.joerg;.</para> - - <sect1> - <title>Introduction</title> - <para>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 - behavior 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'.</para> - - <para>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 - <filename>/dev</filename> in the filesystem 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 <command>MAKEDEV</command>.</para> - - <para>Device drivers can roughly be broken down into two - categories; character and network device drivers.</para> - - </sect1> - - <sect1> - <title>Dynamic Kernel Linker Facility - KLD</title> - - <para>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.</para> - - <para>The kld interface is used through the following - privileged commands: - - <itemizedlist> - <listitem><simpara><command>kldload</command> - loads a new kernel - module</simpara></listitem> - <listitem><simpara><command>kldunload</command> - unloads a kernel - module</simpara></listitem> - <listitem><simpara><command>kldstat</command> - lists the currently loaded - modules</simpara></listitem> - </itemizedlist> - </para> - - <para>Skeleton Layout of a kernel module</para> - -<programlisting>/* - * 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 */ - -static moduledata_t skel_mod = { - "skel", - skel_loader, - NULL -}; - -DECLARE_MODULE(skeleton, skel_mod, SI_SUB_KLD, SI_ORDER_ANY);</programlisting> - - - <sect2> - <title>Makefile</title> - - <para>FreeBSD provides a makefile include that you can use to - quickly compile your kernel addition.</para> - - <programlisting>SRCS=skeleton.c -KMOD=skeleton - -.include <bsd.kmod.mk></programlisting> - - <para>Simply running <command>make</command> with this makefile - will create a file <filename>skeleton.ko</filename> that can - be loaded into your system by typing: -<screen>&prompt.root; <userinput>kldload -v ./skeleton.ko</userinput></screen> - </para> - </sect2> - </sect1> - - <sect1> - <title>Accessing a device driver</title> - - <para>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 <command>/dev/MAKEDEV</command> - 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 <command>mknod</command>. - </para> - - <sect2> - <title>Creating static device nodes</title> - - <para>The <command>mknod</command> command requires four - arguments to create a device node. You must specify the name - of the device node, the type of device, the major number of - the device, and the minor number of the device.</para> - </sect2> - - <sect2> - <title>Dynamic device nodes</title> - - <para>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 nicely.</para> - </sect2> - - </sect1> - - <sect1> - <title>Character Devices</title> - - <para>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.</para> - - <para>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.</para> - - <programlisting>/* - * 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(<literal>&</literal>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);</programlisting> - - <para>To install this driver you will first need to make a node on - your filesystem with a command such as:</para> - - <screen>&prompt.root; <userinput>mknod /dev/echo c 33 0</userinput></screen> - - <para>With this driver loaded you should now be able to type - something like:</para> - - <screen>&prompt.root; <userinput>echo -n "Test Data" > /dev/echo</userinput> -&prompt.root; <userinput>cat /dev/echo</userinput> -Test Data</screen> - - <para>Real hardware devices in the next chapter..</para> - - <para>Additional Resources - <itemizedlist> - <listitem><simpara><ulink - url="http://www.daemonnews.org/200010/blueprints.html">Dynamic - Kernel Linker (KLD) Facility Programming Tutorial</ulink> - - <ulink url="http://www.daemonnews.org/">Daemonnews</ulink> October 2000</simpara></listitem> - <listitem><simpara><ulink - url="http://www.daemonnews.org/200007/newbus-intro.html">How - to Write Kernel Drivers with NEWBUS</ulink> - <ulink - url="http://www.daemonnews.org/">Daemonnews</ulink> July - 2000</simpara></listitem> - </itemizedlist> - </para> - </sect1> - - <sect1> - <title>Network Drivers</title> - - <para>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).</para> - - <para>man ifnet(), loopback device, Bill Paul's drivers, - etc..</para> - - </sect1> - -</chapter> - -<!-- - Local Variables: - mode: sgml - sgml-declaration: "../chapter.decl" - sgml-indent-data: t - sgml-omittag: nil - sgml-always-quote-attributes: t - sgml-parent-document: ("../book.sgml" "part" "chapter") - End: ---> |