linux驱动由浅入深系列:驱动程序的基本结构概览之二(详解驱动注册过程)
2017-03-06 12:10
633 查看
本系列导航:
linux驱动由浅入深系列:驱动程序的基本结构概览之一(第一个驱动程序)
linux驱动由浅入深系列:驱动程序的基本结构概览之二(详解驱动注册过程)
上一篇文章使用了misc_register函数注册字符设备,这篇文章使用基本的字符设备接口申请设备号、创建dev文件来展示一下细节部分:
测试结果:
/dev目录下出现hello_radia文件
cat hello_radia,出现如下打印信息:
echo "1" > hello_radia,出现如下打印信息,测量GPIO75,为高电平
说明这版演示版驱动程序基本能用,但是注意此版为仅为了展示字符驱动的基本注册过程,其中资源释放,函数返回值均未处理,不可用于实际项目中。
linux驱动由浅入深系列:驱动程序的基本结构概览之一(第一个驱动程序)
linux驱动由浅入深系列:驱动程序的基本结构概览之二(详解驱动注册过程)
上一篇文章使用了misc_register函数注册字符设备,这篇文章使用基本的字符设备接口申请设备号、创建dev文件来展示一下细节部分:
#include <linux/init.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/miscdevice.h> #include <linux/fs.h> #include <linux/input.h> #include <linux/workqueue.h> #include <linux/gpio.h> #include <linux/interrupt.h> #define DRIVER_NAME "hello" #define DEVICE_NAME "hello" #define GPIO_KEY 75 MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Radia"); static struct input_dev *input; static struct hello_platform_data *pdata; struct hello_platform_data {//设备结构体中的用户自定义结构体 定义 int gpio; struct work_struct hello_wq_work; }; static struct hello_platform_data hello_pdata = { //设备结构体中的用户自定义结构体 填入初始数据 .gpio = GPIO_KEY, }; static struct platform_device hello_device = {//设备结构体填入初始数据 .name = DRIVER_NAME, .id = -1, .dev = { .platform_data = &hello_pdata,//用户自定义结构体 加入到设备结构体中 } }; static int hello_open(struct inode *inode, struct file *file){ printk(KERN_EMERG "hello open\n"); return 0; } static int hello_release(struct inode *inode, struct file *file){ printk(KERN_EMERG "hello release\n"); return 0; } static ssize_t hello_read(struct file *file, char *buf, size_t count, loff_t *ppos) { printk(KERN_EMERG "hello read!\n"); memcpy(buf, "hi\n", 3); return 3; } static ssize_t hello_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { printk(KERN_EMERG "hello write!\n"); gpio_direction_output(pdata->gpio, simple_strtoul(buf, NULL, 0)); return 2; } static long hello_ioctl(struct file *file, unsigned int cmd, unsigned long arg){ printk("cmd is %d, arg is %d\n", cmd, arg); return 0; } static struct file_operations hello_fops = { .owner = THIS_MODULE, .open = hello_open, .read = hello_read, .write = hello_write, .release = hello_release, .unlocked_ioctl = hello_ioctl, }; static int hello_probe(struct platform_device *pdv)//在probe时,设备结构体被以参数的形式传递了进来,同时自定义的hello_platform_data也在其中了 { static struct class *hello_class; int hello_major; pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); pdata = pdv->dev.platform_data;//获取到hello_platform_data结构体指针 printk(KERN_EMERG "hello key probe\n"); gpio_request(pdata->gpio, "gpio_hello_out\n"); gpio_direction_output(pdata->gpio, 1); //注册一个设备类,使mdev可以在/dev/目录下建立设备节点 hello_class = class_create(THIS_MODULE, "hello"); //注册字符设备,这里定义DEVICE_MAJOR=0,让系统去分配,注册成功后将返回动态分配的主设备号 hello_major = register_chrdev(0,"hello",&hello_fops); //创建一个设备节点,取名为hello_radia //注意2.6内核较早版本的函数名是class_device_create,现该为device_create device_create(hello_class,NULL,MKDEV(hello_major,0),NULL,"hello_radia"); return 0; } static int hello_remove(struct platform_device *pdv) { struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdv); printk(KERN_EMERG "hello key remove\n"); input_unregister_device(input); return 0; } static void hello_shutdown(struct platform_device *pdv) { } static int hello_suspend(struct platform_device *pdv, pm_message_t pmt) { return 0; } static int hello_resume(struct platform_device *pdv) { return 0; } static struct platform_driver hello_driver = {//驱动结构体填入初始数据 .probe = hello_probe, .remove = hello_remove, .shutdown = hello_shutdown, .suspend = hello_suspend, .resume = hello_resume, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, } }; static int hello_init(void) { int driver_state; printk(KERN_EMERG "hello module has been mount!\n"); platform_device_register(&hello_device);//使用设备结构体中的数据将设备进行注册 printk(KERN_EMERG "platform_device_register end\n"); driver_state = platform_driver_register(&hello_driver);//使用驱动结构体中的数据将驱动进行注册 printk(KERN_EMERG "platform_driver_register driver_state is %d\n", driver_state); return 0; } static void hello_exit(void) { printk(KERN_EMERG "hello module has been remove!\n"); platform_driver_unregister(&hello_driver); } module_init(hello_init); module_exit(hello_exit);
测试结果:
/dev目录下出现hello_radia文件
cat hello_radia,出现如下打印信息:
hello read!
echo "1" > hello_radia,出现如下打印信息,测量GPIO75,为高电平
hello write!echo "0" > hello_radia,出现相同打印信息,测量GPIO75,为低电平
说明这版演示版驱动程序基本能用,但是注意此版为仅为了展示字符驱动的基本注册过程,其中资源释放,函数返回值均未处理,不可用于实际项目中。
相关文章推荐
- linux驱动由浅入深系列:驱动程序的基本结构概览之一(第一个驱动程序)
- linux下MMC/SD/SDIO驱动系列之二 ---- host注册过程(一)
- linux下MMC/SD/SDIO驱动系列之二 ---- host注册过程(一)
- linux驱动由浅入深系列:高通sensor架构实例分析之二(驱动代码结构)
- linux设备驱动程序注册过程详解
- linux设备驱动程序注册过程详解
- linux设备驱动程序注册过程详解
- linux设备驱动程序注册过程详解
- linux驱动由浅入深系列:输入子系统之二(编写一个gpio_key驱动)
- linux驱动由浅入深系列:显示子系统之二(基于android的分析)
- <学习笔记>Windows驱动技术开发详解__驱动程序的基本结构
- linux下MMC/SD/SDIO驱动系列之二 ---- host注册过程(一)
- linux驱动由浅入深系列:camera驱动之二(基于高通平台的V4L2结构及代码分析)
- linux驱动由浅入深系列:usb子系统之一(域、包、事务、传输的基本概念)
- linux-i2c驱动 之 i2c设备层的注册过程probe函数如何被调用分析
- ALSA声卡驱动中的DAPM详解之四:在驱动程序中初始化并注册widget和route
- linux 内核驱动--Platform Device和Platform_driver注册过程
- linux I2C 驱动之----i2c驱动的注册过程(i2c_register_driver->driver_register(&driver->driver)->driver_find)
- linux 驱动程序 设备模块 设备号 设备文件创建 设备注册 字符驱动设备分析
- linux 内核驱动--Platform Device和Platform_driver注册过程