Device drivers frequently expose several different ``flavors'' of a device. For example, a single magnetic tape drive will often have many different device files in /dev. Each device file represents a different combination of options such as rewind/no-rewind, or compressed/uncompressed. However, they access the same physical tape drive.
Traditionally, the device file's minor number was used to communicate the desired options with device drivers. But, since devfs dynamically (and unpredictably) generates both major and minor numbers every time a device is registered, a different technique was developed. When using devfs, drivers are allowed to associate a value (of type void *) with each device they register. This facility takes the place of the minor number.
The devfs solution is also used by FUSD. The mysterious third argument to fusd_register that we mentioned in Section 4.1 is an arbitrary piece of data that can be passed to FUSD when a device is registered. Later, when a callback is activated, the contents of that argument are available in the device_info member of the fusd_file_info structure.
Program 4 shows an example of this technique, inspired by Alessandro Rubini's similar devfs tutorial published in Linux Magazine. It creates a number of devices in the /dev/drums directory, each of which is useful for generating a different kind of ``sound''--/dev/drums/bam, /dev/drums/boom, and so on. Reading from any of these devices will return a string equal to the device's name.
The first thing to notice about drums.c is that it registers more than one FUSD device. In the loop starting in line 31, it calls fusd_register() once for every device named in drums_strings on line 1. When fusd_run() is called, it automatically watches every device the driver registered, and activates the callbacks associated with each device as needed. Although drums.c uses the same set of callbacks for every device it registers (as can be seen on line 33), each device could have different callbacks if desired. (Not shown is the initialization of drums_fops, which assigns drums_read to be the read callback.)
If drums_read is called for all 6 types of drums, how does it know which device it's supposed to be servicing when it gets called? The answer is in the third argument of fusd_register(), which we were previously ignoring. Whatever value is passed to fusd_register() will be passed back to the callback in the device_info field of the fusd_file_info structure. The name of the drum sound is passed to fusd_register on line 33, and later retrieved by the driver on line 12.
Although this example uses a string as its device_info, the pointer can be used for anything--a mode number, a pointer to a configuration structure, and so on.