Linux Platform Device/driver (ii)--platform device and Platform_driver registration process

Source: Internet
Author: User
Tags goto new set

A new set of driver management and registration mechanisms have been introduced from Linux 2.6:P latform_device and Platform_driver.

Most of the device drivers in Linux can use this mechanism, the device is represented by Platform_device, and the driver is registered with Platform_driver.


Compared with the traditional device driver mechanism (registration via Driver_register function), the Linux platform driver Mechanism has the obvious advantage that the platform mechanism registers the resources of the device itself into the kernel, which is unified by the kernel. Management, when using these resources in the driver, apply and use the standard interface provided by platform device. This improves the independence of drive and resource management, and has better portability and security (these standard interfaces are secure).


The use of the Platform mechanism itself is not complex and consists of two parts: Platform_device and Platfrom_driver.

The general process for developing the underlying driver through the Platform mechanism is: definition platform_add_devices---platform_device---Define platform_add_driver-- Register Platform_driver.

1, platform_device registration process:


The first thing to be sure is the resource information of the device, such as the address of the device, interrupt number, etc.

The platform device is described in the 2.6 kernel as a struct platform_device, defined in Kernel\include\linux\platform_device.h,

struct Platform_device {
const char * name;
int id;
struct device dev;
U32 num_resources;
struct resource * resource;
struct platform_device_id *id_entry;
};

An important element of the structure is resource, which is the most important device resource information, defined in Kernel\include\linux\ioport.h,

struct Resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};

The following is an example of the s3c6410 platform's I²c drive:

static struct Platform_device *smdk6410_devices [] __initdata = {
#ifdef Config_smdk6410_sd_ch0
&S3C_DEVICE_HSMMC0,
#endif
#ifdef CONFIG_SMDK6410_SD_CH1
&S3C_DEVICE_HSMMC1,
#endif
&S3C_DEVICE_I2C0,
&S3C_DEVICE_I2C1,
&S3C_DEVICE_FB,
&S3C_DEVICE_USB,
&S3C_DEVICE_USB_HSOTG,
&smdk6410_lcd_powerdev,

    &smdk6410_smsc911x,
}; The
puts one or several device resources together for easy centralized management, with the IIC device Platform_device as follows:
struct platform_device  s3c_device_i2c0   = {
    .name          = " S3C2410-I2C ",
#ifdef config_s3c_dev_i2c1
    .id           = 0,
#else
    .id           =-1,
#endif
    .num_resources       = Array_size (S3c_i2c_resource),
    .resource      =  S3c_i2c_resource,
};


Specific resource are as follows:
static struct resource S3c_i2c_resource [] = {
[0] = {
. Start = S3c_pa_iic,
. end = S3c_pa_iic + Sz_4k-1,
. Flags = Ioresource_mem,
},
[1] = {
. Start = Irq_iic,
. end = IRQ_IIC,
. Flags = IORESOURCE_IRQ,
},
};

This defines two sets of resource, which describe the resources of an i²c device, and the 1th group describes the range of bus addresses occupied by this i²c device, ioresource_mem means that the 1th group describes the resource information of the memory type, and the 2nd group describes the interrupt number of the I²C device. IORESOURCE_IRQ indicates that the 2nd group describes the interrupt resource information. The device driver obtains the corresponding resource information according to flags.


Once you have defined the Platform_device struct, you can call the function platform_add_devices to add the device to the system, and then call Platform_driver_register () to register the device.

The Platform_device of S3C6410-I2C is registered in the Smdk6410_machine_init () function in mach-smdk6410.c when the system is started, and this function is declared as a function call of Arch_initcall , the Arch_initcall priority is higher than module_init. So it will be called before the platform driver is registered. (Detailed reference IMACH-SMDK6410.C)

static void __init smdk6410_machine_init (void)
{
S3c_i2c0_set_platdata (NULL);
S3c_i2c1_set_platdata (NULL);
S3c_fb_set_platdata (&smdk6410_lcd_pdata);

Gpio_request (S3C64XX_GPN (5), "LCD power");
Gpio_request (S3C64XX_GPF (), "LCD power");
Gpio_request (S3C64XX_GPF (), "LCD power");

I2c_register_board_info (0, I2c_devs0, array_size (I2C_DEVS0));
I2c_register_board_info (1, I2C_DEVS1, Array_size (I2C_DEVS1));

Platform_add_devices (Smdk6410_devices, Array_size (smdk6410_devices));
Add multiple devices

}


int platform_add_devices (struct platform_device **devs, int num)
{
int i, ret = 0;

for (i = 0; i < num; i++) {
ret = Platform_device_register (devs[i]);
if (ret) {
while (-i. >= 0)
Platform_device_unregister (Devs[i]);
Break
}
}

return ret;
}


int Platform_device_register (struct platform_device *pdev)
{
Device_initialize (&pdev->dev);
Return Platform_device_add (Pdev);
}


int Platform_device_add (struct platform_device *pdev)
{
int i, ret = 0;

if (!pdev)
Return-einval;

if (!pdev->dev.parent)
Pdev->dev.parent = &platform_bus;

Pdev->dev.bus = &platform_bus_type;

if (pdev->id! =-1)
Dev_set_name (&pdev->dev, "%s.%d", Pdev->name, Pdev->id);//If there is an ID indicating that there are multiple similar devices with Pdev->name and pdev-> ID identifies the device
Else
Dev_set_name (&pdev->dev, "%s", pdev->name);
Otherwise, only use Pdev->name to identify the device

for (i = 0; i < pdev->num_resources; i++) {
struct resource *p, *r = &pdev->resource[i];

if (R->name = = NULL)
R->name = Dev_name (&pdev->dev);

        p = r->parent;
        if (!p) {
             if (Resource_type (r) = = Ioresource_mem)
                  p = &iomem_resource;     as IOMEM resource allocation   
             else if (Resource_type (r) = = Ioresource_io)
                  p = &ioport_resource;     as IO port resource allocation   
        }

         if (P && insert_resource (P, r)) {//Adds new Resource Insert Kernel resource tree
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;PRINTK ( Kern_err
                     "%s:failed to claim Resource%d\n",
                    dev_name (&pdev->dev), i);
            ret =-EBUSY;
            goto failed;
        }
    }

Pr_debug ("Registering Platform Device '%s '). Parent at%s\n ",
Dev_name (&pdev->dev), Dev_name (pdev->dev.parent));

ret = Device_add (&pdev->dev);//Add Device to device tree
if (ret = = 0)
return ret;

Failed
while (---->= 0) {
struct Resource *r = &pdev->resource[i];
unsigned long type = Resource_type (r);

if (type = = Ioresource_mem | | type = = IORESOURCE_IO)
Release_resource (R);
}

return ret;
}

2, Platform_driver registration process:


After the Platform_device registration is complete, it is possible to register the Platform_driver, call the function Platform_driver_register () in the driver initialization function to register platform_driver, note that The name element in the S3C_DEVICE_I2C structure must be the same as the driver.name in the s3c6410_i2c_driver structure, so that when the Platform_driver_register () is registered, all registered The name in Platform_device and the driver.name of the currently registered Platform_driver are compared, and only platfomr_device that find the same name can be registered successfully.

Static struct Platform_driver s3c24xx_i2c_driver = {
    .probe         = S3c24xx_i2c_probe,
    .remove         = S3c24xx_i2c_remove,
    .suspend_late    = S3c24xx_i2c_suspend_late,
    .resume        = S3c24xx_i2c_resume,
    .id_table    = s3c24xx_driver_ids,
     .driver        = {
         .owner    = This_module,
         .name    = "S3C-I2C",
    },
};

static int __init i2c_adap_s3c_init (void)
{
Return Platform_driver_register (&s3c24xx_i2c_driver);//Registered IIC Drive
}

int Platform_driver_register (struct platform_driver *drv)
{
Drv->driver.bus = &platform_bus_type;
if (drv->probe)
Drv->driver.probe = Platform_drv_probe;
if (Drv->remove)
Drv->driver.remove = Platform_drv_remove;
if (Drv->shutdown)
Drv->driver.shutdown = Platform_drv_shutdown;

Return Driver_register (&drv->driver);
}


int Driver_register (struct device_driver *drv)
{
int ret;
struct Device_driver *other;

BUG_ON (!DRV->BUS->P);

if ((drv->bus->probe && drv->probe) | |
(Drv->bus->remove && drv->remove) | |
(Drv->bus->shutdown && Drv->shutdown))
PRINTK (kern_warning "Driver '%s ' needs updating-please use"
"Bus_type methods\n", drv->name);

    other = Driver_find (Drv->name, Drv->bus);//Check if driver already exists
     if (Other) {
        put_driver (other);
&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;PRINTK (kern_err "Error:driver '%s ' is already registered,"
             "aborting...\n", drv->name);
        return-EBUSY;
    }
    //If it does not exist, add the driver to the drive tree.
    ret = Bus_add_driver (DRV);
    if (ret)
        return ret;
    ret = Driver_add_groups (DRV, drv->groups);
    if (ret)
        bus_remove_driver (DRV);
    return ret;
}


int bus_add_driver (struct device_driver *drv)
{
struct Bus_type *bus;
struct Driver_private *priv;
int error = 0;

Bus = Bus_get (Drv->bus);
if (!bus)
Return-einval;

Pr_debug ("Bus: '%s ': Add driver%s\n", Bus->name, Drv->name);

    priv = kzalloc (sizeof (*PRIV), Gfp_kernel);
    if (!priv) {
        error =-ENOMEM;
        goto Out_put_bus;
    }
    klist_init (&priv->klist_devices, NULL, NULL);
    priv->driver = DRV;
    drv->p = Priv;
    priv->kobj.kset = bus->p->drivers_kset;
    error = Kobject_init_and_add (&priv->kobj, &driver_ktype, NULL,
                        "%s", drv->name);
    if (Error)
        goto out_unregister;

if (drv->bus->p->drivers_autoprobe) {
Error = Driver_attach (DRV);
if (Error)
Goto Out_unregister;
}
Klist_add_tail (&priv->knode_bus, &bus->p->klist_drivers);
Module_add_driver (Drv->owner, DRV);

Error = Driver_create_file (DRV, &driver_attr_uevent);
if (Error) {
PRINTK (kern_err "%s:uevent attr (%s) failed\n",
__func__, Drv->name);
}
Error = Driver_add_attrs (bus, DRV);
if (Error) {

PRINTK (Kern_err "%s:driver_add_attrs (%s) failed\n",
__func__, Drv->name);
}
Error = Add_bind_files (DRV);
if (Error) {

PRINTK (Kern_err "%s:add_bind_files (%s) failed\n",
__func__, Drv->name);
}

Kobject_uevent (&priv->kobj, Kobj_add);
return 0;
Out_unregister:
Kfree (DRV->P);
Drv->p = NULL;
Kobject_put (&priv->kobj);
Out_put_bus:
Bus_put (bus);
return error;
}

Linux Platform Device/driver (ii)--platform device and Platform_driver registration process

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.