在上一篇博文中,设备和驱动都是通过手动加载的(调试的时候采用这种方式),但有些情况下,内核已经为设备注册到platform总线上,只需要我们注册驱动就可以了。接下来介绍一下设备的静态注册。
先看一下内核是从哪里获取静态注册的platform_device。
内核是从../linux-2.6.36/arch/arm/mach-s3c64xx/mach-mini6410.c文件中获取到platform_device的信息:
362 static struct platform_device *mini6410_devices[] __initdata = {
363 &globalfifo_device,
364 &s3c_device_led, //add by wenhui
365 #ifdef CONFIG_MINI6410_SD_CH0
366 &s3c_device_hsmmc0,
367 #endif
368 #ifdef CONFIG_MINI6410_SD_CH1
369 &s3c_device_hsmmc1,
370 #endif
371 &s3c_device_i2c0,
372 #ifdef CONFIG_S3C_DEV_I2C1
373 &s3c_device_i2c1,
374 #endif
375 &s3c_device_nand,
376 &s3c_device_fb,
...
}
可以看到,这个数组存放着所有静态注册的 platform_device信息,我按照它们的格式,也添加了一个 s3c_device_led结构体指针在这个数组中。接下来就要看看是在哪里定义了。结果发现在../linux-2.6.36/arch/arm/plat-samsung 中发现
每个设备的资源都是以一个单独的文件来包含的 所以我就可以照样画葫芦新建一个dev-led.c
1> cp dev-wdt.c dev-led.c ; vim dev-led.c 经修改后
1 /* linux/arch/arm/plat-samsung/dev-led.c
2 *
3 * Copyright (c) 2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C series device definition for the watchdog timer
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13 #include <linux/kernel.h>
14 #include <linux/platform_device.h>
15
16 #include <mach/irqs.h>
17 #include <mach/map.h>
18
19 #include <plat/devs.h>
20
21 static struct resource s3c_led_resource[1] = {
22 [0] = {
23 .start = 0x7F008800,
24 .end = 0X7F00880C,
25 .flags = IORESOURCE_MEM,
26 },
27 };
28
29 struct platform_device s3c_device_led = {
30 .name = "plat-led",
31 .id = -1,
32 .num_resources = 1,
33 .resource = s3c_led_resource,
34 };
35 EXPORT_SYMBOL(s3c_device_led);
2>在Makefile 中 添加编译选项 50行
45 obj-$(CONFIG_S3C_DEV_USB_HOST) += dev-usb.o
46 obj-$(CONFIG_S3C_DEV_USB_HSOTG) += dev-usb-hsotg.o
47 obj-$(CONFIG_S3C_DEV_WDT) += dev-wdt.o
48
49 #add by wenhui for platform led
50 obj-y += dev-led.o
51
52 obj-$(CONFIG_S3C_DEV_NAND) += dev-nand.o
3>在../linux-2.6.36/arch/arm/plat-samsung/include/plat/devs.h中增加
(platform_match函数是通过包含该文件后读取里面的platform_device信息来跟platform_driver匹配。
所以,必须在这里加上一行代码:)
42 extern struct platform_device s3c_device_fb;
43 extern struct platform_device s3c_device_ohci;
44 extern struct platform_device s3c_device_lcd;
45 extern struct platform_device s3c_device_wdt;
46
47 extern struct platform_device s3c_device_led; //add by wenhui
48
49 extern struct platform_device s3c_device_i2c0;
修改完上面的几个文件后,重新编译内核后就实现了静态注册 platform设备,在内核启动时会自动注册 s3c_device_led。所以,我们只需要注册 platform驱动就可以了
以下是驱动的代码:
//driver.c
1 #include<linux/module.h>
2 #include<linux/init.h>
3
4 #include<linux/platform_device.h>
5 #include<asm/io.h>
6 #include<asm/sizes.h>
7
8 struct plat_led{
9 unsigned long phys, virt;
10 unsigned long gpkcon1, gpkdat, gpkup;
11 unsigned long reg;
12 };
13
14 struct plat_led pled;
15
16 int led_driver_probe(struct platform_device *pdev)
17 {
18 printk("led_driver_probe\n");
19 pled.phys = pdev->resource[0].start; /*0x7F008800*/
20
21 /*不加强制性转换 会报 warning: assignment makes integer from pointer without a cast*/
22 pled.virt = (unsigned long)ioremap(pled.phys, SZ_4K);
23
24 pled.gpkcon1 = pled.virt + 0x4;
25 pled.gpkdat = pled.virt + 0x8;
26 pled.gpkup = pled.virt + 0xc;
27
28 //config
29 pled.reg = ioread32(pled.gpkcon1); /*GPK4 LED1*/
30 pled.reg &= ~(0xe<<0); /*0001 output*/
31 pled.reg |= (0x1<<0);
32 iowrite32(pled.reg, pled.gpkcon1);
33
34 //up
35 pled.reg = ioread32(pled.gpkup);
36 pled.reg &= ~(0x3<<8); /*disable pull-up/down*/
37 iowrite32(pled.reg, pled.gpkup);
38
39 //dat
40 pled.reg = ioread32(pled.gpkdat);
41 pled.reg &= ~(0x1<<8); /*low */
42 iowrite32(pled.reg, pled.gpkdat);
43
44 printk("led on\n");
45 return 0;
46 }
47
48 int led_driver_remove(struct platform_device *pdev)
49 {
50 printk("led_driver_remove\n");
51 pled.reg = ioread32(pled.gpkdat);
52 pled.reg |= (0x1<<8);
53 iowrite32(pled.reg, pled.gpkdat);
54
55 printk("led off\n");
56 return 0;
57 }
58
59 struct platform_driver s3c_led_drv = {
60 .probe = led_driver_probe,
61 .remove = led_driver_remove,
62 .driver = {
63 .name = "plat-led", /*在/sys/ 中的驱动目录名字*/
64 },
65 };
66
67 static int __init plat_led_init(void)
68 {
69 int ret;
70 ret = platform_driver_register(&s3c_led_drv);
71 if(ret){
72 printk("led register failed!\n");
73 return ret;
74 }
75 printk("led driver init\n");
76
77 return ret;
78 }
79
80 static void __exit plat_led_exit(void)
81 {
82 platform_driver_unregister(&s3c_led_drv);
83 printk("led driver exit");
84 }
85
86 module_init(plat_led_init);
87 module_exit(plat_led_exit);
88
89 MODULE_LICENSE("GPL");
90 MODULE_AUTHOR("wenhui");