Topic 10: Device Driver
Tongping Liu
University of Massachusetts Amherst 1 Administration
• Today it is the deadline of Project3 • Homework5 is posted, due on 05/03 • Bonus points: ECE570 – 3 points, ECE670-5 points – Design exam questions – Process&threads, scheduling, synchronization, IPC, memory management, device driver/virtualization – Due: 05/01 • Survey project (ECE570/ECE670): 05/12
University of Massachusetts Amherst 2 Objectives
• Understanding concepts of device driver, e.g., device number, device file • Understand the difference of kernel modules and device drivers • Learn how to implement a simple kernel module • Learn how to implement a simple device driver
University of Massachusetts Amherst 3 Outline
• Basic concepts • Kernel module • Writing device driver
University of Massachusetts Amherst 4 Device Driver
• A special kind of computer program that operates or controls a particular type of device that is attached to a computer
University of Massachusetts Amherst 5 Device Driver
• A special kind of computer program that operates or controls a particular type of device that is attached to a computer – Needs to execute privileged instructions – Must be integrated into the OS kernel, with a specific format – Interfaces both to kernel and to hardware
University of Massachusetts Amherst 6 Whole System Stack
Note: This picture is excerpted from Write a Linux Hardware Device Driver, Andrew O’Shauqhnessy, Unix world
University of Massachusetts Amherst 7 Another View from OS
University of Massachusetts Amherst 8 Type of Devices
• Character device – Read or write one byte at a time as a stream of sequential data – Examples: serial ports, parallel ports, sound cards, keyboard
• Block device – Randomly access fixed-sized chunks of data (block) – Examples: hard disks, USB cameras
University of Massachusetts Amherst 9 Linux Device Driver
• Manage data flow between user programs and device • Typically a self-contained kernel module – Add and remove dynamically • Device is a special file in /dev that user can access, e.g. /dev/lp0 • Can be only programed with C/assembly language
University of Massachusetts Amherst 10 Device Files
• Unix-like systems handle device files with separate subdirectory of /dev for each type of device: disk, block etc.
• Device files are created with mknod: mknod filename type major minor - filename is the device file to be created. - type is c for a character device or b for a block device. - major and minor are the major and minor device numbers.
University of Massachusetts Amherst 11 Device Numbers
• Major device number – Identify the driver that the file is associated with.
• Minor device number – Identify which particular device in a given type. – Called as unit number or instance of the device.
• Both values are stored in the file’s inode structure.
University of Massachusetts Amherst 12 Device Jump Table
• Each driver supports some or all of the following functions:
probe attach open close read reset stop select strategy dump psize write
• Addresses of these functions are stored in a structure called a jump table, which are indexed by major number
University of Massachusetts Amherst 13 Device Jump Table
• Two tables exists - One for character device - One for block devices.
• Upon operations on a device file – Kernel catches the reference, looks up the appropriate function name in the jump table, and transfers control to it.
• For unusual operation (ejecting floppy disk) – ioctl() to pass a message directly from user space into the driver
University of Massachusetts Amherst 14 Character Device Driver
• No buffering is required (only a byte) • Seeking is not allowed • Easy to program, since there is only one position and cannot move back and forth • read() and write() calls do not return until the operation is complete • The kernel doesn’t have to provide an entire subsystem to the character device, since it is less complex
University of Massachusetts Amherst 15 Block Device Driver
• Accessed through a cache so buffering is required. • Seeking is possible, which can move back and forth between any location • Kernel provides an entire subsystem, since it is too complex • Reads and write done by buffer cache mechanism by bread(), bwrite(). These request may be asynchronous.
University of Massachusetts Amherst 16 Outline
• Basic concepts • Kernel module • Writing device driver
University of Massachusetts Amherst 17 Device Driver Interface
Device driver typically exist as kernel modules
Note: This picture is excerpted from Write a Linux Hardware Device Driver, Andrew O’Shauqhnessy, Unix world
University of Massachusetts Amherst 18 Kernel Modules
• Definition: modules are pieces of code that can be loaded and unloaded into the kernel upon demand. – They extend the functionality of the kernel without the need to rebuild/reboot the system. – Without modules, we would have to build monolithic kernels and add new functionality directly into the kernel image. • Advantages: – We do not need to build the entire kernel, saving time – Help us to save memory, due to load on demand
University of Massachusetts Amherst 19 Kernel Modules vs. Device Drivers
• Most modules are device drivers – But some are not, such as IPv6 support or some file systems • Device drivers: drive the hardware – They can be built as kernel modules so that it can be dynamically loaded later. – They can also be built statically into the kernel file on disk.
University of Massachusetts Amherst 20 Device Drivers
• Device drivers are not always kernel modules: – A driver necessary to help the system bootup. – In embedded systems, if you know exactly which drivers will always be needed and that this will never change, then you could statically build it into the kernel – Provide additional security and stability at the expense of flexibility by disabling kernel modules
Device drivers can exist without driving a hardware
University of Massachusetts Amherst 21 Module Interfaces
• lsmod: what modules are already loaded into the kernel by reading the file /proc/modules.
[root@localhost~ ]#lsmod
University of Massachusetts Amherst 22 Module Interfaces
• modprobe: load the designated specific module, or a group of interdependent module . [root@localhost~ ]#modprobe [-lcfr] modules_name
University of Massachusetts Amherst 23 Module Interfaces
• modinfo: show the information of a module.
[root@localhost~ ]#modinfo module_name
University of Massachusetts Amherst 24 Module Interfaces
• insmod: Load the modules that aren’t in /lib/modules/***/kernel
[root@localhost~ ]#insmod module_name.ko
• rmmod: remove modules
[root@localhost~ ]#rmmod module_name
NCHU System & Network Lab University of Massachusetts Amherst 25 Hello, World: The Simplest Module
/* * hello.c − The simplest kernel module. */ #include
University of Massachusetts Amherst 26 Hello, World: The Simplest Module
/* * hello.c − The simplest kernel module. */ #include
University of Massachusetts Amherst 27 Basics of Kernel Module
• init_module() – Start/initialization function that is called when the module is insmoded into the kernel – Registers a handler for something with the kernel, or replaces one of the kernel functions with its own code • cleanup_module() – Called just before it is rmmoded – Undo whatever init_module() did
• MODULE_LISCENSE: avoids warning
University of Massachusetts Amherst 28 Outline
• Basic concepts • Kernel module • Writing device driver
https://www.linuxjournal.com/article/2476
https://www.apriorit.com/dev-blog/195-simple-driver-for-linux-os
https://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN121
University of Massachusetts Amherst 29 Device Driver Interface
Device driver typically exist as kernel modules
Note: This picture is excerpted from Write a Linux Hardware Device Driver, Andrew O’Shauqhnessy, Unix world
University of Massachusetts Amherst 30 Implementation Steps
1. Understand the device characteristic and supported commands. 2. Map device specific operations to unix file operations 3. Select the device name (user interface) 4. Select a major number and minor number for VFS interface: mapping to right device sub-routines 5. Implement file interface subroutines 6. Compile the device driver 7. Install the device driver module with loadable kernel module (LKM) or rebuild (compile) the kernel
University of Massachusetts Amherst 31 Common Operations
• Compile -Wall -DMODULE -D__KERNEL__ -DLINUX –DDEBUG -I /usr/include/linux/version.h -I/lib/modules/`uname -r`/build/include • Install the module %insmod module.o • List the module %lsmod • If you let the system pick Major number, you can find the major number (for special creation) by % more /proc/devices • Make a special file % mknod /dev/device_name c major minor
University of Massachusetts Amherst 32 Implementation Steps
1. Understand the device characteristic and supported commands. 2. Map device specific operations to unix file operations 3. Select the device name (user interface) 4. Select a major number and minor number for VFS interface: mapping to right device sub-routines 5. Implement file interface subroutines 6. Compile the device driver 7. Install the device driver module with loadable kernel module (LKM) or rebuild (compile) the kernel
University of Massachusetts Amherst 33 Principal Interfaces
University of Massachusetts Amherst 34 File Operation Structure struct file_operations • file_operations Fops = { NULL, /* seek */ structure is defined in xxx_read, linux/fs.h xxx_write, NULL, /* readdir */ • Holds pointers to NULL, /* select */ functions defined by NULL, /* ioctl */ NULL, /* mmap */ the driver that xxx_open, perform various NULL, /* flush */ xxx_release operations on the }; device.
University of Massachusetts Amherst 35 File Operation Structure
• Some operations are not implemented by a driver. – A driver that handles a video card won't need to read from a directory structure. – Then the corresponding entries will be set to NULL • Gcc extension to support the initialization
University of Massachusetts Amherst 36 Implementation
• Assuming that your device name is Xxx • Xxx_init() initialize the device when OS is booted • Xxx_open() open a device • Xxx_read() read from kernel memory • Xxx_write() write • Xxx_release() clean-up (close) • init_module() • cleanup_module()
University of Massachusetts Amherst 37 Register and Unregister Device int init_module(void) /*used for all initialition stuff*/ { /* Register the character device (atleast try) */ Major = register_chrdev(0, DEVICE_NAME, &Fops); …… } void cleanup_module(void) /*used for a clean shutdown*/ { ret = unregister_chrdev(Major, DEVICE_NAME); ...... } Adding a driver needs to register it with the kernel.
University of Massachusetts Amherst 38 Register Device
int register_chrdev(unsigned int major, char *name, struct file_operations *fops);
• major is the major number you want to request • name is the name of the device as it'll appear in /proc/devices • fops is a pointer to the file_operations table for your driver • A negative return value means the registration failed. • We didn't pass the minor number to register_chrdev. That's because the kernel doesn't care about the minor number, and only the driver uses it.
University of Massachusetts Amherst 39 Register Device
• It is careful to use major number – Avoid hijack one that's already in use • To avoid this, we could pass 0 instead and let the OS to assign one (return value of register function) • The downside is that we can't make a device file without the major number – Let the driver print major number – Read /proc/devices to find out – Let the driver to invoke mknod to create
University of Massachusetts Amherst 40 Kernel Functions
• get_user() – Allows a driver to access data in user space, a memory area distinct from the kernel • kfree() – Frees memory previously allocated with kmalloc() • kmalloc() – Allocates a chunk of memory • MAJOR() – Reports the major device number for a device. • MINOR() – Reports the minor device number for a device.
University of Massachusetts Amherst 41 Kernel Functions
• outb(), outb_p() – Writes a byte to a port. Here, outb() goes as fast as it can, while outb_p() pauses before returning. • printk() – A version of printf() for the kernel. • put_user() – Allows a driver to write data in user space. • register_*dev() – Registers a device with the kernel.
University of Massachusetts Amherst 42 A Simple Example static struct file_operations fops = { .read = device_read, .write = device_write, .open = device_open, .release = device_release };
int init_module(void) { Major = register_chrdev(0, DEVICE_NAME, &fops); return SUCCESS; } void cleanup_module(void) { int ret = unregister_chrdev(Major, DEVICE_NAME); if (ret < 0) printk(KERN_ALERT "Error in unregister_chrdev: %d\n", ret); } https://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN569
University of Massachusetts Amherst 43 A Simple Example
//Called when the device file is opened static int device_open(struct inode *inode, struct file *file) { static int counter = 0; Device_Open++; sprintf(msg, "I told you %d times Hello world!\n", counter++); msg_Ptr = msg; return SUCCESS; } static int device_release(struct inode *inode, struct file *file) { Device_Open--; /* We're now ready for our next caller */ module_put(THIS_MODULE); return 0; } https://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN569
University of Massachusetts Amherst 44 A Simple Example static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t * offset) { int bytes_read = 0; if (*msg_Ptr == 0) return 0; while (length && *msg_Ptr) { put_user(*(msg_Ptr++), buffer++); length--; bytes_read++; } return bytes_read; }
https://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN569
University of Massachusetts Amherst 45 Outline
• Basic concepts • Kernel module • Writing device driver
University of Massachusetts Amherst 46