FUSD drivers are conceptually similar to kernel drivers: a set of callback functions called in response to system calls made on file descriptors by user programs. FUSD's C library provides a device registration function, similar to the kernel's devfs_register_chrdev() function, to create new devices. fusd_register() accepts the device name and a structure full of pointers. Those pointers are callback functions which are called in response to certain user system calls--for example, when a process tries to open, close, read from, or write to the device file. The callback functions should conform to the standard definitions of POSIX system call behavior. In many ways, the user-space FUSD callback functions are identical to their kernel counterparts.
Perhaps the best way to show what FUSD does is by example. Program 1 is a simple FUSD device driver. When the program is run, a device called /dev/hello-world appears under the /dev directory. If that device is read (e.g., using cat), the read returns Hello, world! followed by an EOF. Finally, when the driver is stopped (e.g., by hitting Control-C), the device file disappears.
On line 40 of the source, we use fusd_register() to create the /dev/hello-world device, passing pointers to callbacks for the open(), close() and read() system calls. (Lines 36-39 use the GNU C extension that allows initializer field naming; the 2.4 series of Linux kernels use also that extension for the same purpose.) The ``Hello, World'' read() callback itself is virtually identical to what a kernel driver for this device would look like. It can inspect and modify the user's file pointer, copy data into the user-provided buffer, control the system call return value (either positive, EOF, or error), and so forth.
The proxying of kernel system calls that makes this kind of program possible is implemented by FUSD, using a combination of a kernel module and cooperating user-space library. The kernel module implements a character device, /dev/fusd, which is used as a control channel between the two. fusd_register() uses this channel to send a message to the FUSD kernel module, telling the name of the device the user wants to register. The kernel module, in turn, registers that device with the kernel proper using devfs. devfs and the kernel don't know anything unusual is happening; it appears from their point of view that the registered devices are simply being implemented by the FUSD module.
Later, when kernel makes a callback due to a system call (e.g. when the character device file is opened or read), the FUSD kernel module's callback blocks the calling process, marshals the arguments of the callback into a message and sends it to user-space. Once there, the library half of FUSD unmarshals it and calls whatever user-space callback the FUSD driver passed to fusd_register(). When that user-space callback returns a value, the process happens in reverse: the return value and its side-effects are marshaled by the library and sent to the kernel. The FUSD kernel module unmarshals this message, matches it up with a corresponding outstanding request, and completes the system call. The calling process is completely unaware of this trickery; it simply enters the kernel once, blocks, unblocks, and returns from the system call--just as it would for any other blocking call.
One of the primary design goals of FUSD is stability. It should not be possible for a FUSD driver to corrupt or crash the kernel, either due to error or malice. Of course, a buggy driver itself may corrupt itself (e.g., due to a buffer overrun). However, strict error checking is implemented at the user-kernel boundary which should prevent drivers from corrupting the kernel or any other user-space process--including the errant driver's own clients, and other FUSD drivers.