驱动开发读书笔记. 0.04 linux 2.6 platform device register 平台设备注册 1/2 共2篇
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了驱动开发读书笔记. 0.04 linux 2.6 platform device register 平台设备注册 1/2 共2篇相关的知识,希望对你有一定的参考价值。
驱动开发读书笔记. 0.04 linux 2.6 platform device register 平台设备注册 1/2 共2篇
下面这段摘自 linux源码里面的文档 :
Documentation/driver-model/platform.txt
Device Enumeration 82 ~~~~~~~~~~~~~~~~~~ 83 As a rule, platform specific (and often board-specific) setup code will 84 register platform devices: 85 86 int platform_device_register(struct platform_device *pdev); 87 88 int platform_add_devices(struct platform_device **pdevs, int ndev); 89 90 The general rule is to register only those devices that actually exist, 91 but in some cases extra devices might be registered. For example, a kernel 92 might be configured to work with an external network adapter that might not 93 be populated on all boards, or likewise to work with an integrated controller 94 that some boards might not hook up to any peripherals. 95 96 In some cases, boot firmware will export tables describing the devices 97 that are populated on a given board. Without such tables, often the 98 only way for system setup code to set up the correct devices is to build 99 a kernel for a specific target board. Such board-specific kernels are 100 common with embedded and custom systems development. 101 102 In many cases, the memory and IRQ resources associated with the platform 103 device are not enough to let the device‘s driver work. Board setup code 104 will often provide additional information using the device‘s platform_data 105 field to hold additional information. 106 107 Embedded systems frequently need one or more clocks for platform devices, 108 which are normally kept off until they‘re actively needed (to save power). 109 System setup also associates those clocks with the device, so that that 110 calls to clk_get(&pdev->dev, clock_name) return them as needed. 111 112 113 Legacy Drivers: Device Probing 114 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 115 Some drivers are not fully converted to the driver model, because they take 116 on a non-driver role: the driver registers its platform device, rather than 117 leaving that for system infrastructure. Such drivers can‘t be hotplugged 118 or coldplugged, since those mechanisms require device creation to be in a 119 different system component than the driver. 120 121 The only "good" reason for this is to handle older system designs which, like 122 original IBM PCs, rely on error-prone "probe-the-hardware" models for hardware 123 configuration. Newer systems have largely abandoned that model, in favor of 124 bus-level support for dynamic configuration (PCI, USB), or device tables 125 provided by the boot firmware (e.g. PNPACPI on x86). There are too many 126 conflicting options about what might be where, and even educated guesses by 127 an operating system will be wrong often enough to make trouble. 128 129 This style of driver is discouraged. If you‘re updating such a driver, 130 please try to move the device enumeration to a more appropriate location, 131 outside the driver. This will usually be cleanup, since such drivers 132 tend to already have "normal" modes, such as ones using device nodes that 133 were created by PNP or by platform device setup. 134 135 None the less, there are some APIs to support such legacy drivers. Avoid 136 using these calls except with such hotplug-deficient drivers. 137 138 struct platform_device *platform_device_alloc( 139 const char *name, int id); 140 141 You can use platform_device_alloc() to dynamically allocate a device, which 142 you will then initialize with resources and platform_device_register(). 143 A better solution is usually: 144 145 struct platform_device *platform_device_register_simple( 146 const char *name, int id, 147 struct resource *res, unsigned int nres); 148 149 You can use platform_device_register_simple() as a one-step call to allocate 150 and register a device.
上文讲了两种platform设备注册方式,一种是
platform specific (and often board-specific) setup code
平台特定的,在/arch/arm/plat-s3c24xx/devs.c中找到相关数据结构和代码
第一步:定义资源结构体
static struct resource s3c_lcd_resource[] = { [0] = { .start = S3C24XX_PA_LCD, .end = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1, .flags = IORESOURCE_MEM, }, [1] = { .start = IRQ_LCD, .end = IRQ_LCD, .flags = IORESOURCE_IRQ, } };
第二步:定义platform_device (主要的有 设备名称 设备id(区分相同设备名) 资源个数 资源定义 内嵌设备)
struct platform_device s3c_device_lcd = { .name = "s3c2410-lcd", .id = -1, .num_resources = ARRAY_SIZE(s3c_lcd_resource), .resource = s3c_lcd_resource, .dev = { .dma_mask = &s3c_device_lcd_dmamask, .coherent_dma_mask = 0xffffffffUL } };
第三步:添加到platform_device指针数组 smdk2440_devices (arch/arm/mach-s3c2440/mach-smdk2440.c)
static struct platform_device *smdk2440_devices[] __initdata = { &s3c_device_usb, &s3c_device_lcd, &s3c_device_wdt, &s3c_device_i2c, &s3c_device_iis, };
第四步:添加到platform_device指针数组 (arch/arm/mach-s3c2440/mach-smdk2440.c)
static void __init smdk2440_machine_init(void) { s3c24xx_fb_set_platdata(&smdk2440_lcd_cfg); platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices)); smdk_machine_init(); }
platform_add_devices会将platform_device 注册到内核
第五步:有没有发现上面有个 s3c24xx_fb_set_platdata 函数?他是干什么的呢?
platform.txt 写道:
In many cases, the memory and IRQ resources associated with the platform
device are not enough to let the device‘s driver work. Board setup code
will often provide additional information using the device‘s platform_data
field to hold additional information.
因为 resource 结构是定义好的,所以不方便添加更多的信息 platform提供了平台数据platform_data的支持.
下面为函数原型:(感觉就是个不美观的补丁。。。)
void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd) { struct s3c2410fb_mach_info *npd; npd = kmalloc(sizeof(*npd), GFP_KERNEL); if (npd) { memcpy(npd, pd, sizeof(*npd)); s3c_device_lcd.dev.platform_data = npd; } else { printk(KERN_ERR "no memory for LCD platform data\n"); } }
第六步:第四步的代码还有个smdk_machine_init();
是进行gpio的设置,还有注册led设备
小结:第一种方法 定义资源 定义平台data 设置platdata(与platform_device 关联) 然后使用 platform_add_devices函数进行注册
注意 platform_add_devices 和platform_device_add区别很大,platform_add_devices(struct platform_device ** devs,int num) 里面根据传入的指针,
计算出需要注册的platform_device的数量(注意,这个number不是platform_device.id)然后使用迭代来调用platform_device_register(struct platform_device *)
进行注册.
所以核心的函数调用就是 platform_device_register这个函数,多个设备时调用platform_add_devices
有兴趣的朋友可以看一下platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));里面ARRAY_SIZE 计算数组元素个数 的实现方法
这个宏在<linux/kernel.h>里面
注意的是:上面代码都是编译进内核,而不是内核模块
小小的感想:
写了字符设备驱动之后,学习这个platform 设备驱动,十分好奇说是设备驱动,但是没有提供应用接口 open write的方法,百思不得其解;后来来回翻了几本书籍,发现platform似乎
就没有也不是为了提供这些接口而设计的,你可以在driver初始化或者proe探测函数里面 注册字符/混合/类设备 ,达到为应用提供write open的目的,而字符设备与platform 设备驱动的
联系似乎只是 提供注册和销毁的关系,设备驱动真是复杂,希望早日攻克。
下次介绍 第二种注册方式
参考资料:
linux源码 2.6.22
《linux驱动入门》----主编 魏清 副主编 梁庚 徐志国
23:56:02
2016-10-05
以上是关于驱动开发读书笔记. 0.04 linux 2.6 platform device register 平台设备注册 1/2 共2篇的主要内容,如果未能解决你的问题,请参考以下文章
驱动开发读书笔记. 0.06 嵌入式linux视频开发之预备知识
Android深度探索--HAL与驱动开发----第六章读书笔记