HAL(1) -- 编写android内核驱动
2013-08-27 10:02
204 查看
一. 进入到kernel/drivers目录,新建zhx_print目录:
$ cd ics/kernel/drivers
$ mkdir zhx_print
二. 在zhx_print目录中增加zhx_print.h文件:
#ifndef _PRINT_H_
#define _PRINT_H_
#include <linux/cdev.h>
#define PRINT_NAME "zhx_print"
struct print_reg_dev
{
struct cdev print_cdev;
int val;
};
#endif
这个头文件定义了一些字符串常量宏,在后面我们要用到!。此外,还定义了一个字符设备结构体print_dev,这个就是我们虚拟的硬件设备了,val成员变量就代表设备里面的寄存器,它的类型为int。
三.在zhx_print目录中增加print.c文件
这是驱动程序的实现部分。驱动程序的功能主要是向上层提供访问设备的寄存器的值,包括读和写。
这里,为了让程序看起来简单明了,我们只实现普遍的字符串驱动模式。
首先是包含必要的头文件和定义三种访问设备的方法:
#[b]include<linux/module.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/fs.h> #include <asm/uaccess.h> #include <linux/device.h> #include <linux/types.h> #include <linux/proc_fs.h> #include <linux/errno.h> #include "print.h" /*device major and minor*/ static int major_number = 0; static int minor_number = 0; static struct print_reg_dev *print_dev= NULL; static struct class*print_class= NULL; /*function*/ static int print_open(struct inode*inodep,struct file*filep); static int print_close(struct inode*inodep,struct file*filep); static ssize_t print_read([b]struct file*filep,char __user*buf,size_t count,loff_t *ppos); static ssize_t print_write(struct file*filep,constchar __user *buf,size_t count,loff_t *ppos)[/b]
四:实现各个函数的功能
主要有 print_open,print_close ,print_read,print_write等
/*打开函数*/
static
int print_open(struct inode*inodep,struct file*filep)
{
struct print_reg_dev
*dev = NULL;
dev = container_of(inodep->i_cdev,struct print_reg_dev,print_cdev);
if(dev
== NULL)
{
printk("print_open is error.\n");
return
-1;
}
filep->private_data= (void*)dev;
return
0;
}
/*关闭*/
static
int print_close(struct inode*inodep,struct file*filep)
{
return
0;
}
/*读取*/
static ssize_t print_read(struct file*filep,char __user*buff,
size_t count,loff_t *ppos)
{
/*定义自己定义的结构体函数*/
struct print_reg_dev
*dev = (struct print_reg_dev*)filep->private_data;
/*返回值*/
int ret
= 0;
printk(KERN_INFO"print_read : you read value\n");
if(count
!= sizeof(dev->val))
{
printk("print_read : sorry error\n");
return
0;
}
if(copy_to_user(buff,&(dev->val),sizeof(dev->val)))
{
ret = -EFAULT;
}
else
{
ret = sizeof(dev->val);
}
return ret;
}
/*写入*/
static ssize_t print_write(struct file*filep,constchar
__user *buf,
size_t count,loff_t *ppos)
{
struct print_reg_dev
*dev = filep->private_data;
int ret
= 0;
printk(KERN_INFO"print_write:yout write value\n");
if(count
!= sizeof(dev->val))
{
printk("print_write : sorry error\n");
return
0;
}
if(copy_from_user((void*)&dev->val,(void*)buf,sizeof(dev->val)))
{
ret = -EFAULT;
}
else
{
ret = sizeof(dev->val);
}
return ret;
}
五:定义字符驱动函数结构体
staticstruct file_operations print_fops=
{
.owner = THIS_MODULE,
.open = print_open,
.release = print_close,
.read = print_read,
.write = print_write,
}
六:实现初始化init函数
staticint __init print_init(void)
{
int err
= 0;
dev_t devno =
0;
printk(KERN_ALERT"Initializing print device\n");
//1.动态分配主从设备号,并且注册驱动
err = alloc_chrdev_region(&devno,0,1,"zhx_print");
if(err
< 0)
{
printk(KERN_ALERT"Failed to alloc char dev region.\n");
return err;
}
printk(KERN_INFO"print_init : alloc_chrdev_region sucessfully\n");
//2.分配结构体内存空间
print_dev = kmalloc(sizeof(struct print_reg_dev),GFP_KERNEL);
if(print_dev
== NULL)
{
printk(KERN_ALERT"Failed to kmalloc print_dev");
err = -ENOMEM;
}
major_number = MAJOR(devno);
minor_number = MINOR(devno);
printk(KERN_INFO"print_init : kmalloc print_dev sucessfully\n");
//3.初始化和注册cdev
memset(print_dev,0,sizeof(struct print_reg_dev));//结构体初始化
cdev_init(&(print_dev->print_cdev),&print_fops);//cdev初始化
print_dev->print_cdev.owner= THIS_MODULE;
print_dev->print_cdev.ops=&print_fops;
err = cdev_add(&print_dev->print_cdev,devno,1);//注册cdev
if(err)
return err;
print_dev->val=0;
printk(KERN_INFO"print_init : cdev_init -- cdev_add sucessfully\n");
//4.创建设备节点,就是在/dev/目录下创建zhx_print
print_class = class_create(THIS_MODULE,"zhx_print");
if(IS_ERR(print_class))
{
err = PTR_ERR(print_class);
printk(KERN_ALERT"Failed to create print device class.\n");
cdev_del(&(print_dev->print_cdev));
unregister_chrdev_region(devno,1);
kfree(print_dev);
return err;
}
device_create(print_class,NULL,devno,"%s","zhx_print");//创建zhx_print
printk(KERN_INFO" init sucessfully!!!!!\n");
return
0;
}
七:实现卸载函数
staticvoid __exit print_exit(void)
{
//1.卸载设备节点
device_destroy(print_class,MKDEV(major_number,minor_number));
//2.卸载cdev
if(print_dev)
{
cdev_del(&(print_dev->print_cdev));
kfree(print_dev);
}
//3.卸载
unregister_chrdev_region(MKDEV(major_number,minor_number),1);
}
八:添加模块协议和指定模块初始化和卸载函数
MODULE_LICENSE("GPL");
module_init(print_init);
module_exit(print_exit);
九:在zhx_print目录下添加Kconfig文件,文件内容:
config ZHX_PRINT
tristate "zhx write driver"
default n
help
this is the driver
十:在zhx_print目录下添加Makefile文件,文件内容:
obj-$(CONFIG_ZHX_PRINT)+= print.o
十一:在ics/kernel/drivers目录上的Kconfig 中添加粗体红色语句:
...
source "drivers/i-tv/Kconfig"
source "drivers/gps/Kconfig"
source "drivers/zhx_print/Kconfig"
endmenu
十二:在ics/kernel/drivers/目录下的Makefile中添加以下语句:
obj-$(CONFIG_ZHX_PRINT)+= zhx_print/
十三:在ics/kernel/目录下,敲入以下命令:
ics/kernle$ make menuconfig
到这里会弹出内核配置菜单,这里配置如下:
Device Drivers --->
[*]zhx write driver
然后重新编译内核!
ics/kernle$ make-j4
到这里,zhx_print的驱动就添加进入内核里面了!!!
十四:处理硬件设备访问权限问题
在硬件抽象层中,我们调用open函数来打开对应内核设备时:
if((dev->fd= open(DEVICE_NAME,O_RDWR))==
-1)
{
LOGE("Failed to open device file /dev/zhx_print");
free(dev);
return
-EFAULT;
}
如果没有修改设备节点/dev/zhx_print权限,那么,就会提示:
Failed to open device file
/dev/zhx_print
这表明当前用户没有权限打开设备文件/dev/zhx_print,解决方法如下:
在板子的命令行中 执行以下命令:
board@Ubuntu:$ chmod 777 /dev/zhx_print
然后就可以操作啦!!!
相关文章推荐
- android hal 学习——编写android内核驱动
- andriod驱动之旅-在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口(6)
- Android内核驱动程序的编写和编译过程
- android驱动之旅-在Ubuntu上为Android系统编写Linux内核驱动程序(3)
- Android 驱动之旅: 第一章 在Android 内核源代码工程中编写硬件驱动程序
- 在Ubuntu上为Android系统编写Linux内核驱动程序
- Android驱动程序开发实例精讲-0_Android系统HAL驱动开发经典案例详解(基于Android4.0)
- Android平台驱动编写实例
- TQ210搭载Android4.0.3系统构建之LED从驱动到HAL到JNI到应用程序(HAL篇)
- TQ210搭载Android4.0.3系统构建之LED从驱动到HAL到JNI到应用程序(应用程序篇)
- ANDROID入门3:在Ubuntu上为Android访问Linux内核驱动程序编写硬件抽象层(HAL)模块
- 【从零开始,从内核驱动驱动到用户空间调用】编写第一个linux驱动,通过端口访问I/O寄存器。
- 在Ubuntu上为Android系统编写Linux内核驱动程序
- 往android的内核添加驱动(其实就是添加linux内核驱动)
- TQ210搭载Android4.0.3系统构建之BEEP从驱动到HAL到JNI到应用程序(JNI篇)
- ANDROID内核和驱动篇-ANDROID内核介绍(转)
- 为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口
- 在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口
- TQ210搭载Android4.0.3系统构建之LED从驱动到HAL到JNI到应用程序(驱动篇)
- Android内核驱动开发中的Kconfig文件结构分析(图文)