Driver model in linux2.6 kernel from serial port-driven porting platform device & platform driver "Turn"

Source: Internet
Author: User

Transferred from: http://blog.csdn.net/bonnshore/article/details/7979705

Written in the previous words:

Bloggers opened a new personal site: You can also see this article here, click to open the link

This article is a blogger learning Linux drive transplant after a full two weeks through the access to data and some of their own observations to do some of the records, designed as a future review materials, because bloggers have not much experience in the text may appear some fallacy, hope to see the enthusiastic friend can make bricks.

In front of me already mentioned I do the sc16c550 serial port transplant, originally is no technical difficulty, but for new people to understand the structure of the kernel code and the principle of porting is the first, so in the work to do some records.

gap//////////////////////////////////////////////////////

In the Linux-2.6 16c550 serial port Driver migration article, the static struct Platform_device sc16550_device structure is configured, The device registration interface function in the platform bus mechanism using the Linux kernel model: platform_device_register (&sc16550_device); mount the Sc16550_device device to platform The bus. As mentioned above, the driver is using exactly 8250来 to drive, so when the 8250.c driver is init, the Platform_driver_register (&serial8250_isa_driver) is called; The function is to load the driver onto the platform bus,

The following is a detailed configuration of the important structure of the Sc16550_device:

static struct Plat_serial8250_port sc16550_data[] = {
. mapbase = Sc16550_uart_base,//flags is automatically mapped using ioremap,8250 driver mapbase
. IRQ = SC16550_UART_IRQ,
. UARTCLK = Sc16550_uart_baud * 16,
. Iotype = Upio_mem,
. Flags = upf_boot_autoconf |
Upf_skip_test | Upf_ioremap,
. Regshift = 0,
};
static struct Platform_device Sc16550_device = {
. Name = "Serial8250",
. id = plat8250_dev_platform,
. Dev = {. Platform_data = Sc16550_data,},
};

The serial8250_isa_driver structure is defined as:

static struct Platform_driver Serial8250_isa_driver = {
. Probe = Serial8250_probe,
. remove = __devexit_p (Serial8250_remove),
. Suspend = Serial8250_suspend,
. Resume = Serial8250_resume,
. Driver = {
. Name = "Serial8250",
. Owner = This_module,
},
};

So how does the Sc16550_device device and the Serial8250_isa_driver drive specifically load into the bus, and how do they match Joseph? So that they can unite with the outside?

Let's dig into it today ...

When the device is hooked up to the bus, it matches all the drivers on the bus (matched with bus_type.match), and if the match succeeds, the Bus_ is called Type.probe or Driver.probe initializes the device and hooks it on the bus if the match fails, it simply hooks the device to the bus.

When the drive is hooked up to the bus, it matches all devices on the bus (matched with bus_type.match), and if the match succeeds, the Bus_ is called Type.probe or Driver.probe initializes the device and hooks it to the bus if the match fails, it simply hooks the driver to the bus.

Now we can't judge which one of our sc16550_device and serial8250_isa_driver is mounted on the bus first. However, this does not affect our understanding of the entire Linux device model.

Since the Platform_bus_type bus is actually registered by Kenrel, it is necessary to comment on the definition of Platform_bus_type, whose   definition is as follows:  
struct bus_type Platform_bus_type = { 
       .name         = "platform",       //bus name will generate/sys/bus/platform   directory  

      /* This property file will be generated in all platform_bus_type types of device directories, with the file name "Modalias" */ 
       .dev_attrs    = platform_dev_attrs,   
       .match        = Platform _match,   //for Drive-to-device matching routines  
       .uevent       = plat form_uevent,  //   is used for output environment variables, related   to property file "Uevent";
       .pm           = platform_pm_ops_ptr,//   power management  
}; 

Code, the Platform_bus_type is registered to the bus module via Bus_register (&platform_bus_type).

We continue to call platform_add_devices or Platform_device_register during system initialization to register the platform device (Platform devices) in the platform bus (platform_bus_type ), the Association of Platform-driven (platform driver) with platform devices (platform device) is implemented in platform device or driver_register, which is typically called during the driver initialization process. Through these three steps, the platform bus, the device, the driver is connected.

Let's look at the whole process in detail.

First, let's take a look at platform_device_register ...

We know that when the system boot up, system initialization calls Platform_device_register (), and it calls Device_initialize () and Platform_device_add (). The following resolves device_initialize () and Platform_device_add () two routines, which are defined in drivers/base/core.c and DRIVERS/BASE/PLATFORM.C respectively.

Device_initialize (the code is as follows:
void device_initialize (struct device *dev)
{
Dev->kobj.kset = Devices_kset; Set the Kset container to which it points


Kobject_init (&dev->kobj, &device_ktype); Initialize the kobj and pass the Device_ktype to it


Klist_init (&dev->klist_children, Klist_children_get,


Klist_children_put); Preliminary examination of Klist


Init_list_head (&dev->dma_pools);


Init_mutex (&dev->sem);


Spin_lock_init (&dev->devres_lock);


Init_list_head (&dev->devres_head);


Device_init_wakeup (Dev, 0);


Device_pm_init (Dev); Preliminary management of power supply


Set_dev_node (Dev,-1);
}

In the code:
1. Devices_kset is the kset of all Dev, that is, all Dev is linked under the Kset, which is passed Kset_create_and_add ("devices") in the Devices_init () of the preliminary routines, & Device_uevent_ops, NULL) to create. Because of the parameter parent=null, the/sys/devices directory is generated. This shows that the following kobj,kset structure contains a kobj, a kobj generates a directory, which is the "Devices" directory, generated by invoking the kobject_add_internal () routine. So from dev->kobj.kset = Devices_kset, the dev.kobj is added to the Devices_kset container, and the kobj belongs to a specific kset. The relationship between Kset,kobj,ktype,kref can be a reference book LDD3
In the 14th chapter, on page No. 370 there is a diagram explaining the relationship between Kobj and Kset (English version).
2. Kobject_init (&dev->kobj, &device_ktype) is used to initialize parameters of variables in dev->kobj, such as Ktype, Kref, entry, and state*. The Devices_init () routine also calls the Kobject_create_and_add () routine to generate the/sys/dev,/sys/dev/block, and/sys/dev/char directories.
3. Other initialization.

The following analysis Platform_device_add:

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;

As you can see, the platform device's parent device is generally platform_bus, so the registered platform devices appear under/sys/devices/platform_bus

Pdev->dev.bus = &platform_bus_type;

Hang onto the platform bus

if (pdev->id! =-1)

Dev_set_name (&pdev->dev, "%s.%d", Pdev->name, Pdev->id);

Else

Dev_set_name (&pdev->dev, "%s", pdev->name);

Set the device name, which corresponds to the name under/sys/devices/platform_bus

for (i = 0; i < pdev->num_resources; i++) {//below the system resources occupied by the operating device

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;

else if (Resource_type (r) = = Ioresource_io)

p = &ioport_resource;

}

if (P && insert_resource (P, r)) {

PRINTK (Kern_err

"%s:failed to claim resource%d\n",

Dev_name (&pdev->dev), i);

ret =-ebusy;

Goto failed;

}

}

The main is to traverse the resources occupied by the device, find the corresponding parent resources, if not defined, then according to the type of resources, respectively, given Iomem_resource and Ioport_resource, and then call Insert_resource Insert Resources.

In this way, the resources of the system form a tree-shaped data structure, which facilitates the management of the system.

Pr_debug ("Registering Platform Device '%s '). Parent at%s\n ",

Dev_name (&pdev->dev), Dev_name (pdev->dev.parent));

ret = Device_add (&pdev->dev);

Registering in the device model

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;

}

This completes the registration of the device to the bus. And then I'll look at the driver to the bus mount process.

This process is a very complex process, the period involved in the call of layer functions, the following gives a specific process:

Platform_driver_register ()->driver_register ()->bus_add_driver ()->driver_attach ()->bus_for_each_dev () for each device hanging on the virtual platform Bus __driver_attach ()->driver_probe_device ()->drv->bus->match () ==platform_ Match (), compare strncmp (Pdev->name, Drv->name, bus_id_size), and call Platform_drv_probe () if it matches->driver->probe () If probe succeeds, bind the device to that drive.

There are two places in the process we need to be aware that we have a lot of people in mind, that is match () and probe (), one is responsible for matching a successful binding device to the port assignment.

Let's start with the match process:

It is also generally mentioned that the so-called match is the driver successfully registered in the bus after the match with the bus mounted on the matching, the specific implementation is in Driver_attach () the Bus_for_each_dev () function is responsible for the driver and the device to match each, This function has a parameter function finally transferred to the __driver_attach to achieve the specific matching process, where the pointer to the match member is called Paltform_match (), of course, this is to be based on, we do not forget the Platform_bus_ The Platform_bus_type struct in which the type bus is registered by Kenrel, the members of which have one entry for. Match=platform_match, yes, the Paltform_match () function is defined in drivers/base/ The PLATFORM.C. Interested friends can check the source code, very simple only 3 lines, it is worth mentioning that there is a CONTAINER_OF macro definition function, in the kernel code of this function with a lot of, you can focus on this function can be returned to the function of the internal parameters of the structure of the address The first is a simple strcmp function that compares the drive to the name stored in the device. After the match succeeds, the execution continues down to probe.

Why execute probe, this is because the driver finally found the right device, it is necessary to put some of our initialization information on the device to the driver standard processing, of course, after this behavior and our drive model does not have much relationship. Of course, continue to focus on my friends in the future should see the next section. How does the system know which driver the probe function is calling probe? It's down here ...

Probe the specific invocation of the process, we first look at the following structure:

static struct Platform_driver Serial8250_isa_driver = {
. Probe = Serial8250_probe,
. remove = __devexit_p (Serial8250_remove),
. Suspend = Serial8250_suspend,
. Resume = Serial8250_resume,
. Driver = {
. Name = "Serial8250",
. Owner = This_module,
},
};

Probe= Serial8250_probe This sentence is the focus, from which we can clearly see that we are in the driver registration mounted to the bus when the call of Platform_driver_register () is passed the parameter is serial8250_ Isa_driver structure, so Serial8250_probe () is called when the system executes to Driver->probe ().

So far, the system-driven model in the process of serial device driver loading is over, the behavior of the platform bus is over, and the next action is the specific driver. In the back of the blog I will also write some user space on the drive to read and write operations, such operations are how to layer calls, how to implement the underlying operation of the drive.

Driver model in linux2.6 kernel from serial port-driven porting platform device & platform driver "Turn"

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.