首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

嵌入式Linux设备驱动程序实例详解

嵌入式Linux设备驱动程序实例详解

嵌入式Linux设备驱动程序实例详解

0
推荐


       嵌入式系统是随着计算机技术、微处理器技术、电子技术、通信技术、集成电路技术的发展而发展起来的嵌入式系统已成为计算机技术和计算机应用领域的一个重要组成部分。一个嵌入式系统就是一个硬件和软件的集合体,它包括硬件和软件两部分。硬件包括嵌入式处理器/控制器/数字信号处理器(Digital Signal Processor,DSP)等、存储器及外设器件、输入/输出(I/O)端口、图形控制器等软件部分包括操作系统软件(嵌入式操作系统)和应用程序(应用软件)。
1. 详解设备驱动程序及相关模块
1.1头文件
#i nclude<linux/module.h>
module.h主要是阐述版本信息。例如:MOD-ULE_LICENSE(license)和ODULE_AUTHOR(name)等。
#i nclude<linux/kernel.h>
kernel.h主要用于prink()中带宏定义的打印输出。
例如:prink(KERN_ALERT,”Hello World!”)。如果prink()的消息没有指定loglevel,则使用默认的loglevel(DE-FAULT_MESSSAGE_LOGLEVEL)。
<0>(KERN_EMERG)emergency message(紧急消息):通常为crash的消息。
<1>(KERN_ALERT)alert message(注意消息):通常为一般的提示消息。
<2>(KERN_CRIT)critical condition message(危急消息):通常为严重的软硬件Failure(失败)消息。
<3>(KERN_ERR)error message(错误消息):通常是一般状况(例如找不到特定硬件)的错误消息。
<4>(KERN_WARNING)warning message(警告消息):即非错误的问题消息。
<5>(KERN_NOTICE)notice message(注意消息):一般需要特别说明的消息,许多与安全性有关的消息都一次loglevel打印。
<6>(KERN_INFO)informational message(信息消息):通常程序所取得的信息都以此loglevel打印。例如开机时驱动程序会将检测到的硬件信息一次loglevel打印。
<7>(KERN_DEBUG)debug message(调试信息):即程序里的调试消息。
#i nclude<linux/init.h>
init.h中主要包括module_init(IOdriver_init)和mod-ule_exit(IOdriver_exit)等。
#i nclude<linux/fs.h>
fs.h中主要包括inode和file结构体和file_opera-tions、register_chrdev和unregister_chrdev等。
#i nclude<asm/uaccess.h>
uaccess.h中主要包括__copy_from_user和__copy_to_user函数。
1.2版本信息
MODULE_LICENSE("GPL");
如果出现警告:warning:loading module-1.o will taint the kernel:no license则是因为Linux Kernel 2.4在开发不久后,便要求module必须加上版本声明,主要是因为随着Linux Kernel的开发日益庞大,有些驱动程序可能不再是以GPL(通用性公开许可证,General Public License)的版权声明。
MODULE_AUTHOR("heting<vt.the@gzu.edu.cn>");此宏用来说明module的作者。
MODULE_DEION("A Linux Kernel Driv-er!");
此宏用来简单说明module的用途。
MODULE_SUPPORT_DEVICE("GPIOdrv");此宏用来说明module所支持的devicefile。MOD-ULE_SUPPORT_DEVICE(“GPIOdrv”);表此module使用到/dev/testdevices文件。不过目前的Linux Kernel并未真正支持此宏,此宏目前暂时没有任何用途,单纯为预先设计的功能。
1.3主设备号定义
#define MAJOR_NUM 254//主设备号
主设备号标识设备对应的驱动程序。次设备号由内核使用,用于正确确定设备文件所指的设备。
1.4设备驱动接口
Struct file_operations GPIO_fops=
{
read:GPIO_read,write:GPIO_write,
下面简单描述一下字符设备驱动接口中关键file_operations结构,基于Linux-2.4.20的<linux/fs.h>
定义如下:
struct file_operations{struct module*owner;/*指向拥有本结构的module,用于内核维护模块引用技术*/
loff_t(*llseek)(struct file*,loff_t,int);
/*改变当前文件的读/写位置并返回新位置,错返回负数*/
ssize_t(*read)(struct file*,char*,size_t,loff_t);
/*用来从设备接收数据,返回的非负数表示成功取的字节数*/
ssize_t(*write)(struct file*,const char*,size_loff_t*);
/*用来往设备发数据,返回的非负数表示成功写的字节数*/
int(readdir))(struct inode*,struct file*,voidfilldir_t);
/*仅用于文件系统的目录读取,不用于设备驱动int(*select)(struct inode*,struct file*,int,seletable*);
/*用于查询设备是否可读、可写或处于特殊的状*/
int(*ioctl)(struct inode*,struct file*,unsigned inunsigned int);
/*用于给设备发送命令的接口函数。如驱动不供,则所有调用失败,返回ENOTTY*/
int(*mmap)(struct inode*,struct file*,struvm_area_struct*);
/*用于请求将设备内存映射到进程空间。如果驱不提供,则所有调用失败,返回ENODEV*/
int(*open)(struct inode*,struct file*);
/*打开设备,通常是对设备的第一个操作函数*/
开发研究与设计技术
void(*release)(struct inode*,struct file*);
/*关闭设备。只有当设备文件的所有备份都被释放时,才进行release调用,而不是每次调用close时都执行。*/
int(*fsync)(struct inode*,struct file*);
/*是系统调用fsync的背后支撑,用户可调用fsync来刷新缓存数据*/
};
1.5注册和注销模块
1.5.1设备注册模块

static int__init GPIO_init_module(void)
{
int ret=0;
ret=register_chrdv(MAJOR_NUM,“GPIOdrv”,&GPIO_fops);
/*注册设备驱动*/
if(ret)
{
printk(KERN_ALERT“GPIOdrv register failure!”);
}
else
{
printk(KERN_ALERT“GPIOdrv register success!”);
}
return ret;
}
1.5.2设备注销模块
static int__exit GPIOdrv_exit(void)
{
int ret=0;
ret=unregister_chrdv(MAJOR_NUM,“GPIOdrv”);
/*注销设备驱动*/
if(ret)
{
printk(KERN_ALERT“GPIOdrv unregister failure
!”);
}
else
{
printk(KERN_ALERT“GPIOdrv unregister success
!”);
}
return ret;
}
1.6基本入口点设备函数的具体实现
1.6.1设备读取模块

static ssize_t GPIIO_read(struct file*file,char*buf,
size_t len,loff_t*off)
{
if(__copy_to_user(buf,&GPIO_var,sizeof(int)))
{/*将GPIO_var中的数据读到buf缓存中,大小是int*/
return–EFAULT;
}
return sizeof(int);
}
1.6.2设备写入模块
static ssize_t GPIO_write(struct file*file,const char
*buf,size_t len,loff_t*off)
{
if(__copy_from_user(&GPIO_var,buf,sizeof(int)))
{/*将IOdriver_var中的数据写入buf缓存中,大小是int*/
return–EFAULT;
}
return sizeof(int);
}
1.7 module_init和module_exit宏
module_init(GPIOdrv_init);
module_exit(GPIOdrv_exit);
Linux Kernel 2.4开始提供module_init和mod-ule_exit宏,这两个宏(注意:不是函数)定义于<linux/init.h>头文件,利用这两个宏可以重新定义module的初
始化函数和清除函数。
结语:
Linux的驱动开发调试有两种方法,一种是直接编译到内核,再运行新的内核来测试;二是编译为模块的形式,单独加载运行调试。第一种效率较低,但在某些场合是唯一的方法。模块方式调试效率很高,可以使用insmod工具将编译的模块直接插入内核,如果发现故障,可以使用rmmod从内核中卸载模块,从而不需要重新启动内核,这使得驱动调试效率大大提高。

返回列表