Article reprinted to CSDN community Luo Shenyang's Android tour, original address: http://blog.csdn.net/luoshengyang/article/details/6573809
In the Android Hardware Abstraction Layer (HAL) Overview and Learning Plan article, we briefly describe the ways in which Android systems write drivers for hardware. In short, hardware drivers are distributed on the Linux kernel, and on the other hand, in the hardware abstraction layer of user space. Next, writing a Linux kernel driver for Android on Ubuntu cited example shows how to write a driver in the Linux kernel. In this article, we will continue to introduce the implementation of hardware drivers for Android systems on the other hand, that is, how to add hardware modules to the hardware abstraction layer to interact with the kernel driver. In this article, we will also learn how to modify the device file mode with the Linux-like Udev rules when creating device files on Android.
I. Refer to the example kernel driver for the Linux kernel driver written for Android on Ubuntu, as shown in the article. After completing this kernel driver, you can get three files in Android system, namely/dev/hello,/sys/class/hello/hello/val and/proc/hello. In this article, we will connect the hardware Abstraction Layer module and the Linux kernel driver module through the device file/dev/hello.
Two. Go to the Hardware/libhardware/include/hardware directory and create a new Hello.h file:
[email protected]:~/android$ cd Hardware/libhardware/include/hardware
[Email protected]:~/android/hardware/libhardware/include/hardware$ VI hello.h
the contents of the Hello.h file are as follows:
[CPP]View Plaincopy
- #ifndef Android_hello_interface_h
- #define Android_hello_interface_h
- #include
- __begin_decls
- /* Define Module id*/
- #define HELLO_HARDWARE_MODULE_ID "HELLO"
- /* Hardware module structure */
- struct hello_module_t {
- struct hw_module_t common;
- };
- /* Hardware Interface structure */
- struct hello_device_t {
- struct hw_device_t common;
- int fd;
- Int (*set_val) (struct hello_device_t* dev, int val);
- Int (*get_val) (struct hello_device_t* dev, int* val);
- };
- __end_decls
- #endif
In accordance with the requirements of the Android Hardware Abstraction Layer specification, the module ID, module structure and hardware interface structure are defined separately. In the hardware interface structure, FD represents the device file descriptor, which corresponds to the device file "/dev/hello" that we will be working on, and the Set_val and Get_val are the function interfaces provided on the HAL pair.
Three. Go to the Hardware/libhardware/modules directory, create a new Hello directory, and add the hello.c file. HELLO.C more content, we segmented to see.
The first is to include the relevant header file and define the relevant structure:
[CPP]View Plaincopy
- #define LOG_TAG "Hellostub"
- #include
- #include
- #include <fcntl.h>
- #include <errno.h>
- #include <cutils/log.h>
- #include <cutils/atomic.h>
- #define DEVICE_NAME "/dev/hello"
- #define MODULE_NAME "Hello"
- #define MODULE_AUTHOR "[Email protected]"
- /* Device to open and close the interface */
- static int Hello_device_open (const struct hw_module_t* module, const char* name, struct HW_ device_t** device);
- static int hello_device_close (struct hw_device_t* device);
- /* Device Access interface */
- static int hello_set_val (struct hello_device_t* dev, int val);
- static int hello_get_val (struct hello_device_t* dev, int* val);
- /* Module Method Table */
- Static struct hw_module_methods_t hello_module_methods = {
- Open:hello_device_open
- };
- /* Module instance variable */
- struct hello_module_t Hal_module_info_sym = {
- Common: {
- Tag:hardware_module_tag,
- Version_major:1,
- version_minor:0,
- ID:HELLO_HARDWARE_MODULE_ID,
- Name:module_name,
- Author:module_author,
- Methods: &hello_module_methods,
- }
- };
Here, the instance variable name must be Hal_module_info_sym,tag and must be Hardware_module_tag, which is specified by the Android Hardware Abstraction Layer specification.
Define the Hello_device_open function:
[CPP]View Plaincopy
- static int Hello_device_open (const struct hw_module_t* module, const char* name, struct HW_ device_t** device) {
- struct hello_device_t* Dev;dev = (struct hello_device_t*) malloc (sizeof (struct hello_device_t));
- if (!dev) {
- LOGE ("Hello stub:failed to Alloc space");
- Return-efault;
- }
- memset (Dev, 0, sizeof (struct hello_device_t));
- Dev->common.tag = Hardware_device_tag;
- dev->common.version = 0;
- Dev->common.module = (hw_module_t*) module;
- Dev->common.close = Hello_device_close;
- Dev->set_val = Hello_set_val;dev->get_val = Hello_get_val;
- if ((dev->fd = open (Device_name, o_rdwr)) = =-1) {
- LOGE ("Hello stub:failed to Open/dev/hello--%s.", Strerror (errno)); free (dev);
- Return-efault;
- }
- *device = & (Dev->common);
- Logi ("Hello Stub:open/dev/hello successfully.");
- return 0;
- }
Device_name is defined as "/dev/hello". Since the device files are created in the kernel driver through device_create, and the device files created by Device_create are read and written by default only by the root user, and Hello_device_open is generally called by the upper-level app, These apps typically do not have root privileges, which can cause the device file to fail to open:
Hello stub:failed to Open/dev/hello--Permission denied.The solution is similar to the Udev rules of Linux, open the Android source code project directory, into the System/core/rootdir directory, there is a file named Ueventd.rc, add a line inside:
/dev/hello 0666 root root
Define the three functions of Hello_device_close, Hello_set_val, and Hello_get_val:
[CPP]View Plaincopy
- static int hello_device_close (struct hw_device_t* device) {
- struct hello_device_t* hello_device = (struct hello_device_t*) device;
- if (hello_device) {
- Close (HELLO_DEVICE->FD);
- Free (hello_device);
- }
- return 0;
- }
- static int hello_set_val (struct hello_device_t* dev, int val) {
- Logi ("Hello Stub:set value%d to device.", Val);
- Write (DEV->FD, &val, sizeof (Val));
- return 0;
- }
- static int hello_get_val (struct hello_device_t* dev, int* val) {
- if (!val) {
- LOGE ("Hello stub:error val Pointer");
- Return-efault;
- }
- Read (DEV->FD, Val, sizeof (*val));
- Logi ("Hello stub:get value%d from device", *val);
- return 0;
- }
Four. Continue to create a new android.mk file in the Hello directory:
Local_path: = $ (call My-dir)
include $ (clear_vars)
local_module_tags: = optional
Local_prelink_module: = False
Local_module_path: = $ (target_out_shared_libraries)/HW
local_shared_libraries: = Liblog
local_src_files: = hello.c
local_module: = Hello.default
include $ (build_shared_library)Note that Local_module's definition rules, followed by default,hello.default, ensure that our modules can always be loaded into the hard-like abstraction layer. Five. Compiling:
[email protected]:~/android$ mmm Hardware/libhardware/modules/hello
After the compilation is successful, you can see the hello.default.so file in the OUT/TARGET/PRODUCT/GENERIC/SYSTEM/LIB/HW directory. Six. RePack Android system Image system.img:
[email protected]:~/android$ make Snod
After repackaging, SYSTEM.IMG contains our defined Hardware Abstraction Layer module HELLO.DEFAULT. While we have added a hardware Abstraction Layer module to our own hardware on the Android system, Java applications are not yet accessible to our hardware. We also have to write JNI methods and add API interfaces to the Android application frameworks layer to get the upper application access to our hardware. In the next article, we will also complete this system process, enabling us to access our own custom hardware in Java applications.
Lao Luo's Sina Weibo: Http://weibo.com/shengyangluo, welcome attention!
Add Hardware abstraction Layer (HAL) module to Android to access Linux kernel drivers on Ubuntu