博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
平台设备驱动之平台驱动
阅读量:4703 次
发布时间:2019-06-10

本文共 9863 字,大约阅读时间需要 32 分钟。

驱动层需要实现的结构体是struct platform_driver,它用来描述一个设备的驱动信息。

结构如下 (include\linux\platform_device.h)

1 struct platform_driver {2     int (*probe)(struct platform_device *);//探测3     int (*remove)(struct platform_device *);//移除4     void (*shutdown)(struct platform_device *);//关闭5     int (*suspend)(struct platform_device *, pm_message_t state);//挂起6     int (*resume)(struct platform_device *);//唤醒7     struct device_driver driver;8     struct platform_device_id *id_table;9 };

其中probe和remove是必需实现的,跟在设备层提到的注册和注销函数有关。其他函数根据需要,自行实现。

struct device_driver中的name成员很重要,必须要和设备层struct platform_device中的name成员相同,这样才能实现驱动层和设备层的绑定

结构如下   (include\linux\device.h)

struct device_driver {    const char        *name;    struct bus_type        *bus;    struct module        *owner;    const char        *mod_name;    /* used for built-in modules */    bool suppress_bind_attrs;    /* disables bind/unbind via sysfs */    int (*probe) (struct device *dev);    int (*remove) (struct device *dev);    void (*shutdown) (struct device *dev);    int (*suspend) (struct device *dev, pm_message_t state);    int (*resume) (struct device *dev);    const struct attribute_group **groups;    const struct dev_pm_ops *pm;    struct driver_private *p;};

 

平台驱动层核心API

int platform_driver_register(struct platform_driver *drv)                  ( drivers\base\platform.c)

void platform_driver_unregister(struct platform_driver *drv)            ( drivers\base\platform.c)

struct resource *platform_get_resource( struct platform_device *dev, unsigned int type, unsigned int num)     ( drivers\base\platform.c)

int platform_get_irq( struct platform_device *dev, unsigned int num)     ( drivers\base\platform.c)

 

 

平台驱动的实现步骤:

1.编写probe函数

2.编写remove函数

3.定义struct platform_drv结构,并填充这个结构(注,此结构是自己定义的,结构中包含的内容也是自己定义的;这个结构其实是将驱动函数中用到的变量,写到了一起,定义成此结构,方便了其它函数的调用) 

4.在模块的初始化函数中调用platform_driver_register(struct platform_driver *drv), 以注册

5.在模块卸载函数中调用platform_driver_unregister(struct platform_driver *drv), 以注销

 

实现代码如下:leds_platform_driver.c

1 #include 
2 #include
3 #include
4 5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 17 18 #define uint unsigned int 19 #define uchar unsigned char 20 21 struct led_info 22 { 23 unsigned int pin_bit; 24 }; 25 26 struct gpioreg 27 { 28 volatile unsigned long vr_gpbcon; 29 volatile unsigned long vr_gpbdat; 30 volatile unsigned long vr_gpbup; 31 }; 32 33 //自己定义的struct platform_drv结构 34 struct s3c2440_leds_drv{ 35 dev_t dev_nr; 36 struct cdev *cdev_led; 37 struct class *led_class; 38 struct resource *ledres; 39 struct led_info *led_pdata; 40 struct device *this_device; 41 struct gpioreg *vr_gpioreg; 42 struct file_operations leds_ops; 43 }; 44 45 #define DEVICE_NAME "s3c2440leds" 46 #define LED_ON 1 47 #define LED_OFF 0 48 49 static struct s3c2440_leds_drv s3c2440_leds_drv_data; 50 static int leds_open(struct inode *inode, struct file *file) 51 { 52 unsigned int tmp=0, up=0, dat=0; 53 unsigned int i=0; 54 uint pin_bit=s3c2440_leds_drv_data.led_pdata->pin_bit; 55 56 tmp=s3c2440_leds_drv_data.vr_gpioreg->vr_gpbcon; 57 up=s3c2440_leds_drv_data.vr_gpioreg->vr_gpbcon; 58 dat=s3c2440_leds_drv_data.vr_gpioreg->vr_gpbup; 59 printk("leds_open:1111\r\n"); 60 61 for(;i<16;i++) 62 { 63 if((1<
vr_gpbcon=tmp; 73 s3c2440_leds_drv_data.vr_gpioreg->vr_gpbup=up; 74 s3c2440_leds_drv_data.vr_gpioreg->vr_gpbdat=dat; 75 return 0; 76 } 77 78 static long leds_ioctl(struct file *filp, uint cmd, unsigned long arg) 79 { 80 uint tmp=0,i=0,j=0; 81 uint ledbit[16]={ 0}; 82 uint pin_bit=s3c2440_leds_drv_data.led_pdata->pin_bit; 83 84 for(i=0;i<16;i++) 85 { 86 if((1<
=j) 95 return -EINVAL; 96 mb();//防止编译器对下面的代码进行优化 97 tmp=s3c2440_leds_drv_data.vr_gpioreg->vr_gpbdat; 98 mb(); 99 100 printk("cmd:%d tmp:%d\r\n",cmd,tmp);101 102 switch(cmd)103 {104 case LED_ON:105 tmp &=~(1<
vr_gpbdat=tmp;107 return 0;108 109 case LED_OFF:110 tmp|=1<
vr_gpbdat=tmp;112 return 0;113 114 default:115 printk("ioctl() cmd is err\r\n");116 return -EINVAL;117 }118 }119 120 static int led_probe(struct platform_device *pdev)121 {122 int msize,val,err;123 // printk("%s is call\r\n",_FUNCTION_);124 printk("led_probe is call\r\n");125 126 //获取平台数据127 s3c2440_leds_drv_data.led_pdata=pdev->dev.platform_data;128 129 if(!s3c2440_leds_drv_data.led_pdata)130 {131 printk("get platform_data error\n");132 return -1;133 }134 135 s3c2440_leds_drv_data.ledres=platform_get_resource(pdev,IORESOURCE_MEM,0);136 if(!s3c2440_leds_drv_data.ledres)137 {138 printk("get resource error\n");139 return -1;140 }141 //142 msize=s3c2440_leds_drv_data.ledres->end-s3c2440_leds_drv_data.ledres->start+1;143 //向内核申请资源144 s3c2440_leds_drv_data.ledres=request_mem_region(145 s3c2440_leds_drv_data.ledres->start,msize,DEVICE_NAME);146 if(!s3c2440_leds_drv_data.ledres)147 {148 printk("request resource error\n");149 return -1;150 }151 152 s3c2440_leds_drv_data.vr_gpioreg=ioremap_nocache(153 s3c2440_leds_drv_data.ledres->start,msize);154 if(!s3c2440_leds_drv_data.vr_gpioreg)155 {156 printk("ioremap_nocache error\n");157 release_region( s3c2440_leds_drv_data.ledres->start,msize);158 return -1;159 }160 memset( s3c2440_leds_drv_data.vr_gpioreg,0,sizeof(struct gpioreg));161 //申请设备号162 val=alloc_chrdev_region(&s3c2440_leds_drv_data.dev_nr,0,1,DEVICE_NAME);163 if(val)164 {165 printk("request dev_nr error\n");166 iounmap(s3c2440_leds_drv_data.vr_gpioreg);167 release_region(s3c2440_leds_drv_data.ledres->start,msize);168 return -1;169 }170 //开辟cdev结构空间,并且初始化cdev结构171 s3c2440_leds_drv_data.cdev_led=cdev_alloc();172 cdev_init(s3c2440_leds_drv_data.cdev_led,&s3c2440_leds_drv_data.leds_ops);173 s3c2440_leds_drv_data.leds_ops.owner=THIS_MODULE,174 s3c2440_leds_drv_data.leds_ops.open=leds_open,175 s3c2440_leds_drv_data.leds_ops.unlocked_ioctl=leds_ioctl,176 //添加字符设备到内核177 val=cdev_add(s3c2440_leds_drv_data.cdev_led,178 s3c2440_leds_drv_data.dev_nr,1);179 if(val)180 {181 printk("cdev_add error\n");182 kfree(s3c2440_leds_drv_data.cdev_led);183 unregister_chrdev_region(s3c2440_leds_drv_data.dev_nr,1);184 iounmap(s3c2440_leds_drv_data.vr_gpioreg);185 release_region(s3c2440_leds_drv_data.ledres->start,msize);186 printk(KERN_INFO "Add device led error!\n");187 return -1;188 }189 190 s3c2440_leds_drv_data.led_class=class_create(THIS_MODULE,DEVICE_NAME);191 if(IS_ERR(s3c2440_leds_drv_data.led_class))192 {193 printk("Err:failed in creating class.\n");194 unregister_chrdev_region(s3c2440_leds_drv_data.dev_nr,1);195 cdev_del(s3c2440_leds_drv_data.cdev_led);196 kfree(s3c2440_leds_drv_data.cdev_led);197 unregister_chrdev_region(s3c2440_leds_drv_data.dev_nr,1);198 iounmap(s3c2440_leds_drv_data.vr_gpioreg);199 release_region(s3c2440_leds_drv_data.ledres->start,msize);200 return PTR_ERR(s3c2440_leds_drv_data.led_class);201 }202 203 s3c2440_leds_drv_data.this_device=device_create(s3c2440_leds_drv_data.led_class,NULL,s3c2440_leds_drv_data.dev_nr,NULL,"%s",DEVICE_NAME);204 if(IS_ERR(s3c2440_leds_drv_data.this_device)){205 printk("Err:failed in creating device_create.\n");206 class_destroy(s3c2440_leds_drv_data.led_class);207 unregister_chrdev_region(s3c2440_leds_drv_data.dev_nr,1);208 cdev_del(s3c2440_leds_drv_data.cdev_led);209 kfree(s3c2440_leds_drv_data.cdev_led);210 unregister_chrdev_region(s3c2440_leds_drv_data.dev_nr,1);211 iounmap(s3c2440_leds_drv_data.vr_gpioreg);212 release_region(s3c2440_leds_drv_data.ledres->start,msize);213 err=PTR_ERR(s3c2440_leds_drv_data.this_device);214 return err;215 }216 217 printk(KERN_INFO "LED Initilized I'm in!! ^_^\n");218 return 0;219 220 }221 222 static int led_remove(struct platform_device *pdev)223 {224 device_destroy(s3c2440_leds_drv_data.led_class,s3c2440_leds_drv_data.dev_nr);225 226 class_destroy(s3c2440_leds_drv_data.led_class);227 unregister_chrdev_region(s3c2440_leds_drv_data.dev_nr,1);228 cdev_del(s3c2440_leds_drv_data.cdev_led);229 kfree(s3c2440_leds_drv_data.cdev_led);230 unregister_chrdev_region(s3c2440_leds_drv_data.dev_nr,1);231 iounmap(s3c2440_leds_drv_data.vr_gpioreg);232 release_region(s3c2440_leds_drv_data.ledres->start,233 s3c2440_leds_drv_data.ledres->end-s3c2440_leds_drv_data.ledres->start+1);234 kfree(s3c2440_leds_drv_data.ledres);235 236 printk("led driver remove\n");237 return 0;238 }239 240 static struct platform_driver led_driver={241 .probe=led_probe,242 .remove=led_remove,243 .driver={244 .owner=THIS_MODULE,245 .name="s3c2440leds",246 },247 };248 249 static int __init leddrv_init(void)250 {251 platform_driver_register(&led_driver);252 return 0;253 }254 255 static void __init leddrv_exit(void)256 {257 platform_driver_unregister(&led_driver);258 }259 260 module_init(leddrv_init);261 module_exit(leddrv_exit);262 263 MODULE_LICENSE("GPL");

注:代码中红色标注部分是字符设备cdev驱动中函数,而定义的struct s3c2440_leds_drv结构中很多是cdev中用到的变量。

  代码中pin_bit[i]中的注释部分,结合led的控制寄存器,可以理解。

ps.结合上一节leds_platform_device.c中提到的platform_data来理解本代码中probe函数下的s3c2440_leds_drv_data.led_pdata = pdev->dev.platform_data, 这样就可以理解为什么struct platform_data可以赋值给struct led_pdata(不同的结构体  之间是不能赋值的)。

 

makefile文件

1 #Makefile 2 obj-m:=leds_platform_drivers.o leds_platform_device.o  3 # leds_platform_driver.o 4  5 KDIR:=/opt/FriendlyARM/mini2440/linux-2.6.32.2 6 PWD:=$(shell pwd) 7 modules: 8     $(MAKE) -C $(KDIR) M=$(PWD) modules 9 #    arm-linux-gcc leds_platform_drivers.c -o leds.o10     arm-linux-gcc leds_platform_test.c leds_platform_test11 #    cp leds_platform_device.ko  leds_platform_driver.ko   leds_platform_test /opt/FriendlyARM/12 13 modules_install:14     $(MAKE) -C $(KDIR) M=$(PWD)15     16 #    rm -rf *.o *.mod.o *mod.c *symvers. *.o. *.cmd modules.order *.bak.tmp_versions17 18 clean: 19     rm -rf *.ko *.o *.mod.o *.mod.c *symvers. *.o. *.cmd modules.order *.bak .tmp_versions

 

 

 

 

 

 

 

 

 

 

参考文献:《嵌入式Linux高级驱动教程》    电子工业出版社      深圳信盈达电子有限公司   陈志发  周中孝  李志超  编著

转载于:https://www.cnblogs.com/weiyublog/p/5321340.html

你可能感兴趣的文章
filter 过滤器(监听)
查看>>
node启动时, listen EADDRINUSE 报错;
查看>>
杭电3466————DP之01背包(对状态转移方程的更新理解)
查看>>
python--注释
查看>>
SQL case when else
查看>>
SYS_CONTEXT 详细用法
查看>>
Pycharm配置autopep8让Python代码更符合pep8规范
查看>>
我的第一篇博客
查看>>
【C++算法与数据结构学习笔记------单链表实现多项式】
查看>>
C#垃圾回收机制
查看>>
31、任务三十一——表单联动
查看>>
python之hasattr、getattr和setattr函数
查看>>
maven使用阿里镜像配置文件
查看>>
Copy code from eclipse to word, save syntax.
查看>>
arguments.callee的作用及替换方案
查看>>
P2709 小B的询问
查看>>
PHP echo 和 print 语句
查看>>
第一讲 一个简单的Qt程序分析
查看>>
Centos 6.5下的OPENJDK卸载和SUN的JDK安装、环境变量配置
查看>>
poj 1979 Red and Black(dfs)
查看>>