驱动开发学习笔记. 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
 

posted on 2016-10-05 23:57  simonlin  阅读(923)  评论(0编辑  收藏  举报

导航