Chinaunix首页 | 论坛 | 博客
  • 博客访问: 223870
  • 博文数量: 39
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 584
  • 用 户 组: 普通用户
  • 注册时间: 2015-04-18 20:24
个人简介

学习总结,分享快乐。 望指正错误, 共同提高!!!

文章分类

全部博文(39)

分类: 嵌入式

2015-06-08 13:01:39

0>目标:

           写一个模仿platform的例子, 通过学习此例更容易理解后面的platform平台

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

1>问题:

        通过上一篇设备模型1》初识:,知道了把驱动程序,分成bus,device和driver3大模块,device和driver通过bus的mach()函数匹配,并调设备对应driver的probe()。

×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

现在要实现在一个总线上,多个设备对应一套驱动,怎么办?例:要对3个U盘写数据。

难点:probe( )问题:任何1个设备与驱动匹配成功后,都会调驱动的probe(),这样都调同1个probe(),怎么区分多个设备呢?也许你在想,现在看看下面这种方法:

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

2>创建总线:


点击(此处)折叠或打开

  1. /*匹配规则*/
  2. static int mymatch(struct device *dev, struct device_driver *drv)
  3. {

  4.         struct mydev_t *mydev = container_of(dev, struct mydev_t, base_dev);
  5.         struct mydrv_t *mydrv = container_of(drv, struct mydrv_t, base_drv);

  6.         if(mydev->vender_id == mydrv->vender_id && mydev->product_id == mydrv->product_id) {
  7.                 return 1;
  8.         }else{
  9.                 return 0;
  10.         };

  11. }

点击(此处)折叠或打开

  1. /*实例化总线*/
  2. static struct bus_typemybus= {
  3.         .name = "plat_lsx",
  4.         .match = mymatch,

  5. };


点击(此处)折叠或打开

  1. /*注册&&移除总线*/

  2. static int __init my_init(void)
  3. {
  4.         return bus_register(&mybus);
  5. }

  6. static void __exit my_exit(void)
  7. {
  8.         bus_unregister(&mybus);
  9. }

  10. module_init(my_init);
  11. module_exit(my_exit);
  12. MODULE_LICENSE("GPL");

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

3>设备:

            1》封装自己的1套设备框架:

点击(此处)折叠或打开

  1. extern struct bus_typemybus;

  2. //外部声明总线
  3. /*抽象自己的设备类型*/
  4. struct mydev_t
  5. {
  6.         int irqno;
  7.         void *conf;
  8.         void *data;

  9.         unsigned int vender_id;
  10.         unsigned int product_id;
  11.         struct device base_dev;       //嵌入标准的设备结构体,多思考会这个。

  12. };

  13. /*必须指定release成员*/
  14. static void myrelease(struct device *dev)
  15. {
  16.             struct mydev_t *mydev = container_of(dev, struct mydev_t, base_dev);
  17.             printk("ID: %#x device is released\n", mydev->product_id);
  18. }



点击(此处)折叠或打开

  1. /*注册设备*/

  2. int mydev_register(struct mydev_t *mydev)
  3. {
  4.          mydev->base_dev.bus = &mybus; //挂载总线
  5.          mydev->base_dev.release = myrelease;
  6.          return device_register(&mydev->base_dev);       //借用标准设备注册函数
  7. }
  8. EXPORT_SYMBOL_GPL(mydev_register);

  9. /*移除设备*/
  10. void mydev_unregister(struct mydev_t *mydev)
  11. {
  12.         device_unregister(&mydev->base_dev);         //借用标准设备移除函数
  13. }
  14. EXPORT_SYMBOL_GPL(mydev_unregister);

………………………………………………………………………………………………

    2》注册实际设备:

点击(此处)折叠或打开

  1. /*实例化设备*/
  2. struct mydev_t mydev = {
  3.         .irqno = 1111,
  4.         .conf = (void *)0x2222,
  5.         .data = (void *)0x3333,
  6.         .vender_id = 0x1234,
  7.         .product_id = 0x5678,
  8.         .base_dev = {
  9.         .init_name = "mydev1",
  10. },
  11. };


  12. static int __init test_init(void)
  13. {
  14.         return mydev_register(&mydev);       //注册设备
  15. }

  16. static void __exit test_exit(void)
  17. {
  18.         mydev_unregister(&mydev);    //移出设备
  19. }

  20. module_init(test_init);
  21. module_exit(test_exit);
  22. MODULE_LICENSE("GPL");

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

4>驱动(重点)

1》封装自己的驱动类型:


点击(此处)折叠或打开

  1. extern struct bus_typemybus//外部声明总线

  2. struct mydrv_t {
  3.         char *drv_name;
  4.         int (*probe)(struct mydev_t *mydev);     //自己的probe
  5.         int (*remove)(struct mydev_t *mydev);     //自己的remove
  6.         unsigned int vender_id;
  7.         unsigned int product_id;
  8.         struct device_driver base_drv;    //将标准设备驱动结构体嵌入,多思考会。
  9. };

/*

*struct device {

*struct device_driver*driver;

*//标准设备结构体中有指向对应驱动的结构体指针,内核维护.

*}

*/

点击(此处)折叠或打开

  1. /*封装自己的一套驱动函数*/
  2. static     int myprobe(structdevice*dev)
  3. {
  4.         struct mydev_t *mydev = container_of(dev, struct mydev_t, base_dev);
  5.         struct mydrv_t *mydrv = container_of(dev->driver, struct mydrv_t, base_drv);

  6.         return mydrv->probe(mydev);     //调我们的probe

  7. }

  8. static int myremove(struct device *dev)
  9. {

  10.         struct mydev_t *mydev = container_of(dev, struct mydev_t, base_dev);
  11.         struct mydrv_t *mydrv = container_of(dev->driver, struct mydrv_t, base_drv);

  12.         return mydrv->remove(mydev);
  13. }


  14. int    mydrv_register(struct mydrv_t *mydrv)
  15. {

  16.         mydrv->base_drv.name = mydrv->drv_name;
  17.         mydrv->base_drv.bus = &mybus;
  18.         mydrv->base_drv.probe = myprobe;
  19.         mydrv->base_drv.remove = myremove;

  20.         return driver_register(&mydrv->base_drv);


  21. }


  22. EXPORT_SYMBOL_GPL(mydrv_register);

  23. void mydrv_unregister(struct mydrv_t *mydrv)
  24. {
  25.         driver_unregister(&mydrv->base_drv);
  26. }

  27. EXPORT_SYMBOL_GPL(mydrv_unregister);


^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


2》驱动注册:

点击(此处)折叠或打开

  1. /*实例化驱动注册*/
  2. static int lsx_probe(struct mydev_t *mydev)      //最终的probe
  3. {
  4.         printk("device's driver probe\n");
  5.         printk("device info:\n");
  6.         printk("vender_id = %#x\n", mydev->vender_id);
  7.         printk("product_id = %#x\n", mydev->product_id);
  8.         printk("irqno = %d\n", mydev->irqno);
  9.         printk("conf = %#x\n", (unsigned int)mydev->conf);
  10.         printk("data = %#x\n", (unsigned int)mydev->data);

  11.         return 0;
  12. }

  13. static int lsx_remove(struct mydev_t *mydev)
  14. {
  15.         printk("device's driver remove\n");
  16.         printk("device info:\n");
  17.         printk("vender_id = %#x\n", mydev->vender_id);
  18.         printk("product_id = %#x\n", mydev->product_id);

  19. return 0;

  20. }


  21. static structmydrv_tmydrv= {
  22.         .drv_name = "mydrv1",
  23.         .probe = lsx_probe,
  24.         .remove = lsx_remove,
  25.         .vender_id = 0x00001234,
  26.         .product_id = 0x00005678,

  27. };


  28. static int __init test_init(void)
  29. {
  30.         return mydrv_register(&mydrv);
  31. }

  32. static void __exit test_exit(void)
  33. {
  34.         mydrv_unregister(&mydrv);
  35. }

  36. module_init(test_init);
  37. module_exit(test_exit);
  38. MODULE_LICENSE("GPL");

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


总结:

重点是驱动,封装自己的驱动类型,将标准的驱动结构体嵌入,有自己的probe成员,当驱动与设备匹配成功,会调标准驱动的base_drv.probe,就是myprobe(),并将标准设备结构体指针传过去,然后,我们可以得到我们封装设备结构体和设备驱动,然后调,我们设备驱动的lsx_probe()。

这样不管再多的同类设备,都是在同一套驱动下,仅仅是都有各自的probe()。

Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

思考:

从以上看出抽象的设备类型,是固定的,怎么能抽象出可以包罗万象的设备类型?


阅读(2228) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~