Matching platform_device and platform_driver

Source: Internet
Author: User
To be honest, I do not like the current Linux 2.6 bus, platform, device, and Device Driver modes. I think this pattern breaks the Linux philosophy of "Simplicity is beauty". Originally, the driver can accommodate all drivers, or directly register driver files and manage them, in addition, the previous driver can also be used in the current structure. What is the purpose of registering it to the bus tree? Although I can see some advantages of portability and platform management, I think the current style of driver programming is more and more like the Windows style, which is not intuitive and simple, so it is quite confusing to understand. After complaining, the bus structure will continue. Let's talk about the matching between platform_device and platform_driver! Generally, the system registers some devices on this platform in the corresponding function ap_init of init_init_machine, as follows: static struct resource cbp_sdmmc_resource [] =

{

[0] = {

. Start = hwd_mmc_base,

. End = hwd_mmc_base + 0xff0,

. Flags = ioresource_mem

},

[1] = {

. Start = irq_sdmmc,

. End = irq_sdmmc,

. Flags = ioresource_irq

},

[2] = {

. Start = irq_sdmmc_cd,

. End = irq_sdmmc_cd,

. Flags = ioresource_irq

}

}; Struct platform_device cbp_device_sdmmc = {

. Name = "White-sdmmc ",

. ID =-1,

. Num_resources = array_size (cbp_sdmmc_resource ),

. Resource = cbp_sdmmc_resource,

. Dev = {

. Coherent_dma_mask = 0 xfffffffful

}

};

Static struct platform_device * cbp_devices [] _ initdata = {

& Cbp_device_sdmmc

};

Static void _ init ap_init (void)

{

Platform_add_devices (cbp_devices, array_size (cbp_devices ));}

This indicates that the SD/MMC driver used by this platform is called "White-sdmmc". Then, the driver uses platform_driver_register to declare the corresponding platform_driver to use the platform resources stated above, as shown below: static int _ init cbpmci_init (void)

{

Return platform_driver_register (& cbpmci_driver );

}

There are two matching methods for platform_driver and platform_driver: 1) Matching Based on the name directly. This method is a common method, for example, the following statement cbpmci_driver: static struct platform_driver cbpmci_driver = {

. Probe = cbpmci_probe,

. Driver = {

. Name = "White-sdmmc ",

},

};

2) implement it through id_talbe. This implementation is ultimately matched by name correspondence, but the matched name is listed in a table. The name of platform_device is compared with each value in this table, find the same one, as stated below: static struct platform_device_id cbpmci_driver_ids [] = {

{

. Name = "Other-sdmmc ",

. Driver_data = 0,

},

{

. Name = "White-sdmmc ",

. Driver_data = 1,

},

{}

}; Static struct platform_driver cbpmci_driver = {
. Driver = {
. Name = "vtc_sdmmc ",
. Owner = this_module,
. PM = & cbpmci_pm_ops,
},
. Id_table = cbpmci_driver_ids,
. Probe = cbpmci_probe,
. Remove = _ devexit_p (cbpmci_remove ),
. Shutdown = cbpmci_shutdown,
};
When id_table is not empty ,. driver. the name "vtc_sdmmc" in name is useless and will be matched according to the content in id_table. After the match, the matched platform_device_id will be saved in the id_entry of the platform_device structure, during probe, you can use driver_data in id_entry to determine which group of IDs are matched in cbpmci_driver_ids.For example, the second group is matched in the "White-sdmmc" in the above example. Then, you can use probe to determine the platform. If (platform_get_device_id (pdev) -> driver_data = 1) printk ("cgp sd/MMC support \ n"); this matching method is used in Samsung's SD/MMC, because the addresses of 2412 and 2440 are the same, but those of 2410 are different, it is determined by whether driver_data is 1. Static struct platform_device_id initiai_driver_ids [] = {

{

. Name = "s3c2410-sdi ",

. Driver_data = 0,

},{

. Name = "s3c2412-sdi ",

. Driver_data = 1,

},{

. Name = "s3c2440-sdi ",

. Driver_data = 1,

},

{}

};

The following is the matching source code in Linux. in C, you can see it at a Glance. Of course, there are still many pointers in the middle to follow this step: static int platform_match (struct device * Dev, struct device_driver * DRV)

{

Struct platform_device * pdev = to_platform_device (Dev );

Struct platform_driver * pdrv = to_platform_driver (DRV);/* match against the ID table first */

If (pdrv-> id_table)

Return platform_match_id (pdrv-> id_table, pdev )! = NULL;/* fall-back to driver name match */

Return (strcmp (pdev-> name, DRV-> name) = 0 );

} In addition, platform_add_devices will eventually call platform_device_register, while platform_device_register and platform_driver_register should first call which theoretically calls device first and then driver, but it doesn't matter. Finally, they will call device_attach () to probe. Http://lwn.net/Articles/448499/The platform device apiby Jonathan Corbet
Jun 21,201 1

In the very early days, Linux users often had to tell the kernel where specific devices were to be found before their systems wocould work. in the absence of this information, the driver cocould not know which I/O Ports and interrupt line (s) the device was configured
To use. happily, we now live in the days of busses like PCI which have discoverability built into them; any device sitting on a PCI bus can tell the system what sort of device it is and where its resources are. so the kernel can, at boot time, enumerate
Devices available and everything just works.

Alas, life is not so simple; there are plenty of devices which are still not discoverable by the CPU. in the embedded and System-on-chip world, non-discoverable devices are, if anything, increasing in number. so the kernel still needs to provide ways
Be told about the hardware that is actually present. "platform devices" have long been used in this role in the kernel. this article will describe the interface for platform devices; it is meant as needed background material for
Following article on integration with device trees.

Platform drivers

A platform device is representedStruct platform_device, Which, like the rest of the relevant declarations, can be found in<Linux/platform_device.h>. These devices are deemed to be connected to a virtual "platform bus"; drivers of Platform
Devices must thus register themselves as such with the Platform bus code. This registration is done by way ofPlatform_driverStructure:

    struct platform_driver {int (*probe)(struct platform_device *);int (*remove)(struct platform_device *);void (*shutdown)(struct platform_device *);int (*suspend)(struct platform_device *, pm_message_t state);int (*resume)(struct platform_device *);struct device_driver driver;const struct platform_device_id *id_table;    };

At a minimum,Probe ()AndRemove ()Callbacks must be supplied; the other Callbacks have to do with power management and shoshould be provided if they are relevant.

The other thing the driver must provide is a way for the bus code to bind actual devices to the driver; there are two mechanic ISMs which can be used for that purpose. The first isId_tableArgument; the relevant structure is:

    struct platform_device_id {char name[PLATFORM_NAME_SIZE];kernel_ulong_t driver_data;    };

If an ID table is present, the platform bus code will scan through it every time it has to find a driver for a new platform device. if the device's name matches the name in an ID table entry, the device will be given to the driver for management; a pointer
To the matching ID table entry will be made available to the driver as well. as it happens, though, most platform drivers do not provide an ID table at all; they simply provide a name for the driver itself inDriverField. As an example, the i2c-gpio
Driver turns two gpio lines into an I2C bus; it sets itself up as a platform device:

    static struct platform_driver i2c_gpio_driver = {.driver= {.name= "i2c-gpio",.owner= THIS_MODULE,},.probe= i2c_gpio_probe,.remove= __devexit_p(i2c_gpio_remove),    };

With this setup, any device identifying itself"I2c-gpio"Will be bound to this driver; no ID table is needed.

Platform drivers make themselves known to the kernel:

    int platform_driver_register(struct platform_driver *driver);

As soon as this call succeeds, the driver'sProbe ()Function can be called with new devices. That function gets as an argumentPlatform_devicePointer describing the device to be instantiated:

    struct platform_device {const char*name;intid;struct devicedev;u32num_resources;struct resource*resource;const struct platform_device_id*id_entry;/* Others omitted */    };

TheDevStructure can be used in contexts where it is needed-the DMA mapping API, for example. If the device was matched using an ID table entry,Id_entryWill point to the specific entry matched.ResourceArray can be used
To learn where varous resources, including memory-mapped I/O registers and interrupt lines, can be found. there are a number of helper functions for getting data out of the resource array; these include:

    struct resource *platform_get_resource(struct platform_device *pdev,    unsigned int type, unsigned int n);    struct resource *platform_get_resource_byname(struct platform_device *pdev,   unsigned int type, const char *name);    int platform_get_irq(struct platform_device *pdev, unsigned int n);

The"N"Parameter says which resource of that type is desired, with zero indicating the first one. Thus, for example, a driver cocould find its second mmio region:

    r = platform_get_resource(pdev, IORESOURCE_MEM, 1);

AssumingProbe ()Function finds the information it needs, it shocould verify the device's existence to the extent possible, register the "real" devices associated with the platform device, and return zero.

Platform Devices

So now we have a driver for a platform device, but no actual devices yet. as was noted at the beginning, platform devices are inherently not discoverable, so there must be another way to tell the kernel about their existence. that is typically done
The creation of a staticPlatform_deviceStructure providing, at a minimum, a name which is used to find the associated driver. So, for example, a simple (fictional) device might be set up this way:

    static struct resource foomatic_resources[] = {{.start= 0x10000000,.end= 0x10001000,.flags= IORESOURCE_MEM,.name= "io-memory"},{.start= 20,.end= 20,.flags= IORESOURCE_IRQ,.name= "irq",}    };    static struct platform_device my_foomatic = {.name = "foomatic",.resource= foomatic_resources,.num_resources= ARRAY_SIZE(foomatic_resources),    };

These declarations describe"Foomatic"Device with a one-page mmio region startingZero X 10000000And using IRQ 20. The device is made known to the system:

    int platform_device_register(struct platform_device *pdev);

Once both a platform device and an associated driver have been registered, the driver'sProbe ()Function will be called and the device will be instantiated. Registration of device and driver are usually done in different places and can happen in
Either order. A callPlatform_device_unregister ()Can be used to remove a platform device.

Platform Data

The above information is adequate to instantiate a simple platform device, but other devices are more complex than that. even the simple i2c-gpio driver described abve needs two additional pieces of information: the numbers of the gpio lines to be used
I2C clock and data lines. the mechanic used to pass this information is called "Platform Data"; in short, one defines a structure containing the specific information needed and passes it in the platform device'sDev. platform_dataField.

With the i2c-gpio example, a full configuration looks like this:

    #include <linux/i2c-gpio.h>    static struct i2c_gpio_platform_data my_i2c_plat_data = {.scl_pin= 100,.sda_pin= 101,    };    static struct platform_device my_gpio_i2c = {.name= "i2c-gpio",.id= 0,.dev = {.platform_data = &my_i2c_plat_data,}    };

When the driver'sProbe ()Function is called, it can fetchPlatform_dataPointer and use it to obtain the rest of the information it needs.

Not everybody in the kernel community is enamored with platform devices; they seem like a bit of a hack used to encode information about specific hardware platforms into the kernel. additionally, the Platform Data mechanic lacks any sort of type checking;
Drivers must simply assume that they have been passed a structure of the expected type. even so, platform devices are heavily used, and that's unlikely to change, though the means by which they are created and discovered is changing. the way of the future
Appears to be device trees, which will be described in the following article.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.