# SOME DESCRIPTIVE TITLE # Copyright (C) YEAR The FreeBSD Project # This file is distributed under the same license as the FreeBSD Documentation package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: FreeBSD Documentation VERSION\n" "POT-Creation-Date: 2025-05-01 19:56-0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. type: Title = #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:1 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:14 #, no-wrap msgid "Writing FreeBSD Device Drivers" msgstr "" #. type: YAML Front Matter: title #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:1 #, no-wrap msgid "Chapter 9. Writing FreeBSD Device Drivers" msgstr "" #. type: Title == #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:52 #, no-wrap msgid "Introduction" msgstr "" #. type: Plain text #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:55 msgid "" "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'." msgstr "" #. type: Plain text #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:57 msgid "" "Most devices in a UNIX(R)-like operating system are accessed through device-" "nodes, sometimes also called special files. These files are usually located " "under the directory [.filename]#/dev# in the filesystem hierarchy." msgstr "" #. type: Plain text #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:59 msgid "" "Device drivers can roughly be broken down into two categories; character and " "network device drivers." msgstr "" #. type: Title == #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:61 #, no-wrap msgid "Dynamic Kernel Linker Facility - KLD" msgstr "" #. type: Plain text #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:64 msgid "" "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." msgstr "" #. type: Plain text #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:66 msgid "The kld interface is used through:" msgstr "" #. type: Plain text #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:68 msgid "`kldload` - loads a new kernel module" msgstr "" #. type: Plain text #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:69 msgid "`kldunload` - unloads a kernel module" msgstr "" #. type: Plain text #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:70 msgid "`kldstat` - lists loaded modules" msgstr "" #. type: Plain text #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:72 msgid "Skeleton Layout of a kernel module" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:79 #, no-wrap msgid "" "/*\n" " * KLD Skeleton\n" " * Inspired by Andrew Reiter's Daemonnews article\n" " */\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:86 #, no-wrap msgid "" "#include \n" "#include /* uprintf */\n" "#include \n" "#include /* defines used in kernel.h */\n" "#include \n" "#include /* types used in module initialization */\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:90 #, no-wrap msgid "" "/*\n" " * Load handler that deals with the loading and unloading of a KLD.\n" " */\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:95 #, no-wrap msgid "" "static int\n" "skel_loader(struct module *m, int what, void *arg)\n" "{\n" "\tint err = 0;\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:109 #, no-wrap msgid "" "\tswitch (what) {\n" "\tcase MOD_LOAD: /* kldload */\n" "\t\tuprintf(\"Skeleton KLD loaded.\\n\");\n" "\t\tbreak;\n" "\tcase MOD_UNLOAD:\n" "\t\tuprintf(\"Skeleton KLD unloaded.\\n\");\n" "\t\tbreak;\n" "\tdefault:\n" "\t\terr = EOPNOTSUPP;\n" "\t\tbreak;\n" "\t}\n" "\treturn(err);\n" "}\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:111 #, no-wrap msgid "/* Declare this module to the rest of the kernel */\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:117 #, no-wrap msgid "" "static moduledata_t skel_mod = {\n" "\t\"skel\",\n" "\tskel_loader,\n" "\tNULL\n" "};\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:119 #, no-wrap msgid "DECLARE_MODULE(skeleton, skel_mod, SI_SUB_KLD, SI_ORDER_ANY);\n" msgstr "" #. type: Title === #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:121 #, no-wrap msgid "Makefile" msgstr "" #. type: Plain text #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:124 msgid "" "FreeBSD provides a system makefile to simplify compiling a kernel module." msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:129 #, no-wrap msgid "" "SRCS=skeleton.c\n" "KMOD=skeleton\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:131 #, no-wrap msgid ".include \n" msgstr "" #. type: Plain text #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:134 msgid "" "Running `make` with this makefile will create a file " "[.filename]#skeleton.ko# that can be loaded into the kernel by typing:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:138 #, no-wrap msgid "# kldload -v ./skeleton.ko\n" msgstr "" #. type: Title == #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:141 #, no-wrap msgid "Character Devices" msgstr "" #. type: Plain text #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:144 msgid "" "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." msgstr "" #. type: Plain text #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:146 msgid "" "This simple example pseudo-device remembers whatever values are written to " "it and can then echo them back when read." msgstr "" #. type: Block title #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:147 #, no-wrap msgid "Example of a Sample Echo Pseudo-Device Driver for FreeBSD 10.X - 12.X" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:159 #, no-wrap msgid "" "/*\n" " * Simple Echo pseudo-device KLD\n" " *\n" " * Murray Stokely\n" " * Søren (Xride) Straarup\n" " * Eitan Adler\n" " */\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:168 #, no-wrap msgid "" "#include \n" "#include /* uprintf */\n" "#include /* defines used in kernel.h */\n" "#include \n" "#include /* types used in module initialization */\n" "#include /* cdevsw struct */\n" "#include /* uio struct */\n" "#include \n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:170 #, no-wrap msgid "#define BUFFERSIZE 255\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:176 #, no-wrap msgid "" "/* Function prototypes */\n" "static d_open_t echo_open;\n" "static d_close_t echo_close;\n" "static d_read_t echo_read;\n" "static d_write_t echo_write;\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:186 #, no-wrap msgid "" "/* Character device entry points */\n" "static struct cdevsw echo_cdevsw = {\n" "\t.d_version = D_VERSION,\n" "\t.d_open = echo_open,\n" "\t.d_close = echo_close,\n" "\t.d_read = echo_read,\n" "\t.d_write = echo_write,\n" "\t.d_name = \"echo\",\n" "};\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:191 #, no-wrap msgid "" "struct s_echo {\n" "\tchar msg[BUFFERSIZE + 1];\n" "\tint len;\n" "};\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:195 #, no-wrap msgid "" "/* vars */\n" "static struct cdev *echo_dev;\n" "static struct s_echo *echomsg;\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:198 #, no-wrap msgid "" "MALLOC_DECLARE(M_ECHOBUF);\n" "MALLOC_DEFINE(M_ECHOBUF, \"echobuffer\", \"buffer for echo module\");\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:207 #, no-wrap msgid "" "/*\n" " * This function is called by the kld[un]load(2) system calls to\n" " * determine what actions to take when a module is loaded or unloaded.\n" " */\n" "static int\n" "echo_loader(struct module *m __unused, int what, void *arg __unused)\n" "{\n" "\tint error = 0;\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:220 #, no-wrap msgid "" "\tswitch (what) {\n" "\tcase MOD_LOAD: /* kldload */\n" "\t\terror = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK,\n" "\t\t &echo_dev,\n" "\t\t &echo_cdevsw,\n" "\t\t 0,\n" "\t\t UID_ROOT,\n" "\t\t GID_WHEEL,\n" "\t\t 0600,\n" "\t\t \"echo\");\n" "\t\tif (error != 0)\n" "\t\t\tbreak;\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:236 #, no-wrap msgid "" "\t\techomsg = malloc(sizeof(*echomsg), M_ECHOBUF, M_WAITOK |\n" "\t\t M_ZERO);\n" "\t\tprintf(\"Echo device loaded.\\n\");\n" "\t\tbreak;\n" "\tcase MOD_UNLOAD:\n" "\t\tdestroy_dev(echo_dev);\n" "\t\tfree(echomsg, M_ECHOBUF);\n" "\t\tprintf(\"Echo device unloaded.\\n\");\n" "\t\tbreak;\n" "\tdefault:\n" "\t\terror = EOPNOTSUPP;\n" "\t\tbreak;\n" "\t}\n" "\treturn (error);\n" "}\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:242 #, no-wrap msgid "" "static int\n" "echo_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused,\n" " struct thread *td __unused)\n" "{\n" "\tint error = 0;\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:246 #, no-wrap msgid "" "\tuprintf(\"Opened device \\\"echo\\\" successfully.\\n\");\n" "\treturn (error);\n" "}\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:251 #, no-wrap msgid "" "static int\n" "echo_close(struct cdev *dev __unused, int fflag __unused, int devtype __unused,\n" " struct thread *td __unused)\n" "{\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:255 #, no-wrap msgid "" "\tuprintf(\"Closing device \\\"echo\\\".\\n\");\n" "\treturn (0);\n" "}\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:266 #, no-wrap msgid "" "/*\n" " * The read function just takes the buf that was saved via\n" " * echo_write() and returns it to userland for accessing.\n" " * uio(9)\n" " */\n" "static int\n" "echo_read(struct cdev *dev __unused, struct uio *uio, int ioflag __unused)\n" "{\n" "\tsize_t amt;\n" "\tint error;\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:274 #, no-wrap msgid "" "\t/*\n" "\t * How big is this read operation? Either as big as the user wants,\n" "\t * or as big as the remaining data. Note that the 'len' does not\n" "\t * include the trailing null character.\n" "\t */\n" "\tamt = MIN(uio->uio_resid, uio->uio_offset >= echomsg->len + 1 ? 0 :\n" "\t echomsg->len + 1 - uio->uio_offset);\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:277 #, no-wrap msgid "" "\tif ((error = uiomove(echomsg->msg, amt, uio)) != 0)\n" "\t\tuprintf(\"uiomove failed!\\n\");\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:280 #, no-wrap msgid "" "\treturn (error);\n" "}\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:290 #, no-wrap msgid "" "/*\n" " * echo_write takes in a character string and saves it\n" " * to buf for later accessing.\n" " */\n" "static int\n" "echo_write(struct cdev *dev __unused, struct uio *uio, int ioflag __unused)\n" "{\n" "\tsize_t amt;\n" "\tint error;\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:297 #, no-wrap msgid "" "\t/*\n" "\t * We either write from the beginning or are appending -- do\n" "\t * not allow random access.\n" "\t */\n" "\tif (uio->uio_offset != 0 && (uio->uio_offset != echomsg->len))\n" "\t\treturn (EINVAL);\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:301 #, no-wrap msgid "" "\t/* This is a new message, reset length */\n" "\tif (uio->uio_offset == 0)\n" "\t\techomsg->len = 0;\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:304 #, no-wrap msgid "" "\t/* Copy the string in from user memory to kernel memory */\n" "\tamt = MIN(uio->uio_resid, (BUFFERSIZE - echomsg->len));\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:306 #, no-wrap msgid "\terror = uiomove(echomsg->msg + uio->uio_offset, amt, uio);\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:310 #, no-wrap msgid "" "\t/* Now we need to null terminate and record the length */\n" "\techomsg->len = uio->uio_offset;\n" "\techomsg->msg[echomsg->len] = 0;\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:315 #, no-wrap msgid "" "\tif (error != 0)\n" "\t\tuprintf(\"Write failed: bad address!\\n\");\n" "\treturn (error);\n" "}\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:317 #, no-wrap msgid "DEV_MODULE(echo, echo_loader, NULL);\n" msgstr "" #. type: delimited block = 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:321 msgid "With this driver loaded try:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:329 #, no-wrap msgid "" "# echo -n \"Test Data\" > /dev/echo\n" "# cat /dev/echo\n" "Opened device \"echo\" successfully.\n" "Test Data\n" "Closing device \"echo\".\n" msgstr "" #. type: Plain text #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:332 msgid "Real hardware devices are described in the next chapter." msgstr "" #. type: Title == #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:334 #, no-wrap msgid "Block Devices (Are Gone)" msgstr "" #. type: Plain text #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:337 msgid "" "Other UNIX(R) systems may support a second type of disk device known as " "block devices. Block devices are disk devices for which the kernel provides " "caching. This caching makes block-devices almost unusable, or at least " "dangerously unreliable. The caching will reorder the sequence of write " "operations, depriving the application of the ability to know the exact disk " "contents at any one instant in time." msgstr "" #. type: Plain text #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:339 msgid "" "This makes predictable and reliable crash recovery of on-disk data " "structures (filesystems, databases, etc.) impossible. Since writes may be " "delayed, there is no way the kernel can report to the application which " "particular write operation encountered a write error, this further compounds " "the consistency problem." msgstr "" #. type: Plain text #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:341 msgid "" "For this reason, no serious applications rely on block devices, and in fact, " "almost all applications which access disks directly take great pains to " "specify that character (or \"raw\") devices should always be used. As the " "implementation of the aliasing of each disk (partition) to two devices with " "different semantics significantly complicated the relevant kernel code, " "FreeBSD dropped support for cached disk devices as part of the modernization " "of the disk I/O infrastructure." msgstr "" #. type: Title == #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:343 #, no-wrap msgid "Network Drivers" msgstr "" #. type: Plain text #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:346 msgid "" "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)." msgstr "" #. type: Plain text #: documentation/content/en/books/arch-handbook/driverbasics/_index.adoc:347 msgid "For more information see ifnet(9), the source of the loopback device." msgstr ""