Linux Driver Platform

Source: Internet
Author: User

Platform device<==> Platform Bus <==> platform driver

Turn from: Platform equipment drive full dialysis Song Baohua http://blog.csdn.net/21cnbao/article/details/5615421

1.1 Platform bus, device and driver

In the Linux 2.6 device driver model, the bus, device, and drive 3 entities are concerned, and the buses bind the device and the driver. Every time the system registers a device, it will look for the matching driver, instead, when the system registers a driver, it will look for the matching device, and the matching is done by the bus.

A realistic Linux device and driver usually need to hook up on a bus, for itself is attached to the PCI, USB, I2 C, SPI and other devices, this is not a problem, but in the embedded system, SOC system integrated independent peripheral Controller, The peripherals attached to the SOC memory space are not attached to such a bus. Based on this background, Linux invented a virtual bus called Platform Bus, the corresponding device is called Platform_device, and the driver becomes platform_driver.

Note that the so-called platform_device is not a parallel concept with character devices, block devices, and network devices, but rather an additional means provided by the Linux system, for example, in the S3C6410 processor, the internally integrated I2 C, RTC, SPI, LCD, Controllers such as watchdog are summarized as Platform_device, which are themselves character devices. The definition of the Platform_device struct is shown in Listing 1.

Code Listing 1 Platform_device struct

1 struct Platform_device {

2 const char * name;/* device name */

3 u32 ID;

4 struct device dev;

5 Number of resources used by U32 num_resources;/* equipment * *

6 struct Resource * resource;/* resources */

7};

Platform_driver This struct contains the probe (), remove (), shutdown (), suspend (), resume () functions, which are often required by the driver, such as Listing 2.

Code Listing 2 Platform_driver struct

1 struct Platform_driver {

2 int (*probe) (struct platform_device *);

3 int (*remove) (struct platform_device *);

4 void (*shutdown) (struct platform_device *);

5 int (*suspend) (struct Platform_device *, pm_message_t State);

6 int (*suspend_late) (struct Platform_device *, pm_message_t State);

7 int (*resume_early) (struct platform_device *);

8 int (*resume) (struct platform_device *);

9 struct Pm_ext_ops *pm;

Ten struct device_driver driver;

11};

A Bus_type instance platform_bus_type is defined for the platform bus in the system, which is defined as code listing 15.3.

Code Listing 15.3 Bus_type instance of platform bus Platform_bus_type

1 struct Bus_type Platform_bus_type = {

2. Name = "Platform",

3. Dev_attrs = Platform_dev_attrs,

4. Match = Platform_match,

5. uevent = Platform_uevent,

6. PM = platform_pm_ops_ptr,

7};

8 EXPORT_SYMBOL_GPL (Platform_bus_type);

The focus here is on the match () member function, which shows how Platform_device and Platform_driver match, as shown in Listing 4.

The match () member function for code Listing 4 Platform_bus_type

1 static int platform_match (struct device *dev, struct device_driver *drv)

2 {

3 struct Platform_device *pdev;

4

5 Pdev = container_of (dev, struct platform_device, dev);

6 return (strncmp (Pdev->name, drv->name, bus_id_size) = = 0);

7}

As you can see from line 6th of Listing 4, matching platform_device and platform_driver mainly depends on whether the name field is the same.

The definition of Platform_device is usually implemented in the BSP Board file, in the board file, the Platform_device is summed up as an array, which is eventually registered through the Platform_add_devices () function. The Platform_add_devices () function can add a platform device to the system, and the prototype of the function is:

int platform_add_devices (struct platform_device **devs, int num);

The first parameter of the function is a pointer to the platform device array, the second parameter is the number of platform devices, which internally calls the Platform_device_register () function to register a single platform device.

1.2 Globalfifo as a platform device

Now we hook up the Globalfifo drive in the previous section to the platform bus, to complete 2 jobs:

1. Migrate the Globalfifo to the platform driver.

2. Add Globalfifo to the platform device in the board file.

To complete the work of porting Globalfifo to platform drivers, a layer of platform_driver is required in the original GLOBALFIFO character device driver, such as listing 5. Note that after doing this work, and did not change the nature of the Globalfifo is the character device, just hook it up to the platform bus.

Listing 5 adds platform_driver to Globalfifo

1 static int __devinit globalfifo_probe (struct platform_device *pdev)

2 {

3 int ret;

4 dev_t Devno = MKDEV (globalfifo_major, 0);

5

6/* Apply for device number */

7 if (globalfifo_major)

8 ret = register_chrdev_region (Devno, 1, "Globalfifo");

9 Else {/* Dynamic request device number */

Ten ret = alloc_chrdev_region (&devno, 0, 1, "Globalfifo");

One globalfifo_major = major (Devno);

12}

if (Ret < 0)

return ret;

15/* Dynamic request for device structure memory */

GLOBALFIFO_DEVP = kmalloc (sizeof (struct globalfifo_dev), gfp_kernel);

if (!GLOBALFIFO_DEVP) {/* request failed */

ret =-Enomem;

Goto Fail_malloc;

20}

21st

memset (GLOBALFIFO_DEVP, 0, sizeof (struct globalfifo_dev));

23

Globalfifo_setup_cdev (GLOBALFIFO_DEVP, 0);

25

Init_mutex (&globalfifo_devp->sem); /* Initialize semaphore */

Init_waitqueue_head (&globalfifo_devp->r_wait); /* Initialize read wait queue header */

Init_waitqueue_head (&globalfifo_devp->w_wait); /* Initialize the Write wait queue header */

29

return 0;

31

Fail_malloc:unregister_chrdev_region (Devno, 1);

return ret;

34}

35

$ static int __devexit globalfifo_remove (struct platform_device *pdev)

37 {

Cdev_del (&globalfifo_devp->cdev); /* Unregister cdev*/

Kfree (GLOBALFIFO_DEVP); /* release device structure in vivo */

Unregister_chrdev_region (MKDEV (globalfifo_major, 0), 1); /* Release the device number */

return 0;

42}

43

static struct Platform_driver Globalfifo_device_driver = {

Probe = Globalfifo_probe,

remove = __devexit_p (Globalfifo_remove),

Driver = {

. Name = "Globalfifo",

. Owner = This_module,

50}

51};

52

__init static int globalfifo_init (void)

54 {

Return Platform_driver_register (&globalfifo_device_driver);

56}

57

__exit static void Globalfifo_exit (void)

59 {

Platform_driver_unregister (&globalfifo_device_driver);

61}

62

Module_init (Globalfifo_init);

Module_exit (Globalfifo_exit);

In Listing 5, the module load and unload functions are only registered and unregistered through the Platform_driver_register (), Platform_driver_unregister () functions, Platform_driver The original registration and logoff of the character device has been transferred to Platform_driver's probe () and remove () member functions.

The parts not listed in Listing 5 are the same as the original Globalfifo drivers, and are member functions that implement file_operations as the character device driver core.

In order to complete the work of adding globalfifo to the platform device in the board file, you need to add the appropriate code in the Board file (for LDD6410, for arch/arm/mach-s3c6410/mach-ldd6410.c), such as listing 6.

Code Listing 6 Globalfifo corresponds to Platform_device

1 static struct Platform_device Globalfifo_device = {

2. Name = "Globalfifo",

3. id =-1,

4};

for the LDD6410 Development Board, in order to complete the above Globalfifo_device this platform_device registration, only need to put its address into the arch/arm/mach-s3c6410/ An array of ldd6410_devices defined in mach-ldd6410.c , such as:

static struct Platform_device *ldd6410_devices[] __initdata = {

+ & Globalfifo_device,

#ifdef CONFIG_FB_S3C_V2

&S3C_DEVICE_FB,

#endif

&S3C_DEVICE_HSMMC0,

...

}

After loading the LDD6410 driver, the following nodes are found in the SYSFS:

/sys/bus/platform/devices/globalfifo/

/sys/devices/platform/globalfifo/

Note that the 48th line of code Listing 5 and line 2nd of code Listing 6, Platform_device and Platform_driver, are identical, which is the premise of matching the two.

1.3 Platform device resources and data

Note the 5th to 6th line of the Platform_device struct definition in code Listing 1, which describes the Platform_device resource, which is described by the resource struct itself, as defined in Listing 7.

Code Listing 7 resouce struct definition

1 struct Resource {

2 resource_size_t start;

3 resource_size_t end;

4 const char *name;

5 unsigned long flags;

6 struct resource *parent, *sibling, *child;

7};

we usually care about the 3 fields of start, end, and flags, which indicate the start value, end value, and type of the resource, flags can be ioresource_io, Ioresource_mem, IORESOURCE_IRQ, IORESOURCE_DMA and so on. The meaning of start and end changes with flags, such as when flags is IORESOURCE_MEM, start and end represent the starting and ending addresses of the memory occupied by that Platform_device, respectively When flags is IORESOURCE_IRQ, start and end respectively represent the starting and ending values of the interrupt number used by the Platform_device, and if only 1 interrupt numbers are used, the start and end values are the same. For resources of the same type, you can define 2 Ioresource_mem resources, for example, if a device occupies 2 memory areas.

The definition of resource is also usually carried out in the BSP board file, and in the specific device driver through the Platform_get_resource () such API to obtain , the prototype of this API is:

struct resource *platform_get_resource (struct platform_device *, unsigned int, unsigned int);

For example, in the board file of the LDD6410 Development Board, the following resouce are defined for the DM9000 NIC:

static struct resource ldd6410_dm9000_resource[] = {

[0] = {

. Start = 0x18000000,

. end = 0x18000000 + 3,

. Flags = Ioresource_mem

},

[1] = {

. Start = 0x18000000 + 0x4,

. end = 0x18000000 + 0x7,

. Flags = Ioresource_mem

},

[2] = {

. Start = Irq_eint (7),

. End = Irq_eint (7),

. Flags = IORESOURCE_IRQ | Ioresource_irq_highlevel,

}

};

In the DM9000 network card driver is the following way to get these 3 resources:

Db->addr_res = Platform_get_resource (Pdev, Ioresource_mem, 0);

Db->data_res = Platform_get_resource (Pdev, Ioresource_mem, 1);

Db->irq_res = Platform_get_resource (Pdev, IORESOURCE_IRQ, 0);

For IRQ, Platform_get_resource () also has an encapsulated variant PLATFORM_GET_IRQ (), which is prototyped as:

int Platform_get_irq (struct platform_device *dev, unsigned int num);

It actually calls "Platform_get_resource (Dev, Ioresource_irq, num);".

In addition to the device can be defined in the BSP resources, but also can attach some data information, because the hardware description of the device in addition to interrupts, memory, DMA channel, there may be some configuration information, and these configuration information is also dependent on the board, not suitable for directly placed in the device driver itself, therefore, Platform also provides support for Platform_data. Platform_data form is custom , such as for the DM9000 NIC, Platform_data is a dm9000_plat_data structure, we can be MAC address, bus width, There is no EEPROM information put into Platform_data:

static struct Dm9000_plat_data Ldd6410_dm9000_platdata = {

. Flags = Dm9000_platf_16bitonly | Dm9000_platf_no_eeprom,

. dev_addr = {0x0, 0x16, 0xd4, 0x9f, 0xed, 0xa4},

};

static struct Platform_device ldd6410_dm9000 = {

. Name = "dm9000",

. id = 0,

. num_resources = Array_size (Ldd6410_dm9000_resource),

. resource = Ldd6410_dm9000_resource,

. Dev = {

. Platform_data = &ldd6410_dm9000_platdata,

}

};

And in the driver of DM9000 network card, get the platform_data by the following way:

struct Dm9000_plat_data *pdata = pdev->dev.platform_data;

Where Pdev is a pointer to Platform_device.

The above analysis shows that the concept of introducing platform into device drivers has at least the following 2 major benefits:

1. The device is hooked up to a bus, so it conforms to the Linux 2.6 device model. As a result, the supporting SYSFS nodes and equipment power management are possible.

2. Isolate the BSP and driver. In the BSP definition of the platform devices and equipment used by the resources, device configuration information, and in the driver, only through the general API to obtain resources and data, the board related code and drive code separation, so that the driver has better scalability and cross-platform.

Linux Driver Platform

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.