Professional Documents
Culture Documents
KCS Murti
Device drivers
Overview
A function of the OS is to provide arbitrated shared access to I/O devices in the system. Applications do not directly interact with the I/O devices Device driver provides an abstraction that allows the device to be written generically regardless of the resources allocated to the device. A software component within the kernel that directly interact with a hardware device. software layer that lies between the applications and the actual device
Kernel module
Runs in kernel space kernel module registers itself in order to serve future requests Exit function unloads the module. function calls and function pointers are used in a module to add new functionality to a running kernel insmod, loads a module into the kernel
#include <linux/init.h> #include <linux/module.h> MODULE_LICENSE("Dual BSD/GPL"); static int hello_init(void) { printk(KERN_ALERT "Hello, world\n"); return 0; } static void hello_exit(void) { printk(KERN_ALERT "Goodbye, cruel world\n"); } module_init(hello_init); module_exit(hello_exit);
DMA approach
Bus Drivers
Provide a mechanism to scan the bus at runtime and identify what devices are attached to the bus. (Enumeration) Bus driver handles the enumeration provides services to each of the devices attached Ex: PCI bus driver Scans the PCI configuration space for devices. Saves the device ID Identifies the memory size requested by each of the base address registers Allocates the memory space for the device. Assigns an interrupt(s) to the device. initializes a device driver registered for the specific device ID.
static int __devinit device_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
Network devices
Typical API
Load/Unload services to load a dynamic driver. Send/Packet Transmit Sends a buffer in the network stack format to be transmitted to on the network interface IOCTL I/o control interface . A generic control API for the driver. Device Stop/Start enable or disable the device
Packet arrivals
On arrival of a packet on the network interface, the network device sends the packet via DMA into a receive buffer interrupts the processor to indicate that a packet has arrived. The network driver then sends an event or notification to a deferred work task. When the deferred task wakes up to process the packet arrival event. makes a call to submit the packet to the IP stack. Linux calls send a packet from the driver up into the TCP/IP network stack netif_rx(struct sk_buff *skb) netif_receive_skb (struct sk_buff *skb)
root@ubuntu:/dev# ls -l crw------- 1 root root 5, 1 2011-05-14 20:31 console crw-rw-rw- 1 root tty 5, 0 2011-06-02 07:13 tty crw--w---- 1 root root 4, 0 2011-05-14 20:31 tty0 crw------- 1 root root 4, 1 2011-05-14 20:31 tty1
A character driver
// Makefile for simple driver. obj-m += ex_kernel_drv.o //Header files required for the driver 1 #include <linux/module.h> 2 #include <linux/moduleparam.h> 3 #include <linux/init.h> 4 #include <linux/kernel.h> 5 #include <linux/fs.h> 6 #include <linux/errno.h> 7 #include <asm/uaccess.h> //Define major device number 11 #define MAJOR_DEVICE_NUMBER 42 12 char *kernel_data; 13 int ret_count; 15 int drv_open(struct inode *inode, struct file *filep) 16 { 17 printk("Example driver open\n"); 18 ret_count 0; 19 return 0; 20 } 21 int drv_close(struct inode *inode,struct file *filep) 22 { 23 printk("Example driver close\n"); 24 return 0; 25 }
90 module_init(example_drv_init); 91 module_exit(example_drv_exit);
static int __devinit e1000_probe (struct pci_dev *pdev, const struct pci_device_id *ent)
static struct pci_driver e1000_driver = { .name =e1000_driver_name, .id_table = e1000_pci_tbl, .probe =e1000_probe, .remove = __devexit_p(e1000_remove), #ifdef CONFIG_PM /* Power Managment Hooks */ .suspend = e1000_suspend, .resume = e1000_resume, #endif .shutdown = e1000_shutdown, .err_handler = &e1000_err_handler }; pci_register_driver(&e1000_driver);
Interrupt Handling
Device driver should respond to interrupts created by device Legacy Interrupts; wire-based interrupts. Each wire is usually shared between multiple devices, each device can only generate a single interrupt type Message Signal Interrupts: system to allocate a number of interrupt vectors to the device. special system message that is directed to the CPUs APIC Message Signal Interrupts eXtension Vectors assigned to a device do not need be contiguous each vector allocated can be directed to a targeted core. driver assigns the vectors to callback routines request_irq(IRQ Number, callback function handler, irq_flags, name, data);
Deferred work
defer work to a kernel task context to perform the remainder of the interrupt work (bottom-half handling ) softIRQs, tasklets, and work queues softIRQs 32 defined in the system statically configured at compile time cannot be created dynamically. Tasklets: A function that is added to a linked list and then called when the softIRQ executes. must run to completion and should not block Only one instance of a given tasklet is guaranteed to execute at any one time. Work queue: executed in the context of a kernel thread. runs as a process that is scheduled
Interrupt flow
References
Chap (7,8) Modern Embedded computing by Peter Barry Linux device drivers by Corbet,Rubini