We saw an example of a simple driver, helloworld.c, in Program 1 on page . Let's go back and examine that program now in more detail.
The FUSD ball starts rolling when the fusd_register function is called, as shown on line 40. This function tells the FUSD kernel module:
If device registration is successful, fusd_register returns a device handle--a small integer . On errors, it returns -1 and sets the global variable errno appropriately. In reality, the device handle you get is a plain old file descriptor, as we'll see in Section 7.
Although Program 1 only calls fusd_register once, it can be called multiple times if the FUSD driver is handling more than one device as we'll see in Program 4.
There is intentional similarity between fusd_register() and the kernel's device registration functions, such as devfs_register() and register_chrdev(). In many ways, FUSD's interface is meant to mirror the kernel interface as closely as possible.
The fusd_file_operations structure, defined in fusd.h, contains a list of callbacks that are used in response to different system calls executed on a file. It is similar to the kernel's file_operations structure, accepting callbacks for system calls such as open(), close(), read(), write(), and ioctl(). For the most part, the prototypes of FUSD file operation callbacks are the same as their kernel cousins, with one important exception. The first argument of FUSD callbacks is always a pointer to a fusd_file_info structure; it contains information that can be used to identify the file. This structure is used instead of the kernel's file and inode structures, and will be described in more detail later.
In lines 35-38 of Program 1, we create and initialize a fusd_file_operations structure. A GCC-specific C extension allows us to name structure fields explicitly in the initializer. This style may look strange, but it guards against errors in the future in case the order of fields in the structure ever changes. The 2.4 kernel series uses the same trick.
After calling fusd_register() on line 40, the example program calls fusd_run() on line 44. This function turns control over to the FUSD framework. fusd_run blocks the driver until one of the devices it registered needs to be serviced. Then, it calls the appropriate callback and blocks again until the next event.
Now, imagine that a user types cat /dev/hello-world. What happens? Recall first what the cat program itself does: opens a file, reads from it until it receives an EOF (printing whatever it reads to stdout), then closes it. cat works the same way regardless of what it's reading--be it a a FUSD device, a regular file, a serial port, or anything else. The strace program is a great way to see this in action; see Appendix A for details.