driver programming report

12
Programming Linux Device Drivers Sarthak Veggalam {[email protected]} Shivek Khurana {[email protected] } Report submitted for the partial fulfillment of the degree B.Tech Innovation with Mathematics and IT Cluster Innovation Centre University Of Delhi

Upload: shivek-khurana

Post on 23-Jun-2015

124 views

Category:

Devices & Hardware


2 download

DESCRIPTION

This is the detailed outline and outcomes of our driver programming project. Presentation at : http://www.slideshare.net/shivekkhurana/driver-programming-the-linux-way

TRANSCRIPT

Page 1: Driver Programming Report

Programming Linux Device Drivers

Sarthak Veggalam {[email protected]} Shivek Khurana {[email protected]}

Report submitted for the partial fulfillment of the degree B.Tech Innovation with Mathematics and IT

Cluster Innovation Centre University Of Delhi

Page 2: Driver Programming Report

Abstract

Drivers are software counterparts of onboard hardware and peripheral devices. Today’s computer architecture is divided into 3 core components : hardware, kernel(OS) and user space(shell). The driver layer sits over hardware along with kernel to read from, write to devices. The hardware connector has various ports to transfer signals, also called interrupts. These electrical voltages are interpreted as hexadecimal numbers. All OSs tackle driver implementations using different paradigms. In this project, we learnt and implemented linux driver programming paradigm. We have created drivers for wired devices over serial and usb port and wireless devices over TCP and UDP. We have also introduced a new way of organizing code using sub directories rather than plain files in the same directory, similar high level language frameworks like Django and Rails.. All kernel softwares in our project are programmed using C programming language. We use the default Linux kernel APIS

Page 3: Driver Programming Report

Acknowledgement

We would like to express my special thanks to our guide, Professor Alok Nikhil. We would also like to thank our friends and batchmates who helped us a lot in finishing this project within the limited time. Sarthak Veggalam Shivek Khurana

Page 4: Driver Programming Report

Index

Abstract Acknowledgement Index Introduction The Linux Kernel

Process Management Memory management File Systems Device Control Networking

Types of Devices 1.Character Devices 2.Block Devices 3.Network Interfaces

Makefile# Modules

Dynamic Loading Loading, Unloading Modules

Insmod Modprobe Semaphores Kernel Stack Size The Kernel stack size is small as compared to the user space stack.Hence it’s a good programming practice to declare global variables instead of local variables as it may lead to stack overflow.

User Space and Kernel Space The Linux Device Model

Power management and system shutdown Communications with user space Hotpluggable devices Device classes Object lifecycles

References Appendix

Page 5: Driver Programming Report

Introduction

Making hardware work is a tedious process. To interpret mouse motion, for example, requires you to map magic numbers to magic files and processes that move the pointer, and hence control the system. Instead of putting code in each application to control the hardware, Linux (OS in general) extracts out the hardware interaction functionality and label them as drivers. This extraction is desirable because :

1. It let’s applications share the same underlying structure 2. It let’s us upgrade hardware or update software without changing the application at all 3. It provides the kernel the ability to restrict or allow certain users from using certain devices or

parts of devices and 4. It also allows the kernel to load, unload devices on runtime

Drivers plugin to the kernel as a module and is available to the user space as a device file. In linux, device files are located in /dev directory. The user then perform file operations(open ,close, read, write) on this device file and the corresponding driver methods will in turn control the physical device. A typical device driver includes definitions for file operations, it’s entry and exit point and error handling. Other factors may be required for different types of drivers but this basic structure remains the same. After successfully compiling the code using a Makefile , the module object is attached to the kernel using insmod . 1 2

Once successfully attached, the device can be accessed in the user space by simply including the device file in the user space program and performing usual file operations on it.

1 http://mrbook.org/tutorials/make/ 2 http://linux.about.com/od/commands/l/blcmdl8_insmod.htm

Page 6: Driver Programming Report

The Linux Kernel

The kernel is the big chunk of executable code in charge of handling all such requests. In a Unix system, several concurrent processes attend to different tasks. Each process asks for system resources, be it computing power, memory, network connectivity, or some other resource. Fig. 1 depicts the schematic diagram of the Linux Kernel.

Fig 1 : The Linux Kernel Map. Source : Wikipedia 3

Process Management

The kernel is in charge of creating and destroying processes and handling their connection to the outside world (input and output). Communication among different processes (through signals, pipes, or interprocess communication primitives) is basic to the overall system functionality and is also handled by the kernel.

3 http://en.wikipedia.org/wiki/Linux_kernel

Page 7: Driver Programming Report

Memory management

The kernel builds up a virtual addressing space for any and all processes on top of the limited available resources. The different parts of the kernel interact with the memory-management subsystem through a set of function calls, ranging from the simple malloc/free pair to much more complex functionalities.

File Systems

Unix is heavily based on the filesystem concept; almost everything in Unix can be treated as a file. The kernel builds a structured filesystem on top of unstructured hardware, and the resulting file abstraction is heavily used throughout the whole system.

Device Control

Almost every system operation eventually maps to a physical device. With the exception of the processor, memory, and a very few other entities, any and all device control operations are performed by code that is specific to the device being addressed. That code is called a device driver. The kernel must have embedded in it a device driver for every peripheral present on a system, from the hard drive to the keyboard and the tape drive.

Networking

Networking must be managed by the operating system, because most network operations are not specific to a process: incoming packets are asynchronous events. The packets must be collected, identified, and dispatched before a process takes care of them.The system is in charge of delivering data packets across program and network interfaces, and it must control the execution of programs according to their network activity.

Types of Devices

There are three types of devices : Character, Block and Network Interfaces.

1.Character Devices

A character device operates in synchronisation with a char driver which interacts with the device by sending or receiving single character of data i.e. it deals with the IO on a character by character basis. Such a driver usually implements at least the open, close, read, and write system calls. The text console (/dev/console) and the serial ports (/dev/ttyS0 and friends) are examples of char devices, as they are well represented by the stream abstraction. Char devices are accessed by means of filesystem nodes, such as /dev/tty1 and /dev/lp0.

Page 8: Driver Programming Report

The only relevant difference between a char device and a regular file is that you can always move back and forth in the regular file, whereas most char devices are just data channels, which you can only access sequentially. There is no buffering while operating on the character devices as they are not accessed via cache . File systems also cannot be mounted on character devices.

2.Block Devices

A block driver interacts with a block device by sending blocks or chunks of data. Like char devices, block devices are accessed by filesystem nodes in the /dev directory. Transaction of large chunks of data back and forth is done efficiently in block devices rather than character devices.Linux, instead, allows the application to read and write a block device like a char device—it permits the transfer of any number of bytes at a time. Block and char devices differ only in the way data is managed internally by the kernel, and thus in the kernel/driver software interface. Like a char device, each block device is accessed through a filesystem node, and the difference between them is transparent to the user. Block drivers have a completely different interface to the kernel than char drivers.

3.Network Interfaces

Any network transaction is made through an interface, that is, a device that is able to exchange data with other hosts. Usually, an interface is a hardware device, but it might also be a pure software device, like the loopback interface. A network interface is in charge of sending and receiving data packets, driven by the network subsystem of the kernel, without knowing how individual transactions map to the actual packets being transmitted. A network interface isn’t easily mapped to a node in the filesystem, as /dev/tty1 because it is not stream

oriented. The Unix way to provide access to interfaces is still by assigning a unique name to them (such as eth0), but that name doesn’t have a corresponding entry in the filesystem. Communication between the kernel and a network device driver is completely different from that used with char and block drivers. Instead of read and write, the kernel calls functions related to packet transmission.

Makefile 4

A makefile is used with the UNIX make utility to determine which portions of a program to compile. A

4 http://en.wikipedia.org/wiki/Make_(software)

Page 9: Driver Programming Report

makefile is basically a script that guides the make utility to choose the appropriate program files that are to be compiled and linked together. The make utility keeps track of the last time files were updated so that it only updates the files containing changes. However, all of the files that are dependent on the updated files must be compiled as well, which can be very time-consuming. With the help of makefile, the make utility automates this compilation to ensure that all files that have been updated - and only those - are compiled and that the most recent versions of files are the ones linked to the main program, without requiring the user to perform the tasks separately.

Modules

Modular programming is a software design technique that emphasizes separating the functionality of a program into independent, interchangeable modules, such that each contains everything necessary to execute only one aspect of the desired functionality. Conceptually, modules represent a separation of concerns, and improve maintainability by enforcing logical boundaries between components. Modules are typically incorporated into the program through interfaces. A module interface expresses the elements that are provided and required by the module. The elements defined in the interface are detectable by other modules. The implementation contains the working code that corresponds to the elements declared in the interface

Dynamic Loading

In computing, a loadable kernel module (or LKM) is an object file that contains code to extend the running kernel, or so-called base kernel, of an operating system. LKMs are typically used to add support for new hardware and/or file systems, or for adding system calls. When the functionality provided by a LKM is no longer required, it can be unloaded in order to free memory and other resources.

Loading, Unloading Modules

Insmod

After the module is built, the next step is loading it into the kernel.The insmod loads the module code and data into the kernel.insmod accepts a number of command-line options and it can assign values to parameters in your module before linking it to the current kernel. Thus, if a module is correctly designed, it can be configured at load time; load-time configuration gives the user more flexibility than compile-time configuration, which is still used sometimes.

Modprobe

Modprobe, like insmod, loads a module into the kernel. It differs in that it will look at the module to be loaded to see whether it references any symbols that are not currently defined in the kernel. If any such references are found, modprobe looks for other modules in the current module search path that define the

Page 10: Driver Programming Report

relevant symbols. When modprobe finds those modules (which are needed by the module being loaded), it loads them into the kernel as well. If you use insmod in this situation instead, the command fails with an “unresolved symbols” message left in the system log file. Rmmod Modules may be removed from the kernel with the rmmod utility. Module removal fails if the kernel believes that the module is still in use (e.g., a program still has an open file for a device exported by the modules), or if the kernel has been configured to disallow module removal. It is possible to configure the kernel to allow “forced” removal of modules, even when they appear to be busy.

Semaphores

Semaphore as used in an operating system to restrict the access to resources by multiple processes at the same time. When a semaphore is used to restrict the access to only one process at a time, it is termed as mutex, as it serves the purpose of mutual exclusion. The part of the program which accesses the shared resource is called as the critical section. Hence a semaphore restricts the execution of the critical section by multiple processes at the same time.

Kernel Stack Size

The Kernel stack size is small as compared to the user space stack.Hence it’s a good programming practice to declare global variables instead of local variables as it may lead to stack overflow.

User Space and Kernel Space

A module runs in kernel space, whereas applications run in user space. This concept is at the base of operating systems theory. The role of the operating system, in practice, is to provide programs with a consistent view of the computer's hardware. In addition, the operating system must account for independent operation of programs and protection against unauthorized access to resources. This nontrivial task is possible only if the CPU enforces protection of system software from the applications. Every modern processor is able to enforce this behavior. The chosen approach is to implement different operating modalities (or levels) in the CPU itself. The levels have different roles, and some operations are disallowed at the lower levels; program code can switch from one level to another only through a limited number of gates. Unix systems are designed to take advantage of this hardware feature, using two such levels. All current processors have at least two protection levels, and some, like the x86 family, have more levels; when several levels exist, the highest and lowest levels are used. Under Unix, the kernel executes in the highest level (also called supervisor mode), where everything is allowed, whereas applications execute in the lowest level (the so-called user mode), where the processor regulates direct

Page 11: Driver Programming Report

access to hardware and unauthorized access to memory. We usually refer to the execution modes as kernel space and user space. These terms encompass not only the different privilege levels inherent in the two modes, but also the fact that each mode can have its own memory mapping—its own address space—as well. Unix transfers execution from userspace to kernel space whenever an application issues a system call or is suspended by a hardware interrupt. Kernel code executing a system call is working in the context of a process—it operates on behalf of the calling process and is able to access data in the process's address space. Code that handles interrupts, on the other hand, is asynchronous with respect to processes and is not related to any particular process. The role of a module is to extend kernel functionality; modularized code runs in kernel space. Usually a driver performs both the tasks outlined previously: some functions in the module are executed as part of system calls, and some are in charge of interrupt handling.

The Linux Device Model

One of the stated goals for the 2.5 development cycle was the creation of a unified device model for the kernel. Previous kernels had no single data structure to which they could turn to obtain information about how the system is put together. Despite this lack of information,things worked well for some time. The demands of newer systems,with their more complicated topologies and need to support features such as power management,made it clear,however,that a general abstraction describing the structure of the system was needed. The 2.6 device model provides that abstraction. It is now used within the kernel to support a wide variety of tasks, including:

Power management and system shutdown

These require an understanding of the system's structure. For example, a USB host adaptor cannot be shut down before dealing with all of the devices connected to that adaptor. The device model enables a traversal of the system's hardware in the right order.

Communications with user space

The implementation of the sysfs virtual file system is tightly tied into the device model and exposes the structure represented by it. The provision of information about the system to user space and knobs for changing operating parameters is increasingly done through sysfs and, therefore, through the device model.

Page 12: Driver Programming Report

Hotpluggable devices

Computer hardware is increasingly dynamic; peripherals can come and go at the whim of the user. The hotplug mechanism used within the kernel to handle and (especially) communicate with user space about the plugging and unplugging of devices is managed through the device model.

Device classes

Many parts of the system have little interest in how devices are connected, but they need to know what kinds of devices are available. The device model includes a mechanism for assigning devices to classes, which describe those devices at a higher, functional level and allow them to be discovered from user space.

Object lifecycles

Many of the functions described above, including hotplug support and sysfs, complicate the creation and manipulation of objects created within the kernel. The implementation of the device model required the creation of a set of mechanisms for dealing with object lifecycles, their relationships to each other, and their representation in user space.

References

[1] Solidus Code , Youtube Channel, https://www.youtube.com/user/SolidusCode?feature=playlist

[2] Linux Source Code, http://github.com/torvalds/linux

[3] Mary Shaw, “Writing Good Software Engineering Research Papers”, Carnegie Mellon University : http://www.cs.cmu.edu/~Compose/shaw-icse03.pdf

[4] Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman, “Linux Device Drivers, Third Edition”

Appendix

[1] Code at https://github.com/shivekkhurana/linux