4454|0

1234

帖子

4

TA的资源

纯净的硅(高级)

楼主
 

【记录】ARM-linux开发之platfrom [复制链接]

本帖最后由 ywlzh 于 2016-8-7 00:58 编辑

  还是为了控制LED灯,只不过换了种方式,采用platfrom,叫它设备模型也好,还是虚拟总线也罢,就是将硬件与软件分层处理,或者分离处理,分成了设备与驱动,设备指硬件部分,也就是硬件资源,驱动就是结合硬件资源做出相应的事,这个看驱动程序怎么写了,反正这样下来硬件资源与驱动平台就分开处理,一切都是为了便于管理。  在LED控制里面,实现了简单的字符设备驱动程序控制,write操作就好了,要想用在platfrom里面,就必须把GPIO作为硬件资源,写在设备程序里面就行,而驱动程序就只需要获取到这个资源,对这个资源进行操作就行了。
  先写驱动程序吧

     1)入口函数只需要向平台注册就行,注册成功就会与设备匹配(出口函数与之对应)
     
  1. static int led_drv_init(void)
  2. {
  3.         platform_driver_register(&led_drv);
  4.         return 0;
  5. }

  6. static void led_drv_exit(void)
  7. {
  8.         platform_driver_unregister(&led_drv);
  9. }
复制代码

    2)注册都是带有结构体的,所以还得提前往结构体填充点东西
  1. struct platform_driver led_drv = {
  2.         .probe                = led_probe,
  3.         .remove                = led_remove,
  4.         .driver                = {
  5.                 .name        = "my_led",    /*这个名字需要dev那边能匹配的上*/
  6.         }
  7. };
复制代码
             3)看来这个结构体还需要两个函数一个led_probe,一个led_remove,这两个函数是需要自己添加的,什么时候调用,当设备与驱动匹配上了就会调用led_probe,当设备卸载了就会调用led_remove函数。这两个函数是相对的,就像字符设备驱动的open与release或者原来普通字符设备驱动程序的入口函数与出口函数,总之,就是相对的。
     那怎么写呢?当程序能进led_probe函数,就证明设备与驱动都匹配上了,那这个函数就可以获取设备上的资源,并对资源初始化(不建议做,交给后面的字符设备驱动框架里open函数,意思就是应用层不打开就不初始化),最后应用层想要访问这个设备,就需要一个设备驱动程序,这里用的混杂驱动程序。

  1. static int led_probe(struct platform_device *pdev)
  2. {
  3.         struct resource                *res;

  4.         /* 获取硬件上的资源 */
  5.         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  6.         pin = res->start;

  7.         /* 注册混杂驱动程序 */

  8.         printk("led_probe, found led\n");
  9.     misc_register(&led_miscdev);
  10.         return 0;
  11. }

  12. static int led_remove(struct platform_device *pdev)
  13. {
  14.         /* 卸载混杂驱动程序 */
  15.         printk("led_remove, remove led\n");
  16.         misc_deregister(&led_miscdev);
  17.         return 0;
  18. }
复制代码

           4)接下来就是混杂驱动程序的框架了,说白了就是字符设备驱动程序的框架(这里只做了open,write,release操作)

  1. static int led_open(struct inode *inode, struct file *file)
  2. {
  3.         /* 配置为输出 */
  4.         printk("led open OK !\n");
  5.         gpio_request(pin, "led");
  6.         return 0;        
  7. }

  8. static int  led_release(struct inode *inode, struct file *filp)
  9. {
  10.         gpio_free(pin);
  11.         return 0;
  12. }
  13. static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
  14. {
  15.         int val;

  16.         //printk("first_drv_write\n");

  17.         copy_from_user(&val, buf, count);
  18.         
  19.         gpio_direction_output(pin, val);   /*对GPIO口直接输出*/
  20.         
  21.         return 0;
  22. }


  23. static struct file_operations led_fops = {
  24.     .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
  25.     .open   =   led_open,
  26.     .release =          led_release,
  27.         .write        =        led_write,           
  28. };
  29. static struct miscdevice led_miscdev = {
  30.         .minor  = MISC_DYNAMIC_MINOR,
  31.         .name        = DEVICE_NAME,
  32.         .fops        = &led_fops,
  33. };        
复制代码
           到此驱动程序就写完了,当这个驱动程序匹配上了设备的时候,就会执行.probe函数,这个函数获取设备的资源,然后注册混杂设备驱动这一步主要是为了便于应用层好与驱动层交互,当应用层open了,那就初初始化硬件,write 1 就使硬件输出高(灯亮),write 0 就使硬件输出低(灯灭)  整个程序使用pin这个变量来作为硬件资源,也就是GPIO口。
   该写设备程序,额外写一个.c文件
   
  1. static struct resource led_resource[] = {
  2.     [0] = {
  3.         .start = MXS_PIN_TO_GPIO(PINID_LCD_D23),
  4.         .end   = MXS_PIN_TO_GPIO(PINID_LCD_D23),
  5.         .flags = IORESOURCE_MEM,
  6.     }

  7. };

  8. static void led_release(struct device * dev)
  9. {
  10.   return 0;      /*不用做任何事情*/
  11. }

  12. static struct platform_device led_dev = {
  13.     .name     = "my_led",      /*这个name要与对应的驱动平台必须一致*/
  14.     .id       = -1,
  15.     .num_resources    = ARRAY_SIZE(led_resource),
  16.     .resource     = led_resource,
  17.     .dev = {
  18.             .release = led_release,
  19.         },
  20. };

  21. static int led_dev_init(void)
  22. {
  23.         platform_device_register(&led_dev);
  24.         return 0;
  25. }

  26. static void led_dev_exit(void)
  27. {
  28.         platform_device_unregister(&led_dev);
  29. }
复制代码
    这个设备程序,整个不到40行,就只做了一个事,提交自己的硬件资源,看自己板子上对应的LED灯是那个引脚,写进resource结构体里面就行,IORESOURCE_MEM是指内存资源,GPIO口还有中断,这是只是为了控制led,所以就不需要用上。因为led就用了一个,所以这里的start与end也就相同了,要是把end写成0,能加载进内核,却不能卸载了,而且还出现这样的情况


这样,整个platfrom框架算是搭建好了,那就需要测试了,写一个测试文件,原先用的QT写的,这次就用.c写算了, 加入参数 on|off,对应的灯亮|灯灭。

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5.    
  6. /* test on
  7. * test off
  8. */
  9. int main(int argc, char **argv)
  10. {
  11.     int fd;
  12.     int val = 1;
  13.     if (fd < 0)
  14.     {
  15.         printf("can't open!\n");
  16.         return 0;
  17.     }
  18.     if (argc != 2)
  19.     {
  20.         printf("Usage :\n");
  21.         printf("%s <on|off>\n", argv[0]);
  22.         return 0;
  23.     }
  24.     fd = open("/dev/my_led", O_RDWR);
  25.     if (strcmp(argv[1], "on") == 0)
  26.     {
  27.         val  = 0;
  28.     }
  29.     else
  30.     {
  31.         val = 1;
  32.     }
  33.    
  34.     write(fd, &val, 4);
  35.     return 0;
  36. }

复制代码
测试记录输入参数 on 就会看见灯亮(右边)

       输入参数off 就会看见灯灭(下面,拍照的时候没有注意)


  最后,将文件保存起来,免得到时候不好找
pla_led.zip (2.82 KB, 下载次数: 10)





此帖出自ARM技术论坛

赞赏

1

查看全部赞赏

点赞 关注
个人签名天地庄周马;江湖范蠡船。
个性签名还是放QQ号吧,2060347305,添加说明EEworld好友
 

回复
举报
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表