Misc (or miscellaneous) drivers are simple char drivers that share certain common characteristics. The kernel abstracts these commonalities into an API (implemented in drivers/char/misc.c), and this simplifies the way these drivers are initialized. All misc devices are assigned a major number of 10, but each can choose a single minor number. So, if a char driver needs to drive multiple devices as in the CMOS example discussed earlier, it's probably not a candidate for being a misc driver.
Consider the sequence of initialization steps that a char driver performs:
A misc driver accomplishes all this with a single call to misc_register():
static struct miscdevice mydrv_dev = { MYDRV_MINOR, "mydrv", &mydrv_fops }; misc_register(&mydrv_dev);
In the preceding example, MYDRV_MINOR is the minor number that you want to statically assign to your misc driver. You may also request a minor number to be dynamically assigned by specifying MISC_DYNAMIC_MINOR rather than MYDRV_MINOR in the mydrv_dev structure.
Each misc driver automatically appears under /sys/class/misc/ without explicit effort from the driver writer. Because misc drivers are char drivers, the earlier discussion on char driver entry points hold for misc drivers, too. Let's now look at an example misc driver.
A watchdog's function is to return an unresponsive system to operational state. It does this by periodically checking the system's pulse and issuing a reset[4] if it can't detect any. Application software is responsible for registering this pulse (or "heartbeat") by periodically strobing (or "petting") the watchdog using the services of a watchdog device driver. Most embedded controllers support internal watchdog modules. External watchdog chips are also available. An example is the Netwinder W83977AF chip.
[4] A watchdog may issue audible beeps rather than a system reset. An example scenario is when a timeout occurs due to a power supply problem, assuming that the watchdog circuit is backed up using a battery or a super capacitor.
Linux watchdog drivers are implemented as misc drivers and live inside drivers/char/watchdog/. Watchdog drivers, like RTC drivers, export a standard device interface to user land, so conforming applications are rendered independent of the internals of watchdog hardware. This API is specified in Documentation/watchdog/watchdog-api.txt in the kernel source tree. Programs that desire the services of a watchdog operate on /dev/watchdog, a device node having a misc minor number of 130.
Listing 5.9 implements a device driver for a fictitious watchdog module built in to an embedded controller. The example watchdog contains two main registers as shown in Table 5.2: a service register (WD_SERVICE_REGISTER) and a control register (WD_CONTROL_REGISTER). To pet the watchdog, the driver writes a specific sequence (0xABCD in this case) to the service register. To program watchdog timeout, the driver writes to specified bit positions in the control register.
Strobing the watchdog is usually done from user space because the goal of having a watchdog is to detect and respond to both application and kernel hangs. A critical application[5] such as the graphics engine in Listing 5.10 opens the watchdog driver in Listing 5.9 and periodically writes to it. If no write occurs within the watchdog timeout due to an application hang or a kernel crash, the watchdog triggers a system reset. In the case of Listing 5.10, the watchdog will reboot the system if
[5] If you need to monitor the health of several applications, you may implement a multiplexer in the watchdog device driver. If any one of the processes that open the driver becomes unresponsive, the watchdog attempts to self-correct the system.
The watchdog starts ticking when an application opens /dev/watchdog. Closing this device node stops the watchdog unless you set CONFIG_WATCHDOG_NOWAYOUT during kernel configuration. Setting this option helps you tide over the possibility that the watchdog monitoring process (such as Listing 5.10) gets killed by a signal while the system continues running.
Code View: #include |
#include |
For platforms that do not support a hardware watchdog module, the kernel implements a software watchdog, also called a softdog. The softdog driver, drivers/char/watchdog/softdog.c, is a pseudo misc driver because it does not operate on real hardware. The softdog driver has to perform two tasks that a watchdog driver doesn't have to do, which the latter accomplishes in hardware:
Implement a timeout mechanism
Initiate a soft reboot if the system isn't healthy
This is done by delaying the execution of a timer handler whenever an application writes to the softdog. If no write occurs to the softdog within a timeout, the timer handler fires and reboots the system.
A related support in 2.6 kernels is the sensing of soft lockups, which are instances when scheduling does not occur for 10 or more seconds. A kernel thread watchdog/N, where N is the CPU number, touches a per-CPU timestamp every second. If the thread doesn't touch the timestamp for more than 10 seconds, the system is deemed to have locked up. Soft lockup detection (implemented in kernel/softlockup.c) will aid us while debugging a kernel crash in the section "Kdump" in Chapter 21, "Debugging Device Drivers."
There are several more misc drivers in the kernel. The Qtronix infrared keyboard driver, drivers/char/qtronix.c, is another example of a char driver that has a misc form factor. Do a grep on misc_register() in the drivers/char/ directory to find other misc device drivers present in the kernel.