Linux kernel Driver Implementation method for Android system in Ubuntu _android

Source: Internet
Author: User
Tags goto semaphore

In the age of smartphones, each brand's mobile phone has its 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. Reference to the previous two articles the Android source is downloaded on Ubuntu, compiled and installed and downloaded on the android kernel source in Ubuntu, compiled, installed (Linux Kernel) ready for the Android kernel driver development environment.

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:

#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

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.

         first contains the necessary header files and defines three ways to access the device:

#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 device and from 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_r

Elease,. 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, mainly defining the four methods of opening, releasing, reading, and writing device files for Hello_open, Hello_release, Hello_read, and Hello_write:

/* open Device Method */static int hello_open (struct inode* inode, struct file* filp) {struct dev;
	/* The custom device structure is saved in the private data field of the file pointer for access to the device using/dev = container_of (inode->i_cdev, struct hello_android_dev, dev);
	
	Filp->private_data = Dev;
return 0;

}/* Device file release called, NULL implementation/static int hello_release (struct inode* inode, struct file* filp) {return 0;} /* Read Device register Val value/static ssize_t hello_read (struct file* filp, char __user *buf, size_t count, loff_t* f_pos) {ssize_t E
	rr = 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 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) {struct 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;
		/* * Writes 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 (dev->val);
	Out:up (& (Dev->sem));
return err; }

The

Defines the access method through the Devfs file system, where the register Val of the device is considered to be an attribute of the device, accessed by reading and writing this property, primarily implementing hello_val_show and Hello_val_ Store two methods, while defining the two methods used internally to access the Val value __hello_get_val and __hello_set_val:

/* Read the value of register Val to the buffer buf, internal use/static ssize_t __hello_get_val (struct hello_android_dev* dev, char* 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); /* * Write the value of the buffer buf to the device register Val, internal use/static ssize_t __hello_set_val (struct hello_android_dev* dev, const char* buf, size_t Co 

	UNT) {int val = 0; 

	/* Converts a string to a number/val = Simple_strtol (buf, NULL, 10); 
	/* Synchronous Access/if (down_interruptible (& Dev->sem)) {Return-erestartsys; 
	} dev->val = val;

	Up (& (Dev->sem));
return count; /* Read Device properties val*/static ssize_t hello_val_show (struct device* dev, struct device_attribute* attr, char* buf) {struct HEL 

	lo_android_dev* Hdev = (struct hello_android_dev*) dev_get_drvdata (dev);
Return __hello_get_val (Hdev, buf); /* Write device properties val*/static ssize_t hello_val_store (struct device* dev, struct device_attribute* attr, const char* BUF, Size_t count) {struct hello_android_dev* Hdev = (struct hello_android_dev*) dev_get_drvdata (dev);
Return __hello_set_val (Hdev, buf, Count); }

The

  definition uses the proc file system access method, which mainly implements the Hello_proc_read and Hello_proc_write two methods. Also defines methods for creating and deleting files in the proc file system Hello_create_proc and hello_remove_proc :

/* Read the value of the device register Val, save in the page buffer/static ssize_t Hello_proc_read (char* page, char** start, off_t off, int count, int* EOF, Voi
		d* data) {if (off > 0) {*eof = 1;
	return 0;
Return __hello_get_val (Hello_dev, page); /* * To save the value of the buffer buff to the device register Val */static ssize_t hello_proc_write (struct file* filp, const char __user *buff, unsigned long l
	EN, void* data) {int err = 0;

	char* page = NULL;
		if (Len > Page_size) {printk (kern_alert "The buff is too large:%lu.\n", Len);
	Return-efault;
	page = (char*) __get_free_page (Gfp_kernel);
		if (!page) {PRINTK (Kern_alert "Failed to Alloc page.\n");
	Return-enomem; }/* First copy the user supplied buffer value to the kernel buffer */if (Copy_from_user (page, buff, len)) {PRINTK (kern_alert "Failed to copy buff from user.\n 
		");
		err =-efault;
	Goto out;

Err = __hello_set_val (Hello_dev, page, Len);
	Out:free_page ((unsigned long) page);
return err;
	
	* * * Create/proc/hello file/static void Hello_create_proc (void) {struct proc_dir_entry* entry; Entry = Create_proc_enTry (hello_device_proc_name, 0, NULL);
		if (entry) {Entry->owner = This_module;
		Entry->read_proc = Hello_proc_read;
	Entry->write_proc = Hello_proc_write; }/* Delete/proc/hello file */static void Hello_remove_proc (void) {Remove_proc_entry (hello_device_proc_name, NULL);}

  Finally, define module loading and unloading methods, where you can perform device registration and initialization operations:

static int __hello_setup_dev (struct hello_android_dev* dev) {int err;

	dev_t Devno = Mkdev (Hello_major, Hello_minor);

	memset (Dev, 0, sizeof (struct hello_android_dev));
	Cdev_init (& (Dev->dev), &hello_fops);
	Dev->dev.owner = This_module; 

	Dev->dev.ops = &hello_fops;
	/* Registered character device/err = Cdev_add (& (Dev->dev), Devno, 1);
	if (err) {return err;
	/* The value of the initialization semaphore and register Val/* Init_mutex (& (Dev->sem));

	Dev->val = 0;
return 0;
	}/* Module Load method */static int __init hello_init (void) {int err =-1;
	dev_t dev = 0;

	struct device* temp = NULL; 

	PRINTK (kern_alert "initializing Hello device.\n");
	/* Dynamic allocation of the main device and from the device number/err = alloc_chrdev_region (&dev, 0, 1, hello_device_node_name);
		if (Err < 0) {PRINTK (Kern_alert "Failed to alloc Char dev region.\n");
	Goto fail;
	} hello_major = major (Dev); 

	Hello_minor = minor (dev);
	/* Allocation HELO DEVICE structure Variable * * Hello_dev = kmalloc (sizeof (struct hello_android_dev), gfp_kernel);
		if (!hello_dev) {err =-enomem; PRINTK (KERn_alert "Failed to Alloc hello_dev.\n");
	Goto unregister;
	/* Initialize device/err = __hello_setup_dev (Hello_dev);
		if (err) {PRINTK (kern_alert "Failed to setup Dev:%d.\n", err);
	Goto cleanup;
	/* * Create the device category directory under the/sys/class/directory hello*/hello_class = class_create (This_module, hello_device_class_name);
		if (Is_err (Hello_class)) {ERR = Ptr_err (Hello_class);
		PRINTK (Kern_alert "Failed to create Hello class.\n");
	Goto Destroy_cdev; /* Create device files separately under the/dev/directory and/sys/class/hello directory hello*/temp = device_create (Hello_class, NULL, Dev, "%s", Hello_device_file_n
	AME);
		if (Is_err (temp)) {ERR = Ptr_err (temp);
		PRINTK (Kern_alert "Failed to create Hello device.");
	Goto Destroy_class;
	/* Create a property file in the/sys/class/hello/hello directory val*/err = device_create_file (temp, &dev_attr_val); 
		if (Err < 0) {PRINTK (kern_alert "Failed to create attribute Val.");
	Goto Destroy_device; 

	} dev_set_drvdata (temp, hello_dev);

	* * Create/proc/hello File/Hello_create_proc (); PRINTK (Kern_alert "succedded to InitiaLize Hello device.\n ");

return 0;

Destroy_device:device_destroy (Hello_class, Dev);

Destroy_class:class_destroy (Hello_class);

Destroy_cdev:cdev_del (& (Hello_dev->dev));

Cleanup:kfree (Hello_dev);

Unregister:unregister_chrdev_region (Mkdev (Hello_major, Hello_minor), 1);
Fail:return err;

	/* Module Uninstall method/static void __exit hello_exit (void) {dev_t Devno = Mkdev (Hello_major, Hello_minor); 

	PRINTK (kern_alert "Destroy Hello device.\n"); 

	/* Delete/proc/hello file */Hello_remove_proc ();
		/* Destruction Equipment category and equipment/if (Hello_class) {Device_destroy (Hello_class, Mkdev (Hello_major, Hello_minor));
	Class_destroy (Hello_class);
		/* Remove character devices and release device memory//if (Hello_dev) {Cdev_del (& Hello_dev->dev));
	Kfree (Hello_dev);
/* Release Device number */Unregister_chrdev_region (DEVNO, 1);
} module_license ("GPL");

Module_description ("the Driver");
Module_init (Hello_init); Module_exit (Hello_exit);

Five. Add kconfig and makefile two files in the Hello directory , where Kconfig is used when the configuration command make Menuconfig is executed before compiling, and makefile is used to execute compile command make:

contents of Kconfig file

Config HELLO
TriState "The Driver of the"
Default n
Help
This is the the driver Android.

contents of makefile file

obj-$ (Config_hello) + + hello.o

In the Kconfig file, TriState represents the compile option Hello support when compiling the kernel, the Hello module supports modules, builds, and does not compile three compilation methods, and by default it does not compile, so before compiling the kernel, we also need to execute make Menuconfig command to configure compilation options so that Hello can be compiled in a modular or built-in way.

In the makefile file, perform different compilation methods based on the value of the option hello.

Six. Modify Arch/arm/kconfig and Drivers/kconfig two files to add a row between menu "Device Drivers" and Endmenu:

source "Drivers/hello/kconfig"

This allows you to configure the compile options for the Hello module when you execute make menuconfig.

Seven. Modify the Drivers/makefile file and add one line:

obj-$ (Config_hello) + + hello/

Eight. Configure compilation options:

user-name@machine-name:~/android/kernel/common$ make menuconfig

Locate the "Device Drivers" => "the" "The" "The" "The" "The" "" ".

Note that if the kernel does not support dynamic loading of modules, you cannot select M here, although we have configured the Hello option to tristate in the Kconfig file. To support dynamic load module options, you must select the Enable Loadable Module support option in the Configuration menu, and in support of the Dynamic Uninstall Module option, you must select module in the Enable Loadable Module support menu item Unloading option.

Nine. Compile:

user-name@machine-name:~/android/kernel/common$ Make

After the compilation is successful, you can see the hello.o file in the Hello directory, and the compiled zimage already contains the Hello driver.

10. Run the newly compiled kernel file to verify that the Hello driver is properly installed by referring to downloading , compiling, and installing the latest Android Kernel source code (Linux Kernel) in Ubuntu :

user-name@machine-name:~/android$ emulator-kernel./kernel/common/arch/arm/boot/zimage &
user-name@machine-name:~/android$ adb shell

Access to the Dev directory, you can see the Hello device file:

root@android:/# CD Dev
Root@android:/dev # ls

Entering the proc directory, you can see the hello file:

root@android:/# CD Proc
Root@android:/proc # ls

To access the value of the Hello file:

Root@android:/proc # Cat Hello
0

Root@android:/proc # echo ' 5 ' > Hello
Root@android:/proc # Cat Hello
5

Access to the Sys/class directory, you can see the Hello directory:

root@android:/# CD Sys/class
Root@android:/sys/class # ls

Into the Hello directory, you can see the Hello directory:

Root@android:/sys/class # cd Hello
Root@android:/sys/class/hello # ls

Go to the next level Hello directory, you can see the Val file:

Root@android:/sys/class/hello # cd Hello
Root@android:/sys/class/hello/hello # ls

To access the value of the property file Val:

Root@android:/sys/class/hello/hello # cat Val
5

Root@android:/sys/class/hello/hello # echo ' 0 ' > val
Root@android:/sys/class/hello/hello # cat Val
0

At this point, our Hello kernel driver is complete and verifies that everything is OK. Here we are using the system provided by the method and the driver to interact, that is, through the proc file system and Devfs file system method, in the next article, we will compile the C language program to access the/dev/hello file to the Hello driver interaction, please look forward to.

Follow-up to continue to collate relevant article materials, I hope to help study the android source of friends, thank you for your support!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.