of 27
7/27/2019 L35-36 Device Drivers
1/27
Software for Embedded Systems
IS C424
KCS Murt i
Device drivers
7/27/2019 L35-36 Device Drivers
2/27
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
7/27/2019 L35-36 Device Drivers
3/27
General classification of devices
Character
accessed as a stream of bytesopen, close, read, and write system calls
Block devices
accessed by filesystem nodes in the/dev directory.
can host a filesystem
Network interfacesa device that is able to exchange data with other hosts.
interface is a hardware or pure software device
7/27/2019 L35-36 Device Drivers
4/27
Kernel module
Runs in kernel space
kernel module registers itself in orderto 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
#include
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);
7/27/2019 L35-36 Device Drivers
5/27
Device Driver Relationships.
7/27/2019 L35-36 Device Drivers
6/27
Role of device driver
Roles:
Abstracts the hardware.Manages privilege.
Enables multiplexed access.
Martials data to and from an applications process space to kernel space.
Provides security.
driver provides services to other modules within the operating system. entry to the device driver often provides a reentrant API.
ensure safe concurrent access to the actual device or data.
Manage the memory associated with the payload being sent or received from the
device.
Provide separation for security and robustness. Driver is running in kernel process space has direct access to the buffer
Defect free as this works in kernel space.
7/27/2019 L35-36 Device Drivers
7/27
Low-Level Data Path(TX)
7/27/2019 L35-36 Device Drivers
8/27
Low-Level Data Path(RX)
7/27/2019 L35-36 Device Drivers
9/27
DMA approach
7/27/2019 L35-36 Device Drivers
10/27
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);
7/27/2019 L35-36 Device Drivers
11/27
Network devices
7/27/2019 L35-36 Device Drivers
12/27
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
7/27/2019 L35-36 Device Drivers
13/27
Packet arrivals
On arrival of a packet on the network interface,
the network device sends the packet via DMA into a receive bufferinterrupts 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)
7/27/2019 L35-36 Device Drivers
14/27
Storage File systems
abstract mechanism to open and close a storage device
read and write to a storage device. Many different file systems
Windows: NTFS,FAT32
Linux: EXT3/4
Embedded systems: JFFS2, TFAT, CRAMFS etc..
Steps:application performs a write to the file system.
file system allocates blocks on the storage device
Writes the required contents Into the allocated blocks
An asynchronous operation without blocking
file system drivers will at some point reflect the write in the file system
Journalling
system maintains a record of updates or deltas to the existing state of the mass
storage device.(EXT3)
Non-journalling
performs all updates directly to the file system management structures(FAT32)
7/27/2019 L35-36 Device Drivers
15/27
Character Driver Model
referenced through special files in the file system.
typically placed in the /dev folder major number typically indicates a device driver type
minor number indicates an instance
The user space application can perform the traditional
open/close/read/write and ioctl calls to interact with the device.
read()read data from the device.write()write data to the device.
ioctl()generic control function that can be used to pass setup
information and configuration information to a device.
Synchronous/asynchronous drivers
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
7/27/2019 L35-36 Device Drivers
16/27
A character driver
//Header files required for the driver
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include 7 #include
//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 }
// Makefile for simple driver.
obj-m += ex_kernel_drv.o
7/27/2019 L35-36 Device Drivers
17/27
A character device driver26 ssize_t drv_read(struct file *filep,char *user_buf, size_t count,loff_t *offp )
28 {
29 printk("Example driver read: size:%d\n",count);
30 if ( ret_count >= strlen(kernel_data))
31 {
32 printk("Example driver read: ret_count = %d", ret_count);
34 return 0;
35 }
36 if (
37 copy_to_user(user_buf,kernel_data,strlen(kernel_data)) != 0 )
39 printk("Kernel to user copy failed\n");
40 ret_count += strlen(kernel_data);
41 return (strlen(kernel_data));
42 }
7/27/2019 L35-36 Device Drivers
18/27
A character device driver43 ssize_t drv_write(struct file *filep, const char *user_buf, size_t count,loff_t *offp )
46 {47 printk("Example driver write:Count:%d\n",count);
48 if ( copy_from_user(kernel_data,user_buf,count) !=0 )
49 printk("User to kernel copy failed\n");
50 *(kernel_data+count)=NULL;
51 return count;
52 }
7/27/2019 L35-36 Device Drivers
19/27
A character device driver53// The device operations structure.
57 static struct file_operations drv_ops = {
58 .owner =THIS_MODULE,
59 .open = drv_open,
60 .read =drv_read,
61 .write =drv_write,
62 .release = drv_close,
63 /* .ioctl = drv_ioctl */
64 };
67 static int __init example_drv_init(void)
68 {
69 printk("Example driver init\n");
70 kernel_data =kmalloc(132,GFP_KERNEL);
71 strcpy(kernel_data, "Kernel data string not yet written to\n");
73 if ( register_chrdev( MAJOR_DEVICE_NUMBER, "example_dev", &drv_ops))77 printk("Device registration failed");
78 printk("Example driver init complete\n");
79 return 0;
80 }
7/27/2019 L35-36 Device Drivers
20/27
A character device driver82 static void __exit example_drv_exit(void)
83 {84 printk("Example driver exit\n");
85 unregister_chrdev(MAJOR_DEVICE_NUMBER,
"example_device");
87 kfree(kernel_data);
88 }
90 module_init(example_drv_init);
91 module_exit(example_drv_exit);
7/27/2019 L35-36 Device Drivers
21/27
A character device driverCompile the kernel modules
make -C /usr/src/linux-source-2.6.38/ M=$PWD modules
Next, create the device node in the /dev file system.
mknod /dev/new_device c 42 0
Now, load the kernel module (you can verify it was loaded by issuing the lsmod command).
insmod ex_kernel_drv.ko
Perform a number of reads and writes to the device.
cat /dev/example_device
Kernel data string not yet written to.
echo "Hello world driver" > /dev/example_device
cat /dev/example_device
Hello world driver.
echo "New string" > /dev/example_device
cat /dev/example_device
Debug messages from the module can be displayed using: dmesg
[46306.157051] Example driver init complete
[46309.165205] Example driver open
[46309.165317] Example driver read: size:32768
[46309.165465] Example driver read: size:32768
[46309.165482] Example driver read: ret_count 38
[46309.165510] Example driver close
7/27/2019 L35-36 Device Drivers
22/27
PCI device driver
kernel identifies all hardware on the
system associates it automatically with the
appropriate driver
Kernel module indicates list of
devices supported using
pci_device_table
static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl)
= {
PCI_DEVICE(0x8086, 0x1000),PCI_DEVICE(0x8086, 0x1000),
{0,}
};
MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
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);
static int __devinit e1000_probe (struct pci_dev
*pdev, const struct pci_device_id *ent)
the structureresponsible for
driver
7/27/2019 L35-36 Device Drivers
23/27
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 routinesrequest_irq(IRQ Number, callback function handler, irq_flags, name, data);
7/27/2019 L35-36 Device Drivers
24/27
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
7/27/2019 L35-36 Device Drivers
25/27
Interrupt flow
7/27/2019 L35-36 Device Drivers
26/27
References
Chap (7,8) Modern Embedded computing by Peter Barry
Linux device drivers by Corbet,Rubini
7/27/2019 L35-36 Device Drivers
27/27