Chinaunix首页 | 论坛 | 博客
  • 博客访问: 494330
  • 博文数量: 223
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2145
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-01 10:23
个人简介

该坚持的时候坚持,该妥协的时候妥协,该放弃的时候放弃

文章分类

全部博文(223)

文章存档

2017年(56)

2016年(118)

2015年(3)

2014年(46)

我的朋友

分类: 嵌入式

2016-11-11 23:15:29

一、总线模型
随着技术的不断进步,系统的拓扑结构也越来越复杂,对热插拔,跨平台移植性的要求也越来越高,2.4内核已经难以满足这些需求。为适应这种形势的需要,Linux 2.6内核开始提供了全新的设备模型

2.1 描述结构
在 Linux 内核中, 总线由 bus_type 结构表示,
定义在
struct bus_type {
const char *name; /*总线名称*/
int (*match) (struct device *dev, struct
device_driver *drv); /*驱动与设备的匹配函数*/
………
}

int (*match)(struct device * dev, struct device_driver * drv);
当一个新设备或者新驱动被添加到这个总线时,该函数被调用。用于判断指定的驱动程序是否能处理指定的设备。若可以,则返回非零。

2.2 总线注册与注销
总线的注册使用如下函数
bus_register(struct bus_type *bus);
若成功,新的总线将被添加进系统,并可在/sys/bus 下看到相应的目录。
总线的注销使用:
void bus_unregister(struct bus_type *bus);

3.1 描述结构
在 Linux内核中, 驱动由 device_driver结构表示。
struct device_driver {
{
const char *name; /*驱动名称*/
struct bus_type *bus; /*驱动程序所在的总线*/
int (*probe) (struct device *dev);
………
}

3.2 驱动注册与注销
 驱动的注册使用如下函数

int driver_register(struct device_driver *drv);
 驱动的注销使用:
void driver_unregister(struct device_driver *drv);

4.1 描述结构
在 Linux内核中, 设备由struct device结构表示。
struct device {
{
const char *init_name; /*设备的名字*/
struct bus_type *bus; /*设备所在的总线*/
………
}

4.2 驱动注册与注销
 设备的注册使用如下函数
int device_register(struct device *dev);
 设备的注销使用:
void device_unregister(struct device *dev);

5.编写代码
bus.c
  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/kernel.h>
  4. #include <linux/device.h>

  5. MODULE_LICENSE("GPL");

  6. int my_match(struct device *dev, struct device_driver *drv)
  7. {
  8.     return !strncmp(dev->kobj.name, drv->name, strlen(drv->name));
  9. }

  10. struct bus_type my_bus_type = {
  11.     .name = "my_bus",
  12.     .match = my_match,
  13. };
  14. EXPORT_SYMBOL(my_bus_type);

  15. int my_bus_init()
  16. {
  17.     int ret;
  18.     ret = bus_register(&my_bus_type);

  19.     return ret;
  20. }

  21. void my_bus_exit()
  22. {
  23.     bus_unregister(&my_bus_type);

  24. }

  25. module_init(my_bus_init);
  26. module_exit(my_bus_exit);
device.c:
  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/kernel.h>
  4. #include <linux/device.h>

  5. MODULE_LICENSE("GPL");

  6. extern struct bus_type my_bus_type;

  7. struct device my_device = {
  8.     .init_name = "my_dev",
  9.     .bus = &my_bus_type,
  10. };

  11. int my_device_init()
  12. {
  13.     int ret;
  14.     ret = device_register(&my_device);
  15.     return ret;
  16. }

  17. void my_device_exit()
  18. {
  19.     device_unregister(&my_device);
  20. }

  21. module_init(my_device_init);
  22. module_exit(my_device_exit);
device.c:
  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/device.h>
  4. #include <linux/kernel.h>

  5. MODULE_LICENSE("GPL");

  6. extern struct bus_type my_bus_type;

  7. int my_probe(struct device *dev)
  8. {
  9.     printk("driver found the device it can handle!\n");
  10.     return 0;
  11. }

  12. struct device_driver my_driver = {
  13.     .name = "my_dev",
  14.     .bus = &my_bus_type,
  15.     .probe = my_probe,
  16. };

  17. int my_driver_init()
  18. {
  19.     int ret;
  20.     ret = driver_register(&my_driver);
  21.     return ret;
  22. }

  23. void my_driver_exit()
  24. {
  25.     driver_unregister(&my_driver);
  26. }

  27. module_init(my_driver_init);
  28. module_exit(my_driver_exit)

1.平台总线概述
平台总线(Platform bus)是linux2.6内核加入的一种虚拟总线,其优势在于采用了总线的模型对设备与驱动进行了管理,这样提高了程序的可移植性。
通过平台总线机制开发设备驱动的流程如图:


2.平台设备
平台设备使用struct platform_device来描述:
struct platform_device {
const char *name; /*设备名*/
int id; /*设备编号,配合设备名使用*/
struct device dev;
u32 num_resources;
struct resource *resource; /*设备资源*/
}

struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags; /*资源的类型*/
struct resource *parent, *sibling, *child;
};
注册平台设备,使用函数:
int platform_device_register(struct platform_device *pdev);

3.平台驱动
平台驱动使用struct platform_driver 描述:
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
……
}

平台驱动注册使用函数:
int platform_driver_register(struct platform_driver *);

将按键驱动修改为平台驱动模型
key_dev.c:
  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/platform_device.h>
  4. #include <linux/interrupt.h>

  5. MODULE_LICENSE("GPL");

  6. #define GPFCON 0x56000050

  7. struct resource key_resource[] = {                                                             //设置资源,对应2440的芯片地址
  8.     [0] = {
  9.         .start = GPFCON,
  10.     .end = GPFCON + 8,
  11.     .flags = IORESOURCE_MEM,
  12.         },
  13.     [1] = {
  14.         .start = IRQ_EINT0,
  15.     .end = IRQ_EINT2,
  16.     .flags = IORESOURCE_IRQ,
  17.         },
  18. };

  19. struct platform_device key_device = {                                                           //这个是平台设备结构
  20.     .name = "my-key",
  21.     .id = 0,
  22.     .num_resources = 2,
  23.     .resource = key_resource,
  24. };

  25. int keydev_init()
  26. {
  27.     platform_device_register(&key_device);                                                  //注册平台设备
  28. }

  29. void keydev_exit()
  30. {
  31.     platform_device_unregister(&key_device);                                              //注销平台设备
  32. }

  33. module_init(keydev_init);
  34. module_exit(keydev_exit);
key_drv.c:
  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/miscdevice.h>
  4. #include <linux/fs.h>
  5. #include <asm/uaccess.h>
  6. #include <linux/io.h>
  7. #include <linux/irqreturn.h>
  8. #include <linux/interrupt.h>
  9. #include <linux/uaccess.h>
  10. #include <linux/platform_device.h>

  11. MODULE_LICENSE("GPL");

  12. #define GPFCON (volatile unsigned long*) 0x56000050
  13. #define GPFDAT (volatile unsigned long*) 0x56000054

  14. unsigned int *gpio_data;

  15. struct work_struct *work1;
  16. struct timer_list key_timer;
  17. wait_queue_head_t key_q;

  18. struct resource *res_irq;
  19. struct resource *res_mem;
  20. unsigned int *key_base;

  21. unsigned int key_num = 0;

  22. void key_timer_func(unsigned long data)
  23. {
  24.     unsigned int key_val;
  25.     key_val = readw(key_base+1);
  26.     if((key_val & 0x01) == 0)
  27.     {
  28.         key_num = 4;
  29.     }
  30.     else if((key_val& 0x02) == 0)
  31.     {
  32.         key_num = 1;
  33.     }
  34.     else if((key_val & 0x04) == 0)
  35.     {
  36.         key_num = 3;
  37.     }
  38.     else if((key_val & 0x10) == 0)
  39.     {
  40.         key_num = 2;
  41.     }

  42.     wake_up(&key_q);
  43. }

  44. void work1_func(struct work_struct *work)
  45. {
  46.     mod_timer(&key_timer, jiffies + HZ/10);
  47. }

  48. irqreturn_t key_int(int irq, void *dev_id)
  49. {
  50.     //1.检测是否发生了按键中断
  51.     
  52.     //2.清除已经发生的按键中断
  53.   
  54.     //3.提交下半部
  55.     schedule_work(work1);

  56.     return 0;
  57. }

  58. void key_hw_init()
  59. {
  60.     unsigned short data;
  61.     
  62.     data = readw(key_base);
  63.     data &= ~0x33f;
  64.     data |= 0x22a;
  65.     writew(data, key_base);
  66. }

  67. int key_open(struct inode *inode, struct file *filp)
  68. {
  69.     return 0;
  70. }

  71. ssize_t key_read(struct file *filp, char __user *buf, size_t size, loff_t *pos)
  72. {
  73.     wait_event(key_q, key_num);

  74.     printk("in kernel :key num is %d\n",key_num);
  75.     copy_to_user(buf, &key_num, 4);

  76.     key_num = 0;

  77.     return 4;
  78. }

  79. struct file_operations key_fops = {
  80.     .open = key_open,
  81.     .read = key_read,
  82. };

  83. struct miscdevice key_miscdev = {
  84.     .minor = 200,
  85.     .name = "tq2440key",
  86.     .fops = &key_fops,
  87. };

  88. int key_probe(struct platform_device *pdev)
  89. {
  90.     int ret,size;
  91.     
  92.     
  93.     ret = misc_register(&key_miscdev);
  94.     
  95.     if (ret !=0)
  96.         printk("register fail!\n");
  97.     
  98.     //注册中断处理程序
  99.     
  100.     res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);                                            //获取资源
  101.     
  102.     request_irq(res_irq->start,key_int,IRQF_TRIGGER_FALLING,"key",(void *)4);                          //设置中断
  103.     request_irq(res_irq->end,key_int,IRQF_TRIGGER_FALLING,"key",(void *)3);
  104.     
  105.     //按键初始化
  106.     res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  107.     size = (res_mem->end - res_mem->start) + 1;
  108.     key_base = ioremap(res_mem->start, size);
  109.     
  110.     key_hw_init();
  111.     
  112.     //. 创建工作
  113.     work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);
  114.     INIT_WORK(work1, work1_func);
  115.     
  116.     /* 初始化定时器 */
  117.     init_timer(&key_timer);
  118.     key_timer.function = key_timer_func;
  119.     
  120.     /* 向内核注册一个定时器 */
  121.     add_timer(&key_timer);
  122.     
  123.     /*初始化等待队列*/
  124.     init_waitqueue_head(&key_q);
  125.     
  126.     return 0;
  127. }

  128. int key_remove(struct paltform_device *pdev)
  129. {
  130.     misc_deregister(&key_miscdev);
  131.     //注销中断处理函数
  132.     //free_irq(IRQ_EINT0, 0);
  133.     //free_irq(IRQ_EINT1, 0);
  134.     //free_irq(IRQ_EINT2, 0);
  135.     //free_irq(IRQ_EINT4, 0);
  136.     return 0;
  137. }

  138. struct platform_driver key_driver = {                                                         //这里是平台驱动结构,与平台设备结构通过name进行对接
  139.     .probe = key_probe,
  140.     .remove = key_remove,
  141.     .driver = {
  142.         .owner = THIS_MODULE,
  143.         .name = "my-key",
  144.     },
  145. };

  146. static int button_init()
  147. {
  148.     return platform_driver_register(&key_driver);                                         //注册平台驱动
  149.     
  150. }

  151. static void button_exit()
  152. {
  153.     platform_driver_unregister(&key_driver);                                               //注销平台驱动
  154. }

  155. module_init(button_init);
  156. module_exit(button_exit);



阅读(426) | 评论(0) | 转发(0) |
0

上一篇:阻塞型驱动设计

下一篇:tty驱动程序架构

给主人留下些什么吧!~~