1 平臺匯流排的簡介 平臺匯流排是一種虛擬的匯流排,相應的設備則為platform_device,而驅動則為platform_driver。匯流排將設備和驅動綁定,在系統每註冊一個設備的時候,會尋找與之匹配的驅動;相反的,在系統每註冊一個驅動的時候,會尋找與之匹配的設備,而匹配由匯流排完成。 我們可以把一個驅 ...
1 平臺匯流排的簡介
平臺匯流排是一種虛擬的匯流排,相應的設備則為platform_device,而驅動則為platform_driver。匯流排將設備和驅動綁定,在系統每註冊一個設備的時候,會尋找與之匹配的驅動;相反的,在系統每註冊一個驅動的時候,會尋找與之匹配的設備,而匹配由匯流排完成。
我們可以把一個驅動程式抽出來分為兩部分,一部分是硬體相關的dev,另一部分則是穩定的純軟體部分driver。而匯流排只是一種機制,把dev和driver這兩部分建立“聯繫”的機制。
eg:
①dev部分
a.把device放入bus的dev鏈表
b.從bus的drv鏈表取出每一個drv,用bus的match函數判斷drv是否支持dev
c.如果支持,將調用drv的probe函數
②drv部分
a.把driver放入bus的drv鏈表
b.從bus的dev鏈表取出每一個dev,用bus的match函數判斷dev是否支持drv
c.如果支持,將調用drv的probe函數
2 linux平臺匯流排的代碼分析
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match, //dev和drv匹配時調用的函數
.uevent = platform_uevent,
.suspend = platform_suspend,
.suspend_late = platform_suspend_late,
.resume_early = platform_resume_early,
.resume = platform_resume,
};
static int platform_match(struct device * dev, struct device_driver * drv)
{
struct platform_device *pdev = container_of(dev, struct platform_device, dev);
return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);//當dev的設備名與drv的名字相同時,則匹配成功
}
platform_device結構體的定義
struct platform_device {
const char * name;
u32 id;
struct device dev;
u32 num_resources;//資源數目
struct resource * resource;//設備信息,使用platform_get_resource函數來獲取資源信息
};
註冊平臺設備platform_device_register,實際上是加入到bus的dev鏈表中
1 int platform_device_register(struct platform_device * pdev)
2 {
3 device_initialize(&pdev->dev);//初始化platform_device的device成員
4 return platform_device_add(pdev);//實際上是調用device_add函數
5 }
同樣的,也有platform_driver結構體的定義
1 struct platform_driver { 2 int (*probe)(struct platform_device *); 3 int (*remove)(struct platform_device *); 4 void (*shutdown)(struct platform_device *); 5 int (*suspend)(struct platform_device *, pm_message_t state); 6 int (*suspend_late)(struct platform_device *, pm_message_t state); 7 int (*resume_early)(struct platform_device *); 8 int (*resume)(struct platform_device *); 9 struct device_driver driver; 10 }
//device_driver的定義:
1 struct device_driver {
2 const char * name;
3 struct bus_type * bus;
4
5 struct kobject kobj;
6 struct klist klist_devices;
7 struct klist_node knode_bus;
8
9 struct module * owner;
10 const char * mod_name; /* used for built-in modules */
11 struct module_kobject * mkobj;
12
13 int (*probe) (struct device * dev);
14 int (*remove) (struct device * dev);
15 void (*shutdown) (struct device * dev);
16 int (*suspend) (struct device * dev, pm_message_t state);
17 int (*resume) (struct device * dev);
18 };
註冊device_driver結構體:
1 int driver_register(struct device_driver * drv)
2 {
3 if ((drv->bus->probe && drv->probe) ||
4 (drv->bus->remove && drv->remove) ||
5 (drv->bus->shutdown && drv->shutdown)) {
6 printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);
7 }
8 klist_init(&drv->klist_devices, NULL, NULL);
9 return bus_add_driver(drv);
10 }
3 寫代碼
3.1框架
(1)分配、設置、註冊一個platform_device/platform_driver結構體
(2)按照led.c的框架來構建
3.2 源代碼
1 #include <linux/module.h>
2 #include <linux/version.h>
3
4 #include <linux/init.h>
5
6 #include <linux/kernel.h>
7 #include <linux/types.h>
8 #include <linux/interrupt.h>
9 #include <linux/list.h>
10 #include <linux/timer.h>
11 #include <linux/init.h>
12 #include <linux/serial_core.h>
13 #include <linux/platform_device.h>
14
15 static struct resource myled_dev_resource[] = {
16 [0] = {
17 .start = 0x56000050,
18 .end = 0x56000050 + 8 - 1,
19 .flags = IORESOURCE_MEM,
20 },
21 [1] = {
22 .start = 6,
23 .end = 6,
24 .flags = IORESOURCE_IRQ,
25 }
26 };
27
28
29 static void myled_dev_release(struct device * dev)
30 {
31 }
32
33
34 static struct platform_device myled_dev = {
35 .name = "myled",
36 .id = -1,
37 .num_resources = ARRAY_SIZE(myled_dev_resource),
38 .resource = myled_dev_resource,
39 .dev = {
40 .release = myled_dev_release,
41 }
42 };
43
44 static int myled_dev_init(void)
45 {
46 platform_device_register(&myled_dev);
47 return 0;
48 }
49
50 static void myled_dev_exit(void)
51 {
52 platform_device_unregister(&myled_dev);
53 }
54
55 module_init(myled_dev_init);
56 module_exit(myled_dev_exit);
57
58 MODULE_LICENSE("GPL");
myled_dev.c
1 #include <linux/module.h>
2 #include <linux/version.h>
3
4 #include <linux/init.h>
5 #include <linux/fs.h>
6 #include <linux/interrupt.h>
7 #include <linux/irq.h>
8 #include <linux/sched.h>
9 #include <linux/pm.h>
10 #include <linux/sysctl.h>
11 #include <linux/proc_fs.h>
12 #include <linux/delay.h>
13 #include <linux/platform_device.h>
14 #include <linux/input.h>
15 #include <linux/irq.h>
16 #include <asm/uaccess.h>
17 #include <asm/io.h>
18
19
20
21 static struct class *g_ptMyledCls;
22 static struct class_device *g_ptMyledClsDev;
23 static int g_iPin;
24
25 volatile unsigned long *gpiocon = NULL;
26 volatile unsigned long *gpiodat = NULL;
27
28
29 static int myled_open(struct inode *inode, struct file *file)
30 {
31 //printk("first_drv_open\n");
32 /* 配置GPF4,5,6為輸出 */
33 *gpiocon &= ~(0x3<<(g_iPin*2)) ;
34 *gpiodat |= (0x1<<(g_iPin*2)) ;
35 return 0;
36 }
37
38 static ssize_t myled_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
39 {
40 int val;
41
42 //printk("first_drv_write\n");
43
44 copy_from_user(&val, buf, count); // copy_to_user();
45
46 if (val == 1)
47 {
48 // 點燈
49 *gpiodat &= ~(1<<g_iPin);
50 }
51 else
52 {
53 // 滅燈
54 *gpiodat |= (1<<g_iPin);
55 }
56
57 return 0;
58 }
59
60
61 static struct file_operations myled_fops = {
62 .owner = THIS_MODULE, /* 這是一個巨集,推向編譯模塊時自動創建的__this_module變數 */
63 .open = myled_open,
64 .write = myled_write,
65 };
66
67
68 static int g_iMajor;
69
70 static int myled_probe(struct platform_device *dev)
71 {
72 struct resource *tRes;
73 tRes = platform_get_resource(dev, IORESOURCE_MEM, 0);
74 gpiocon = ioremap(tRes->start, tRes->end - tRes->start +1);
75 gpiodat = gpiocon + 1;
76
77 tRes = platform_get_resource(dev, IORESOURCE_IRQ, 0);
78 g_iPin = tRes->start;
79
80 printk("myled_probe, found led\n");
81
82 g_iMajor = register_chrdev(0, "myled", &myled_fops); // 註冊, 告訴內核
83 g_ptMyledCls = class_create(THIS_MODULE, "myled");
84
85 g_ptMyledClsDev = class_device_create(g_ptMyledCls, NULL, MKDEV(g_iMajor, 0), NULL, "myled"); /* /dev/xyz */
86 return 0;
87 }
88
89 static int myled_remove(struct platform_device *dev)
90 {
91 printk("led_remove, remove led\n");
92
93 class_device_destroy(g_ptMyledCls, MKDEV(g_iMajor, 0));
94 class_destroy(g_ptMyledCls);
95 unregister_chrdev(g_iMajor, "myled");
96 iounmap(gpiocon);
97
98 return 0;
99 }
100
101 static struct platform_driver myled_driver = {
102 .probe = myled_probe,
103 .remove = myled_remove,
104 .driver = {
105 .name = "myled",
106 },
107 };
108
109 static int myled_drv_init(void)
110 {
111 platform_driver_register(&myled_driver);
112 return 0;
113 }
114
115 static void myled_drv_exit(void)
116 {
117 platform_driver_unregister(&myled_driver);
118 }
119
120
121 module_init(myled_drv_init);
122 module_exit(myled_drv_exit);
123
124 MODULE_LICENSE("GPL");
myled_drv.c
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <stdio.h>
5
6 /* firstdrvtest on
7 * firstdrvtest off
8 */
9 int main(int argc, char **argv)
10 {
11 int fd;
12 int val = 1;
13 fd = open("/dev/myled", O_RDWR);
14 if (fd < 0)
15 {
16 printf("can't open!\n");
17 }
18 if (argc != 2)
19 {
20 printf("Usage :\n");
21 printf("%s <on|off>\n", argv[0]);
22 return 0;
23 }
24
25 if (strcmp(argv[1], "on") == 0)
26 {
27 val = 1;
28 }
29 else
30 {
31 val = 0;
32 }
33
34 write(fd, &val, 4);
35 return 0;
36 }
測試程式
編輯於2017-01-09 16:36:01