总线驱动设备模型:
1. 总线设备驱动模型概述
随着技术的不断进步,系统的拓扑结构也越来越复杂,对热插拔,跨平台移植性的要求也越来越高,2.4内核已经难以满足这些需求,为适应这宗形势的需求,从linux2.6内核开始提供了全新的设备模型
2. 总线
2.1 描述结构
2.2 注册
2.3 注销
void bus_unregister(struct bus_type *bus)
代码例程:
bus.c
[cpp] view plain copy
1. #include<linux/module.h>
2. #include<linux/init.h>
3. #include<linux/kernel.h>
4. #include<linux/device.h>
5.
6. MODULE_LICENSE("GPL");
7.
8. int my_match(struct device *dev, struct device_driver *drv)
9. {
10.
11. return 0;
12. }
13.
14. struct bus_type my_bus_type =
15. {
16. "my_bus",
17. .match = my_match,
18. };
19.
20. int my_bus_init(void)
21. {
22. int ret;
23.
24. ret = bus_register(&my_bus_type);
25.
26. return ret;
27. }
28.
29. void my_bus_exit(void)
30. {
31. bus_unregister(&my_bus_type);
32. }
33.
34.
35. module_init(my_bus_init);
36. module_exit(my_bus_exit);
这是上面的总线驱动模块编译运行的效果图!
下面向上面的my_bus总线上挂载一个驱动!
3. 驱动
3.1 描述结构
3.2 注册
int drvier_register(struct device *dev)
3.3 注销
void drever_unregister(struct device_driver *drv)
4. 设备
4.1 设备的描述
4.2 设备的注册
int device_register(struct device *dev)
4.3 设备的注销
void device_unregister(struct device *dev)
driver.c
[cpp] view plain copy
1. #include<linux/module.h>
2. #include<linux/init.h>
3. #include<linux/device.h>
4. #include<linux/kernel.h>
5.
6. MODULE_LICENSE("GPL");
7.
8. extern struct bus_type my_bus_type;
9.
10. int my_probe(struct device *dev)
11. {
12. "driver found the device!!!\n");
13.
14. return 0;
15. }
16.
17. struct device_driver my_driver =
18. {
19. "my_dev",
20. .bus = &my_bus_type,
21. //当找到这个设备时将调用这个函数
22. };
23.
24. int my_device_init(void)
25. {
26. int ret;
27.
28. //注册一个驱动
29.
30. return 0;
31. }
32.
33. void my_device_exit(void)
34. {
35. driver_unregister(&my_driver);
36. }
37.
38. module_init(my_device_init);
39. module_exit(my_device_exit);
Makefile
[cpp] view plain copy
1. obj-m := bus.o device.o
2. KDIR := /home/kernel/linux-ok6410
3. all:
4. make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm
5. clean:
6. rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order
下面再在总线上挂载一个设备!
device.c
[cpp] view plain copy
1. #include <linux/device.h>
2. #include <linux/module.h>
3. #include <linux/kernel.h>
4. #include <linux/init.h>
5.
6. MODULE_LICENSE("GPL");
7.
8. extern struct bus_type my_bus_type;
9.
10. struct device my_dev =
11. {
12. "my_dev",//和驱动名字一样
13. .bus = &my_bus_type,
14. };
15.
16. int my_device_init(void)
17. {
18. int ret;
19. ret = device_register(&my_dev);
20. return ret;
21.
22. }
23.
24.
25. void my_device_exit(void)
26. {
27. device_unregister(&my_dev);
28. }
29.
30. module_init(my_device_init);
31. module_exit(my_device_exit);
driver.
[cpp] view plain copy
1. #include<linux/module.h>
2. #include<linux/init.h>
3. #include<linux/device.h>
4. #include<linux/kernel.h>
5.
6. MODULE_LICENSE("GPL");
7.
8. extern struct bus_type my_bus_type;
9.
10. int my_probe(struct device *dev)
11. {
12. "driver found the device!!!\n");
13.
14. return 0;
15. }
16.
17. struct device_driver my_driver =
18. {
19. "my_dev",
20. .bus = &my_bus_type,
21. //当找到这个设备时将调用这个函数
22. };
23.
24. int my_device_init(void)
25. {
26. int ret;
27.
28. //注册一个驱动
29.
30. return 0;
31. }
32.
33. void my_device_exit(void)
34. {
35. driver_unregister(&my_driver);
36. }
37.
38. module_init(my_device_init);
39. module_exit(my_device_exit);
bus.c
[cpp] view plain copy
1. #include<linux/module.h>
2. #include<linux/init.h>
3. #include<linux/kernel.h>
4. #include<linux/device.h>
5.
6. MODULE_LICENSE("GPL");
7.
8. int my_match(struct device *dev, struct device_driver *drv)
9. {
10. return !strncmp(dev->kobj.name,drv->name,strlen(drv->name));
11. }
12.
13. struct bus_type my_bus_type =
14. {
15. "my_bus",
16. .match = my_match,
17. };
18.
19. EXPORT_SYMBOL(my_bus_type);//输出符号 另一device.c要用到
20.
21. int my_bus_init(void)
22. {
23. int ret;
24.
25. ret = bus_register(&my_bus_type);
26.
27. return ret;
28. }
29.
30. void my_bus_exit(void)
31. {
32. bus_unregister(&my_bus_type);
33. }
34.
35.
36. module_init(my_bus_init);
37. module_exit(my_bus_exit);
Makefile
[cpp] view plain copy
1. obj-m := bus.o driver.o device.o
2. KDIR := /home/kernel/linux-ok6410
3. all:
4. make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm
5. clean:
6. rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order
运行效果图:
平台总线驱动设计:
1. 平台总线概述
平台总线(Platform bus)是linux2.6内核加入的一种虚拟总线,其优势在于采用了总线的模型对设备与驱动进行了管理,这样提高了程序的可移植性。
2. 平台设备
注册平台设备,使用函数:
int platform_device_register(struct platform_device *pdev)
3. 平台驱动
平台驱动注册使用函数:
int platform_driver_register(struct platform_driver *)
结合上面的基础知识,将案件驱动修改为平台驱动模式!
1. 平台设备注册
2. 平台按键驱动设计
key_dev.c
[cpp] view plain copy
1. #include<linux/init.h>
2. #include<linux/module.h>
3. #include<linux/platform_device.h>
4. #include<linux/interrupt.h>
5.
6. MODULE_LICENSE("GPL");
7.
8. #define GPNCON 0x7F008830
9.
10. static struct resource key_resource[] = { //定义按键资源
11. [0] = {
12. .start = GPNCON,
13. .end = GPNCON + 8,
14. //内存地址资源
15. },
16. [1] = {
17. //按键中断资源
18. .end = S3C_EINT(5),
19. //内存地址资源
20. },
21. };
22.
23. struct platform_device key_device =
24. {
25. "my_key",
26. .id = 0,
27. .num_resources = ARRAY_SIZE(key_resource),
28. .resource = key_resource,
29. };
30.
31. int keydri_init(void)
32. {
33. platform_device_register(&key_device);
34. return 0;
35. }
36.
37. void keydri_exit(void)
38. {
39. platform_device_unregister(&key_device);
40. }
41.
42. module_init(keydri_init);
43. module_exit(keydri_exit);
编译运行截图:
key_dri.c
[cpp] view plain copy
1. #include <linux/module.h>
2. #include <linux/init.h>
3. #include <linux/miscdevice.h> /* for struct miscdevice*/
4. #include <linux/interrupt.h>
5. #include <linux/fs.h> /* for iormap */
6. #include <linux/io.h>
7. #include <linux/slab.h> /* for kmalloc */
8. #include<linux/uaccess.h> /* for copy_to_usr */
9. #include <linux/platform_device.h>
10.
11. //#define GPNCON 0x7F008830
12. //#define GPNDAT 0x7F008834
13. MODULE_LICENSE("GPL");
14.
15. unsigned int *key_base;
16.
17. struct work_struct *work1;//定义一项工作
18.
19. struct timer_list key_timer; //定义一个定时器key_timer
20.
21. unsigned int key_num;
22.
23. struct resource *res_mem;
24. struct resource *res_irq;
25. int size;
26.
27. void work1_func(struct work_struct *work)
28. {
29. //启动定时器 jiffies是全局变量,用来表示当前系统时间 1S=1000个滴答数
30. //设置100ms超时 1HZ=1S
31. }
32.
33. void key_timer_func(unsigned long data)
34. {
35. int key_val;
36.
37. //只读取最后一位
38. if(key_val == 0)
39. {
40. "OK6410 key1 down!\n");
41. key_num = 0;
42. }
43.
44. //只读取最后一位
45. if(key_val == 0)
46. {
47. "OK6410 key6 down!\n");
48. key_num = 6;
49. }
50.
51. }
52.
53. irqreturn_t key_int(int irq, void *dev_id)
54. {
55. //1. 检测是否发生了按键中断 这里可以暂时不做,因为这里没有使用共享中断
56.
57. //2. 清除已经发生的按键中断 这个是指硬件内部处理,按键CPU内部不需要做处理
58.
59. //3. 提交下半部
60. schedule_work(work1);
61.
62. //return 0;
63. return IRQ_HANDLED;
64. }
65.
66. void key_hw_init(void) //按键硬件初始化部分
67. {
68. //unsigned int *gpio_config;
69. short data;
70.
71. //gpio_config = ioremap(GPNCON, 4);//将物理地址转化为虚拟地址
72. data = readw(key_base);
73. //先清零
74. //后两位设置成0b10
75. writew(data, key_base);
76.
77. //gpio_data = ioremap(GPNDAT, 4);//将物理地址转化为虚拟地址
78.
79. "init ...!\n");
80. }
81.
82. int key_open(struct inode *node, struct file *filp)
83. {
84. "open ...!\n");
85.
86. return 0;
87. }
88.
89. ssize_t key_read(struct file *filp, char __user *buf, size_t size, loff_t *pos)
90. {
91. //将key_value值返回给用户空间
92. "in kernel :key num is %d\n",key_num);
93. //buf为用户空间传过来的地址
94.
95. return 4;
96. }
97.
98. struct file_operations key_fops =
99. {
100. .open = key_open,
101. .read = key_read,
102. };
103.
104. struct miscdevice key_miscdev = //定义一个misdevice结构
105. {
106. .minor = 200,
107. "6410key",
108. //这里key_fops是一个struct file_operations结构
109. };
110.
111. static int __devinit key_probe(struct platform_device *pdev)
112. {
113.
114. //注册一个混杂设备驱动设备
115.
116. //取出中断资源
117. "my_key",(void *)1);
118. "my_key",(void *)6);
119.
120. //取出地址资源
121.
122. size = res_mem->end - res_mem->start + 1;
123. key_base = ioremap(res_mem->start,size);
124.
125. key_hw_init();
126.
127. sizeof(struct work_struct),GFP_KERNEL);
128. INIT_WORK(work1 , work1_func );
129.
130. //初始化定时器
131. init_timer(&key_timer);
132. //将定义的函数赋值给函数指针
133.
134. //注册定时器
135. add_timer(&key_timer);
136.
137.
138. return 0;
139.
140. }
141.
142. static int key_remove(struct platform_device *device)
143. {
144. //注销中断 这里irqnumber参数暂时用一个变量来表示(中断号)
145. //注销中断 这里irqnumber参数暂时用一个变量来表示(中断号)
146.
147. //注销一个混杂设备驱动
148.
149. return 0;
150. }
151.
152. struct platform_driver key_driver =
153. {
154. .driver = {
155. "my_key",
156. .owner = THIS_MODULE,
157. },
158. .probe = key_probe,
159. .remove = key_remove,
160. };
161.
162. static int key_init(void)
163. {
164.
165. return platform_driver_register(&key_driver);
166.
167. }
168.
169. static void key_exit(void)
170. {
171.
172. //卸载平台驱动
173.
174. "key up!");
175. }
176.
177. module_init(key_init);
178. module_exit(key_exit);
179. MODULE_LICENSE("GPL");
180. MODULE_DESCRIPTION("key driver");
Makefile
[cpp] view plain copy
1. obj-m := key_dev.o key_dri.o
2. KDIR := /home/kernel/linux-ok6410
3. all:
4. make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm
5. clean:
6. rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order
编译运行效果截图:
按下按键1或者按下按键6 可以看到驱动程序打印出如下信息! 这里或者创建设备文件,然后用前面博客里面的应用程序来测试也是一样的!