Reprinted from HTTP://BLOG.CSDN.NET/LUOSHENGYANG/ARTICLE/CATEGORY/838604/3 in the era of smartphone, each brand of mobile phones have their own personality characteristics. It is the unique personality to attract users, create brand cohesion and loyalty to the city, the typical representative of the non-iphone. According to statistics, as of May 2011, the App Store software number of 381,062, ranked first, while the Android Market application software number of 294738, followed by the App Store, and is expected to cross the app Store in August. As Android gradually expands its market share, the diversity of terminal equipment requires more mobile developers to participate. According to industry statistics, Android Research and development talent gap at least 300,000. At the moment, the demand for Android talent is skewed towards hardware-driven Android talent, one of Android's demand for software applications. In general, it is a chance for development engineers who are interested in Android hardware drivers. So let's take a look at how to write a kernel driver for the Android system.
Here, we do not write kernel drivers for real hardware devices. To facilitate the description of the process of writing kernel drivers for the Android system, we use a virtual hardware device that has only a 4-byte register that can be read and writable. The first time we learn programming languages, we like to use "Hello, World" as an example, here, we have this virtual device named "Hello", and this kernel driver is also named Hello driver. In fact, the Android kernel driver and the general Linux kernel driver writing method is the same, are implemented in the form of Linux modules, specific reference to the previous Android learning launch of the article mentioned in the Linux Device drivers book. However, here we also describe the Android kernel driver's writing and compiling process from the perspective of the Android system.
I. To download, compile and install the latest Android source code in Ubuntu, and to download, compile and install Android's latest kernel source code (Linux Kernel) in Ubuntu to prepare the Android kernel driver development environment for the previous two articles.
Two. Enter to Kernel/common/drivers directory, new Hello directory:
user-name@machine-name:~/android$ CD kernel/common/drivers
user-name@machine-name:~/android/kernel/common/drivers$ mkdir Hello
Three. Add hello.h files to the Hello directory:
[CPP] View Plain copy print? #ifndef _HELLO_ANDROID_H_ #define _HELLO_ANDROID_H_ #include <linux/cdev.h> #include <linux/semaphore.h> #define hello_device_node_name "Hello" #define HELLO_DEVICE_FILE_NAME "Hello" #define HELLO_DEVICE_PROC_NAME "HELLO" #define hello_device_class_ name "Hello" struct hello_android_dev { int val; struct semaphore sem; struct cdev dev; }; #endif #ifndef _hello_ Android_h_ #define _hello_android_h_ #include <linux/cdev.h> #include <linux/semaphore.h> #define Hello_ Device_node_name "Hello" #define hello_device_file_name "Hello" #define Hello_deVice_proc_name "Hello" #define hello_device_class_name "Hello" struct Hello_android_dev {int val; struct semaphore sem; s Truct Cdev Dev; }; #endif
This header file defines some string Chang, which we'll use later. In addition, the definition of a character device structure Hello_android_dev, this is our virtual hardware device, the Val member variable represents the register inside the device, its type is INT,SEM member variable is a semaphore, is using synchronous access register Val, The dev member variable is an embedded character device that the Linux driver customizes to the standard method of the character device structure.
Four. Add the hello.c file in the Hello directory, which is the implementation part of the driver. The main function of the driver is to provide the upper level with the value of the registers that access the device, including reading and writing. Here, three methods of accessing device registers are provided, one is accessed through proc file system, the other is accessed through traditional method of device file, and third is accessed through Devfs file system. The following fragment describes the implementation of the driver.
The first is to include the necessary header files and define three ways to access the device:
[CPP] View Plain copy print? #include <linux/init.h> #include <linux/module.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/proc_fs.h > #include <linux/device.h> #include <asm/uaccess.h> #include "hello.h" /* Main equipment and variable */ static int from device number hello_major = 0; static int hello_minor = 0; /* device category and device variable */ static struct class* hello_class = null; static struct hello_android_dev* hello_dev = null; /* Traditional device file operation method */ Static int hello_open (struct inode* inode, struct file* &NBSP;FILP); Static int hello_release (struct inode* inode, strUCT&NBSP;FILE*&NBSP;FILP); Static ssize_t hello_read (struct file* filp, Char __user *buf, size_t count, loff_t* f_pos); static ssize_t hello_write (struct file* filp, const char __user *buf, size_t Count, loff_t* f_pos); /* Device file Operation method table */ Static struct file_ operations hello_fops = { .owner = this_module, .open = hello_open, .release = hello_release, .read = hello_read, .write = hello_write, }; /* Access Settings Property Method * * Static ssize_t hello_val_show (Struct device* dev, struct device_ attribute* attr, char* buf); Static ssize_t hello_val_store (struct device* dev, struct device_attribute* attr, const char* buf, size_t Count); /* defines device properties */ static device_attr (val, s_irugo | s_ Iwusr, hello_val_show, hello_val_store); #include <linux/init.h> #include <linux/ module.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/proc_fs.h> #include < linux/device.h> #include <asm/uaccess.h> #include "hello.h"/* main equipment and from the device number variable/static int hello_major = 0; static int hello_minor = 0; /* device category and device variable/static struct class* hello_class = NULL; static struct hello_android_dev* Hello_dev = NULL; /* Traditional Device file operation method * * static int hello_open (struct inode* inode, struct file* filp); static int hello_release (struct inode* inode, struct file* filp); Static ssize_t hello_read (struct file* filp, char __usEr *buf, size_t count, loff_t* F_pos); Static ssize_t hello_write (struct file* filp, const char __user *buf, size_t count, loff_t* F_pos); /* Device file Operation method table/static struct file_operations Hello_fops = {. Owner = This_module,. Open = Hello_open,. Release = Hello_rele ASE,. Read = Hello_read,. Write = Hello_write,}; /* Access Settings Property method * * Static ssize_t hello_val_show (struct device* dev, struct device_attribute* attr, char* buf); Static ssize_t hello_val_store (struct device* dev, struct device_attribute* attr, const char* buf, size_t count); /* Define device Properties/Static Device_attr (val, S_irugo | S_IWUSR, Hello_val_show, Hello_val_store);
Defines traditional device file access methods, primarily defining the four ways to open, release, read, and write device files for Hello_open, Hello_release, Hello_read, and Hello_write:
[CPP] View Plain copy print? /* Open Device Method */ Static int hello_open (struct inode* inode, struct file* &NBSP;FILP) { struct hello_android_dev* dev; /* The custom device structure is saved in the private data field of the file pointer so that the device is accessed using the */ dev = container_of (inode- >i_cdev, struct hello_android_dev, dev); filp->private _data = dev; return 0; } /* Device file release, NULL implementation */ static int hello_release (struct &NBSP;INODE*&NBSP;INODE,&NBSP;STRUCT&NBSP;FILE*&NBSP;FILP) { return 0; } * Read the value of the register Val for the device */ STATIC&NBSP;SSIZE_T&NBSp;hello_read (struct file* filp, char __user *buf, size_t count, loff_ T* f_pos) { ssize_t err = 0; struct hello_android_dev* dev = filp->private_data; /* Synchronous Access */ if (down_interruptible (& Dev->sem)) { return -ERESTARTSYS; } if (count < sizeof (dev->val)) { goto out; } /* Copies the value of the register Val to the user-supplied buffer */ iF (Copy_to_user (buf, & dev->val), sizeof (dev->val)) { err = -EFAULT; goto out; } err = sizeof (dev->val); out: up (& dev- >sem)); return err; } /* The register value of the write device val*/ static ssize_t hello_write (struct file* filp, const Char __user *buf, size_t count, loff_t* f_pos) { struct hello_android_dev* dev = filp->private_data; ssize_t err = 0; &NBSP;&NBsp; /* Synchronous Access */ if (down_interruptible (& (Dev->sem)) { return -ERESTARTSYS; } if (count != sizeof (dev->val)) { goto out; } /* writes the value of the user-supplied buffer to the device register to */ if Copy_from_user (& ( Dev->val), buf, count) { err = -EFAULT; goto out; } err = sizeof (dev->val); out: up (& (Dev->sem)); return err; } /* Open device Method */static int hello_open (struct inode* inode, struct file* Filp {struct hello_android_dev* dev; * Saves the custom device structure in the private data field of the file pointer so that the device can be accessed using the/dev = container_of (Inode->i_cdev, struct Hello_android_dev, Dev); Filp->private_data = Dev; return 0; }/* Device file release call, NULL implementation */static int hello_release (struct inode* inode, struct file* filp) {return 0;}///Read device register Val value/* Stati C ssize_t hello_read (struct file* filp, char __user *buf, size_t count, loff_t* f_pos) {ssize_t err = 0; struct Hello_and roid_dev* dev = filp->private_data; /* Synchronous Access/if (down_interruptible (& Dev->sem)) {Return-erestartsys} if (Count < sizeof (dev->val)) {goto OU T */* Copy the value of register Val to the user-supplied buffer */if (Copy_to_user buf, & (dev->val), sizeOf (Dev->val)) {err =-efault; goto out;} err = sizeof (dev->val); Out:up (& (Dev->sem)); return err; }/* Write device Register value val*/static ssize_t hello_write (struct file* filp, const char __user *buf, size_t count, loff_t* f_pos) {str UCT hello_android_dev* dev = filp->private_data; ssize_t err = 0; /* Synchronous Access/if (down_interruptible (& Dev->sem)) {Return-erestartsys} if (Count!= sizeof (dev->val)) {goto out; /* * Write the value of the user-supplied buffer to the device register/*/if (Copy_from_user (& Dev->val), buf, count) {err =-efault; goto out;} err = sizeof (DE V->val); Out:up (& (Dev->sem)); return err; }
Defined by the Devfs file system access method, where the device's register Val is viewed as an attribute of the device, accessed by reading and writing this property, mainly to implement the Hello_val_show and Hello_val_store two methods, Also defines the two methods used internally to access the Val value __hello_get_val and __hello_set_val:
[CPP] View Plain copy print? /* Reads the value of register Val into the buffer buf, using */ static ssize_t __hello_get_val internally (struct hello_android_dev* &NBSP;DEV,&NBSP;CHAR*&NBSP;BUF) { int val = 0; /* Synchronous Access */ if (down_interruptible (& Dev->sem)) { return -ERESTARTSYS; } val = dev->val; up (& (Dev->sem));   return snprintf (buf, page_size, "%d\n", val); } * Writes the value of the buffer buf to the device register Val, using */ static ssize_t __hello_set_val internally (struct hello_android_dev* dev, const char* buf, size_t count) { int val = 0; /* Converts a string into a digital */ val = simple_strtol (buf, null, 10); /* Synchronous Access */ if (down_interruptible (& Dev->sem)) { &n