[arm驱动]platform第一个程序led灯循环

简介:

2000元阿里云代金券免费领取,2核4G云服务器仅664元/3年,新老用户都有优惠,立即抢购>>>


阿里云采购季(云主机223元/3年)活动入口:请点击进入>>>,


阿里云学生服务器(9.5元/月)购买入口:请点击进入>>>,

《[arm驱动]Platform设备驱动》涉及内核驱动函数二个,内核结构体一个,分析了内核驱动函数二个;可参考的相关应用程序模板或内核驱动模板零个,可参考的相关应用程序或内核驱动一个


一、关键是device程序中resource结构体

结构体一)resource结构体

1
2
3
4
5
6
7
struct  resource {
         resource_size_t start;       //定义资源的起始地址
         resource_size_t end;        //定义资源的结束地址
         const  char  *name;                    //定义资源的名称
         unsigned  long  flags;            //定义资源的类型,例如MEM, IO ,IRQ, DMA类型
         struct  resource *parent, *sibling, *child;      //资源链表指针
};


函数一)driver程序中获取资源

1
struct  resource *platform_get_resource( struct  platform_device *dev, unsigned  int  type, unsigned  int  num)

参数:
dev: 资源所属的设备
type: 获取的资源类型  IORESOURCE_IO IORESOURCE_MEM IORESOURCE_IRQ IORESOURCE_DMA
num: 获取的资源数
例:platform_get_resource(pdev, IORESOURCE_IRQ, 0)获取第一个中断号

内核源码一)platform_get_resource内核源码


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
platform_get_resource( struct  platform_device *dev, unsigned  int  type,
               unsigned  int  num)
{
     int  i;
     for  (i = 0; i < dev->num_resources; i++) {
         struct  resource *r = &dev->resource[i];
         //从下面两个if中看出num = 0并不等同于要取resource[0],而是获取第一个flag为type的resource
         if  ((r->flags & (IORESOURCE_IO|IORESOURCE_MEM|
                  IORESOURCE_IRQ|IORESOURCE_DMA))
             == type)
             if  (num-- == 0)
                 return  r;
     }
     return  NULL;
}

函数二)driver中获取第num+1个中断资源

1
platform_get_irq( struct  platform_device * dev, unsigned  int  num)

内核源码二)platform_get_irq内核源码

1
2
3
4
5
6
int  platform_get_irq( struct  platform_device *dev, unsigned  int  num)
{
     struct  resource *r = platform_get_resource(dev, IORESOURCE_IRQ, num);
     //调用了platform_get_resource
     return  r ? r->start : -ENXIO;
}


实例一)实现一个s3c2440的platform led流水灯

   platform_led_dev.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*代码代换:platform_led_dev_, "platform_led"*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/platform_device.h>
#include <linux/fs.h>//文件系统相关的函数和头文件
#include <linux/device.h>
#include <linux/cdev.h> //cdev结构的头文件包含<linux/kdev_t.h>
static  struct  resource platform_led_dev_resource[] = {
     /*
       参考s3c2440芯片手册
       GPFCON 0x56000050//本驱动使用,注意unsigned long 为4字节(4*8 bit),相当与ff
       GPFDAT 0x56000054//本驱动使用
       GPFUP 0x56000058//本驱动不使用,上拉电阻在驱动中不使用到,
     */
     [0] = {
         .start = 0x56000050,
         .end   = 0x56000050 + 8 - 1,
         .flags = IORESOURCE_MEM,
     },
                                                                                                                                             
};
static  void  platform_led_dev_release( struct  device * dev){
     printk( "device say the device is release\n" );
return ;
}
static  struct  platform_device platform_led_dev_device = {   //添加设备结构体
     .name =  "platform_led" ,
     .id = -1,
     .num_resources    = ARRAY_SIZE(platform_led_dev_resource), //一定要加,因为platform_get_resource中要用到
     .resource = platform_led_dev_resource,
     .dev = {
     .release = platform_led_dev_release, //解决"Device 'platform_dev' does not have a release() function“问题
     }
};
static  int   __init platform_led_dev_init( void ){
     platform_device_register(&platform_led_dev_device);   //注册设备到内核
     return  0;
}
static  void  platform_led_dev_exit( void ){
      platform_device_unregister(&platform_led_dev_device);   //卸载设备
     printk(KERN_ALERT  "good bye\n" );
}
module_init(platform_led_dev_init);
module_exit(platform_led_dev_exit);
MODULE_LICENSE( "GPL" );

   platform_led_drv.c

   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/*
  *代码代换:platform_led_drv_, "platform_led"
  */
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <linux/platform_device.h>
     static  struct  class  *platform_led_drv_cls;
     static  volatile  unsigned  long  *gpiof_con; //注意unsigned long 为4字节(4*8 bit),相当与ff
     static  volatile  unsigned  long  *gpiof_dat;
     static  int  major;
                                                                                                                        
                                                                                                                        
     static  int  platform_led_drv_open( struct  inode *inode,  struct  file *file)
     {
         printk( "driver\tplatform_led open\n" );
         /* 配置为输出 */
         *gpiof_con &= ~((0x3 << (4*2)) | (0x3 << (5*2)) | (0x3 << (6*2)));
         *gpiof_con |= ((0x1 << (4*2)) | (0x1 << (5*2)) | (0x1 << (6*2) ));
         return  0; 
     }
                                                                                                                        
                                                                                                                        
     static  ssize_t platform_led_drv_write( struct  file *file,  const  char  __user *buf,  size_t  count, loff_t * ppos)
     {
     int  val;
     int  on;
     copy_from_user(&val, buf, count);
     on = val % 10;
     val = val / 10 + 4;
     if (on == 0){
     *gpiof_dat &= ~(1 << val);  
     } else {
     *gpiof_dat |= (1 << val);
     }
     return  0;
     }
                                                                                                                        
     static  struct  file_operations platform_led_drv_fops = {
         .owner  =   THIS_MODULE,     /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
         .open   =   platform_led_drv_open,   
         .write  =   platform_led_drv_write,  
     };
     static  int  platform_led_drv_probe( struct  platform_device *dev) //
     {
                                                                                                                            
         struct  resource     *res;
         //获得GPFCON,GPFDAT
         res = platform_get_resource(dev, IORESOURCE_MEM, 0);
         printk( "driver say the driver found the device\n" );
         gpiof_con = ( volatile  unsigned  long  *)ioremap(res->start, res->end - res->start + 1); //将0x56000050-0x56000057进行IO映射,gpiof_con等于ioremap的首地址,占4个字节
         gpiof_dat = gpiof_con + 1; //相当与0x56000050 + 4
         major = register_chrdev(0,  "platform_led" , &platform_led_drv_fops);   /*/proc/devices*/
         platform_led_drv_cls = class_create(THIS_MODULE,  "platform_led" ); /* /sys/class/platform_led */
         class_device_create(platform_led_drv_cls, NULL, MKDEV(major, 0), NULL,  "platform_led" );  /* /dev/platform_led */
         printk( "driver say the driver probe ok\n" );
         return  0;
     }
     static  int  platform_led_drv_remove( struct  platform_device *dev)
     {
         printk( "driver say the device is polled out\n" );
         /* 卸载字符设备驱动程序 */
     /* iounmap */
         class_device_destroy(platform_led_drv_cls, MKDEV(major, 0));
         class_destroy(platform_led_drv_cls);
         unregister_chrdev(major,  "platform_led" );
         iounmap(gpiof_con);
         return  0;
     }
//platform 总线相关文件挂载/sys/bus/platform/路径下
     static  struct  platform_driver platform_led_drv_driver = { //driver是驱动的意思,相关文件在/sys/bus/platform/drivers
         .probe = platform_led_drv_probe, //注册时要执行的函数
         . remove  = platform_led_drv_remove, //注销时会执行的函数
         .driver = {
             .owner = THIS_MODULE,
             .name =  "platform_led" , //会在"/sys/bus/platform/drivers"下创建platform_dev文件夹
         },
     };
     static  int  __init platform_led_drv_driver_init( void )
     {
             /*注册平台驱动*/
         return  platform_driver_register(&platform_led_drv_driver);
     }
     static  void  platform_led_drv_driver_exit( void )
     {
         platform_driver_unregister(&platform_led_drv_driver);
     }
     module_init(platform_led_drv_driver_init);
     module_exit(platform_led_drv_driver_exit);
     MODULE_LICENSE( "GPL" );

   上面两个c文件对于的Makefile

   

1
2
3
4
5
6
7
8
9
10
11
12
13
KERN_DIR =  /workspacearm/linux-2 .6.2.6
#platform_led_dev.ko
#platform_led_drv.ko
all:
     make  -C $(KERN_DIR) M=` pwd ` modules
     cp  platform_led_dev.ko  /opt/fsmini/
     cp  platform_led_drv.ko  /opt/fsmini/
clean:
     make  -C $(KERN_DIR) M=` pwd ` modules clean
     rm  -rf modules.order
     rm  -rf Module.symvers
obj-m   += platform_led_dev.o
obj-m   += platform_led_drv.o

   应用测试程序

   

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
//myled
int  main( int  argc,  char  **argv)
{
     int  fd;
     int  val = 1;
     fd = open( "/dev/platform_led" , O_RDWR);
     if  (fd < 0)
     {
         printf ( "can't open!\n" );
     }
     while (1){     
     if (val > 10){
     val = val - 10;
     write(fd, &val, 4);
     val = val + 10;
     } else {
     val = 21;
     write(fd, &val, 4);
     val = 1;
     }
     val -=1;      
     write(fd, &val, 4);
     sleep(1);
     val += 11;
     if (val > 22 )val = 1;
     }
     //write(fd, &val, 4);
     close(fd);
     return  0;
}

   

   应用程序对应的Makefile

   

1
2
3
4
5
6
7
8
9
objs := $(patsubst %c, %o, $(shell ls *.c))
myarmgcc := /workspacearm/armlinuxgcc2626/bin/arm-linux-gcc
myled.bin:$(objs)
     $(myarmgcc) -o $@ $^
     cp *.bin /opt/fsmini/
%.o:%.c
     $(myarmgcc) -c -o $@ $<
clean:
     rm -f  *.bin *.o


  总结:可以看出,将device可drive分开写,驱动(driver)可以达到平台(device)无关性,这也是总线的初衷



本文转自lilin9105 51CTO博客,原文链接:http://blog.51cto.com/7071976/1396916,如需转载请自行联系原作者

相关文章
|
8月前
|
缓存 C++
基于ARM-contexA9-蜂鸣器pwm驱动开发
基于ARM-contexA9-蜂鸣器pwm驱动开发
59 0
|
8月前
基于ARM-contexA9蜂鸣器驱动开发
基于ARM-contexA9蜂鸣器驱动开发
48 0
|
8月前
|
Linux C++ 流计算
基于ARM_contexA9 led驱动编程
基于ARM_contexA9 led驱动编程
39 0
|
C语言 芯片
ARM架构与编程--基于STM32F103 (1)LED原理图
当我们学习C语言的时候,我们会写个Hello程序。那当我们写ARM程序,也该有一个简单的程序引领我们入门,这个程序就是点亮LED。 我们怎样去点亮一个LED呢? 分为三步: 1.看原理图,确定控制LED的引脚; 2.看主芯片的芯片手册,确定如何设置控制这个引脚; 3.写程序;
119 0
|
Linux 编译器 Windows
6818开发板(arm平台)利用SecureCRT连接主机并运行程序(99乘法表)
6818开发板(arm平台)利用SecureCRT连接主机并运行程序(99乘法表)
348 0
|
芯片 内存技术
基于ARM Cortex-M0+内核的bootloader程序升级原理及代码解析
基于ARM Cortex-M0+内核的bootloader程序升级原理及代码解析
http://www.vxiaotou.com