Sie sind auf Seite 1von 39

Developing Device Drivers for Android Part 1: Basics

P.N. Anantharaman
Director Engineering, Adobe Systems India

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

References and Credits


Some of the examples and content in this presentation and my other
presentations on Kernel and Device drivers draw heavily from the following
resources and to be credited with the authors of these literature

The Linux Kernel Module Programming Guide by Peter Jay Salzman,


Michael Burian, Ori Pomerantz

http://www.freesoftwaremagazine.com/articles/drivers_linux

Essential Linux Device Drivers, Pearson Education by Sreekrishnan


Venkateswaran

The Design Of the Unix Operating System, PHI, Maurice J Bach

Linux Device Drivers Third Edition, OReilly, Jonathan Corbet, Alessandro


Rubini, and Greg Kroah-Hartman

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

What would we cover under device drivers?

Part 1 Basic Principles

Device drivers overview

A simple Hello World equivalent of a device driver

Part 2 Diving deeper

Hardware block diagram, buses, interrupts

Linux Device Driver model

Part 3 - Examples

IPC Binder driver, I2C, Power driver

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

What is a Device Driver?

Device drivers are programs that allow applications to access the devices in a
consistent, uniform and safe manner

In Linux, the devices are treated like files and hence their access is very similar to the way
files are accessed, thus providing uniformity

The interfaces to integrate a new device driver in to the OS is well defined and consistent
across different devices. This allows third party developers to easily integrate their devices in
to the OS

Device drivers form part of the OS running in kernel mode that have access to kernel
data structures and functions

Device specific details are localized to their respective drivers

The device drivers hide these details from the application or rest of the operating system,
thus making it simple to access the device and also add/remove new devices

Making the device drivers part of kernel and disallowing applications to directly
manipulate devices have the following advantages:

User mode applications dont need to worry about specifics of device. Without the device
driver the applications are more complex to maintain.

Improved security as user mode applications are not allowed to manipulate devices directly

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

Why should I care for device drivers?

The availability of new hardware, particularly on the mobile devices, implies


the requirement for accompanying new device drivers

Without suitable device drivers the hardware is unusable and hence the
hardware vendors often supply the device drivers. Hence the device driver
development is very critical.

Suppose you are engaged in a project where you build a new hardware
device and are interested in integrating that with the computing system, you
often need to write your own driver

Suppose you are required to understand an existing device driver and need
to extend it for some other use, it is essential to understand the concept
and implementation of device drivers

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

Policy and Mechanism

Device drivers provide the mechanism and policies can be implemented


on top of them by higher level layers

Eg: A hard disk driver is policy free while the higher layers may decide who can
access the device, how the device storage is utilized as disk blocks etc

Mechanism deals with: What capabilities are to be provided?, the


policies deal with: How are these capabilities used?

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

A simplified architecture depicting the role of a device driver


User mode
applications

libraries

System Call Interface

File sub system

Buffer Cache
Character
Block Drivers
Drivers
Device Drivers
Hardware Control
2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

Modules

Traditionally, the kernel is built as one kernel image having a fixed set of
functionalities. The device drivers were also built along with the kernel.

However, the newer versions of the kernel allow addition or removal of functionalities
to the kernel dynamically, when the kernel is already running

Modules provide the mechanism to accomplish this.

Each piece of code that can be added to the kernel at runtime can be introduced as
a module.

From the user space, one can install a module as a part of the kernel by using
insmod command and the module can be removed dynamically from the kernel by
using rmmod

Technically, a module is a piece of object code that can be linked with the kernel
dynamically. The module by itself is not an executable program

Modules are logically part of the kernel, they are not user programs though they may
be installed by user mode programs

A device driver can be introduced as a module

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

Types of Loadable Kernel Modules

Device drivers

File system driver (one for ext2, MSDOS FAT16, 32, NFS)

System calls

Network Drivers

Executable interpreters.

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

10

Modules (contd)

A module can be installed in the kernel by insmod command from the


user space and can be removed or uninstalled from the kernel using
rmmod command

The listing of all modules inserted in to the kernel can be viewed by a


user mode command lsmod that gets the information from /proc/modules

A minimalistic module can be written with 2 key functions: init_module( ),


cleanup_module( )

From Linux kernel 2.4 onwards, it is not necessary to name these


functions with these fixed names init_module( ), cleanup_module( ) but
one can use any names by using module_init( ) and module_exit( )
macros (See: linux/init.h)

The module can then be compiled in to the object code (usually with .ko
extension) and installed in to the kernel

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

11

Hello World Module version 1


#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
int init_module(void)
{
printk(KERN_INFO "Hello world 1.\n");
return 0; /* A non 0 return means init_module failed; module can't be loaded. */
}
void cleanup_module(void)
{
printk(KERN_INFO "Goodbye world 1.\n");
}

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

12

Hello World version 2


/* * hello2.c Demonstrating the module_init() and module_exit() macros. This is
preferred over using init_module() and cleanup_module(). */
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
static int __init hello_2_init(void)
{
printk(KERN_INFO "Hello, world 2\n");
return 0;
}
static void __exit hello_2_exit(void)
{
printk(KERN_INFO "Goodbye, world 2\n");
}
module_init(hello_2_init);
module_exit(hello_2_exit);
2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

13

Modules: __init, __exit, __initdata

The __init macro causes the init function to be discarded and its memory
freed once the init function finishes for builtin drivers, but not loadable
modules.

__initdata works similarly to __init but for init variables rather than functions.

The __exit macro causes the omission of the function when the module is
built into the kernel, and has no effect for loadable modules. Again, if you
consider when the cleanup function runs, this makes complete sense;
builtin drivers don't need a cleanup function, while loadable modules do.

Look at linux/init.h, these macros help free up kernel memory.

The kernel boot time message: Freeing unused kernel memory: 236k freed
is an illustration of this

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

14

Modules version 3
/* * hello3.c Illustrating the __init, __initdata and __exit macros. */
#include <linux/module.h> /* Needed by all modules */
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h> /* Needed for the macros */
static int hello3_data __initdata = 3;
static int __init hello_3_init(void)
{
printk(KERN_INFO "Hello, world %d\n", hello3_data);
return 0;
}
static void __exit hello_3_exit(void)
{
printk(KERN_INFO "Goodbye, world 3\n");
}
module_init(hello_3_init);
module_exit(hello_3_exit);
2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

15

Device Drivers in Linux

Character drivers

A device can be accessed as a stream of bytes using file system calls like
open, read, write, close etc

Usually, no buffer at driver level

Examples: Console, keyboard, Serial port

Block drivers

Block drivers are meant for those devices that operate on blocks of data as
compared to the devices that work at a character level granularity

Usually, the data from/to these devices are buffered at driver level

Example: Secondary storage devices like hard disk, CD etc

Network Drivers

Network drivers operate on packets and need different handling at driver level

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

16

Device Driver in perspective

Applications reside in the user space while the device


drivers are part of kernel

With the exception of some special situations that may arise


in embedded systems, applications and kernel are built
separately using different build mechanisms and are
different binaries. Hence the applications are not linked with
the device driver routines statically or directly

The devices are treated as files in Linux

As the nature of devices are very diverse, the


implementation of file system calls like open, read, write etc
are different for different devices

Hence the issue is: If we invoke a open file system call with
the device name as the file name, how does the kernel
locate the device and execute the right device driver
function? How does the kernel enforce permissions like the
way it enforces on regular files? How are the custom
functions (for example: take picture from camera) that may
be needed for a device are supported?

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

17

Table 1: Interfacing functions between user space and kernel space


Events

User Functions

Load Module
Open device
Read device
Write device
Close device
Remove module

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

18

Kernel Functions

Table 2: Kernel space and Hardware


Events

Kernel Functions

Read data
Write data

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

19

Example Device Driver


#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void) {
printk("<1> Hello world!\n"); return 0;
}
static void hello_exit(void) {
printk("<1> Bye, cruel world\n");
}
module_init(hello_init); module_exit(hello_exit);
2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

20

Building the object file

Insert the following statement in Makefile

obj-m += hello.o

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

21

Table 1: Interfacing functions between user space and kernel space


Events

User Functions

Kernel Functions

Load Module

insmod

module_init()

rmmod

module_exit()

Open device
Read device
Write device
Close device
Remove module

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

22

Character Device Driver Memory access

Let us consider a device driver memory.c that access memory as if it is a


device

Look at linux/fs.h to get an understanding of file_operations structure

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

23

Memory.c
MODULE_LICENSE("Dual BSD/GPL");
/* Declaration of memory.c functions */
int memory_open(struct inode *inode, struct file *filp);
int memory_release(struct inode *inode, struct file *filp);
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t memory_write(struct file *filp, char *buf, size_t count, loff_t *f_pos);
void memory_exit(void);
int memory_init(void);
/* Structure that declares the usual file */ /* access functions */
struct file_operations memory_fops = {
read: memory_read,
write: memory_write,
open: memory_open,
release: memory_release
};
/* Declaration of the init and exit functions */ module_init(memory_init); module_exit(memory_exit);
/* Global variables of the driver Major number */ int memory_major = 60;
/* Buffer to store data */ char *memory_buffer;
2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

24

Connection of device to file

In Linux devices are accessed as if they are files

Hence it is necessary to create a node for the device in the file system

Within the kernel, the device is referenced by its major number

Example: Let us create a file using: mknod /dev/memory c 4 0

In the above example, we created a device file by name memory that can
be accessed by user mode program referring to this as /dev/memory.
This is a character device with a major number 4 and minor number 0

How does the device file name is associated with the right device driver
in the kernel? The register_chrdev function makes this connection. It is
called with three arguments: major number, a string of characters
showing the module name, and a file_operations structure which links the
call with the file functions it defines. It is invoked, when installing the
module, in this way:

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

25

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

26

Device Driver Interface

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

27

<memory init module> =


int memory_init(void) {
int result;
/* Registering device */
result = register_chrdev(memory_major, "memory", &memory_fops);
if (result < 0) {
printk( "<1>memory: cannot obtain major number %d\n", memory_major); return result;
}
/* Allocating memory for the buffer */
memory_buffer = kmalloc(1, GFP_KERNEL);
if (!memory_buffer) { result = -ENOMEM; goto fail; }
memset(memory_buffer, 0, 1);
printk("<1>Inserting memory module\n");
return 0;
fail: memory_exit();
return result;
}
2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

28

Memory Exit function


void memory_exit(void) {
/* Freeing the major number */
unregister_chrdev(memory_major, "memory");
/* Freeing buffer memory */
if (memory_buffer)
{
kfree(memory_buffer);
}
printk("<1>Removing memory module\n");
}

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

29

Memory Driver: Opening the device

User mode applications typically use a library function fopen to open a file. This call
maps to the member function open of the file_operations structure.

The file_operations strucutre for a device driver is registered with the kernel through
a call to register_chrdev function

The structure associates a function pointer with the member field open of the
variable of form file_operations structure. In this case, it is the memory_open
function. It takes as arguments: an inode structure, which sends information to the
kernel regarding the major number and minor number; and a file structure with
information relative to the different operations that can be performed on a file.

When a file is opened, its normally necessary to initialize driver variables or reset
the device. In this simple example, though, these operations are not performed.

int memory_open(struct inode *inode, struct file *filp)


{
return 0;
}
2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

30

Table 1: Interfacing functions between user space and kernel space


Events

User Functions

Kernel Functions

Load Module

insmod

module_init()

Open device

fopen

file_operations: open

rmmod

module_exit()

Read device
Write device
Close device
Remove module

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

31

File Close

In our example, we dont need to do anything special for closing the device

int memory_release(struct inode *inode, struct file *filp)


{
/* Success */ return 0;
}

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

32

Table 1: Interfacing functions between user space and kernel space


Events

User Functions

Kernel Functions

Load Module

insmod

module_init()

Open device

fopen

file_operations: open

Close device

fclose

file_operations: release

Remove module

rmmod

module_exit()

Read device
Write device

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

33

Reading the device

The user space function fread or fscanf etc use the member read of the
file_operations structure. We will map the driver function memory_read to
the member function read and hence memory_read will be invoked
whenever fread or fscanf is called with the file descriptor that corresponds
to our /dev/memory

ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
/* Transfering data to user space */
copy_to_user(buf,memory_buffer,1);
/* Changing reading position as best suits */
if (*f_pos == 0) { *f_pos+=1; return 1; } else return 0;
}

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

34

Table 1: Interfacing functions between user space and kernel space


Events

User Functions

Kernel Functions

Load Module

insmod

module_init()

Open device

fopen

file_operations: open

Read device

fread

file_operations: read

Close device

fclose

file_operations: release

Remove module

rmmod

module_exit()

Write device

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

35

Writing to the device

The user space function fwrite or fprintf etc use the member write of the
file_operations structure. We will map the driver function memory_write to
the member function write and hence memory_write will be invoked
whenever fwrite or fprintf is called with the file descriptor that corresponds
to our /dev/memory

ssize_t memory_write(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
char *tmp;
tmp=buf+count-1;
copy_from_user(memory_buffer,tmp,1);
return 1;
}

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

36

Table 1: Interfacing functions between user space and kernel space


Events

User Functions

Kernel Functions

Load Module

insmod

module_init()

Open device

fopen

file_operations: open

Read device

fread

file_operations: read

Write device

fwrite

file_operations: write

Close device

fclose

file_operations: release

Remove module

rmmod

module_exit()

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

37

Completing the installation of the driver


# insmod memory.ko
# chmod 666 /dev/memory
If everything went well, you will have a device /dev/memory to which you
can write a string of characters and it will store the last one of them. You
can perform the operation like this:
$ echo -n abcdef > /dev/memory
To check the content of the device you can use a simple cat:
$ cat /dev/memory
The stored character will not change until it is overwritten or the module is
removed

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

38

Summary General Implementation Steps

Understand the device characteristic and supported


commands.
Map device specific operations to unix file operation
Select the device name (user interface)
(optional) select a major number and minor (a device
special file creation) for VFS interface

1.
2.
3.
4.

5.
6.
7.

Mapping the number to right device sub-routines

Implement file interface subroutines


Compile the device driver
Install the device driver module with loadable kernel module
(LKM) or Rebuild (compile) the kernel

2011 Adobe Systems Incorporated. All Rights Reserved. Adobe Confidential.

39

Das könnte Ihnen auch gefallen