Linux platform device driver

Source: Internet
Author: User

 

Platform-related fields are often seen in device drivers and distributed across multiple corners of the driver. This is also an important mechanism in the 2.6 kernel, it will be helpful for analyzing drivers in the future: In the linux2.6 device model, the three entities of bus, device, and driver are concerned, and the bus binds the device and driver, when the system registers a device, it looks for a matching driver. On the contrary, when the system registers a driver, it searches for the matching device, and the matching is done by the bus.

A real Linux Device and driver usually need to be mounted on a bus. This is naturally not a problem for devices that depend on PCI, USB, I2C, SPI, etc, however, in an embedded system, the independent peripheral controller integrated in the SoC system and peripherals attached to the SOC memory space are not attached to this type of bus. Based on this background, Linux invented a virtual bus called platform bus. The independent peripheral units (such as LCD, RTC, and wdt) integrated in the SoC system are processed as platform devices, and they are self-contained Devices.

From the Linux kernel, a new driver management and registration mechanism is introduced: platform_device and platform_driver. Most device drivers in Linux can use this mechanism. The device is represented by platform_device, and the driver is registered by platform_driver.

(1) platform Equipment

In a Linux device driver, a type of device is called a "platform device". Generally, the independent peripheral units integrated in the SoC system are processed as platform devices. The platform device is described using the platform_device struct. In kernel 2.6.32.2, It is defined in include/Linux/platform_devide.h. The struct is as follows:

[CPP]
View plaincopyprint?
  1. Struct platform_device {
  2. Const char * Name;
  3. Int ID;
  4. Struct device dev;
  5. U32 num_resources;
  6. Struct resource * resource; // The resource used by the device
  7. Struct platform_device_id * id_entry;
  8. /* Arch specific additions */
  9. Struct pdev_archdata archdata;
  10. };
  11. Struct resource // In include/Linux/ioport. h
  12. {
  13. Resource_size_t start;
  14. Resource_size_t end;
  15. Const char * Name;
  16. Unsigned long flags;
  17. Struct resource * parent, * sibling, * child;
  18. };

Struct platform_device {<br/> const char * Name; <br/> int ID; <br/> struct device dev; <br/> u32 num_resources; <br/> struct resource * resource; // The resource used by the device </P> <p> struct platform_device_id * id_entry; </P> <p>/* arch specific additions */<br/> struct pdev_archdata archdata; <br/> }; <br/> struct resource // located in include/Linux/ioport. h <br/>{< br/> resource_size_t start; <br/> resource_size_t end; <br/> const char * Name; <br/> unsigned long flags; <br/> struct resource * parent, * sibling, * child; <br/> };
We usually care about the start, end, and flags fields, respectively indicating the start value, end value, and type of the resource. flags can be ioresource_io, ioresource_mem, ioresource_irq, ioresource_dma, etc.

Many platform devices are defined in Linux, such as in: ARCH/ARM/plat-s3c24xx/Devs. C, the following is the definition of the watchdog platform device:

[CPP]
View plaincopyprint?
  1. Static struct resource initi_wdt_resource [] = {
  2. [0] = {// IO port Resource
  3. . Start = s3c24xx_pa_watchdog,
  4. . End = s3c24xx_pa_watchdog + s3c24xx_sz_watchdog-1,
  5. . Flags = ioresource_mem,
  6. },
  7. [1] = {// resource interruption
  8. . Start = irq_wdt,
  9. . End = irq_wdt,
  10. . Flags = ioresource_irq,
  11. }
  12. };
  13. Struct platform_device initi_device_wdt = {
  14. . Name = "s3c2410-wdt ",
  15. . ID =-1,
  16. . Num_resources = array_size (maid ),
  17. . Resource = maid,
  18. };
  19. Export_symbol (initi_device_wdt );

Static struct resource maid [] = {<br/> [0] = {// IO port resource <br/>. start = s3c24xx_pa_watchdog, <br/>. end = s3c24xx_pa_watchdog + s3c24xx_sz_watchdog-1, <br/>. flags = ioresource_mem, <br/>}, <br/> [1] ={// resource interruption <br/>. start = irq_wdt, <br/>. end = irq_wdt, <br/>. flags = ioresource_irq, <br/>}< br/>}; <br/> struct platform_device initi_device_wdt ={< br/>. name = "s3c2410-wdt", <br/>. id =-1, <br/>. num_resources = array_size (maid), <br/>. resource = jx_wdt_resource, <br/>}; <br/> export_symbol (cloud_device_wdt );

After the platform device is defined, how can it be used in the system? In ARCH/ARM/mach-s3c2440/mach-smdk2440.c, this arm2440 platform's system entry file, the system initialization function smdk2440_machine_init uses the platform_add_devices function to add a series of platform devices to the system.

[CPP]
View plaincopyprint?
  1. Static struct platform_device * smdk2440_devices [] _ initdata = {
  2. & Initi_device_usb,
  3. & Amp; cloud_device_ LCD,
  4. & Amp; cloud_device_wdt,
  5. & Amp; cloud_device_i2c0,
  6. & Amp; cloud_device_iis,
  7. };
  8. Static void _ init smdk2440_machine_init (void)
  9. {
  10. S3c24xx_fb_set_platdata (& smdk2440_fb_info );
  11. Initi_i2c0_set_platdata (null );
  12. Platform_add_devices (smdk2440_devices, array_size (smdk2440_devices ));
  13. Smdk_machine_init ();
  14. }

Static struct platform_device * smdk2440_devices [] _ initdata ={< br/> & cloud_device_usb, <br/> & cloud_device_ LCD, <br/> & cloud_device_wdt, <br/> & gt, <br/> & jx_device_iis, <br/>}; </P> <p> static void _ init smdk2440_machine_init (void) <br/>{< br/> devices (& smdk2440_fb_info); <br/> devices (null); <br/> platform_add_devices (smdk2440_devices, array_size (smdk2440_devices )); <br/> smdk_machine_init (); <br/>}
(2) platform-driven

In Linux, the platform driver platform_driver is defined for the platform device. The platform driver struct defines interface functions such as probe, remove, suspend, and resume to implement the driver. Defined in include/Linux/platform_devide.h.

[CPP]
View plaincopyprint?
  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 (* resume) (struct platform_device *);
  7. Struct device_driver driver;
  8. Struct platform_device_id * id_table;
  9. };

Struct platform_driver {<br/> int (* probe) (struct platform_device *); <br/> int (* remove) (struct platform_device *); <br/> void (* shutdown) (struct platform_device *); <br/> int (* suspend) (struct platform_device *, pm_message_t State ); <br/> int (* resume) (struct platform_device *); <br/> struct device_driver driver; <br/> struct platform_device_id * id_table; <br/> };
The following is the platform_driverde initialization of watchdog. The owner and name variables are initialized in the driver struct. The name must be the same as the name of the platform device, so that the platform device and the platform driver are associated.

[CPP]
View plaincopyprint?
  1. Static struct platform_driver s3c2410wdt_driver = {
  2. . Probe = s3c2410wdt_probe,
  3. . Remove = _ devexit_p (s3c2410wdt_remove ),
  4. . Shutdown = s3c2410wdt_shutdown,
  5. . Suspend = s3c2410wdt_suspend,
  6. . Resume = s3c2410wdt_resume,
  7. . Driver = {
  8. . Owner = this_module,
  9. . Name = "s3c2410-wdt ",
  10. },
  11. };

Static struct platform_driver s3c2410wdt_driver ={< br/>. probe = s3c2410wdt_probe, <br/>. remove = _ devexit_p (s3c2410wdt_remove), <br/>. shutdown = s3c2410wdt_shutdown, <br/>. suspend = s3c2410wdt_suspend, <br/>. resume = s3c2410wdt_resume, <br/>. driver ={< br/>. owner = this_module, <br/>. name = "s3c2410-wdt", <br/>}, <br/> };
How to Implement the driver? In the macro-real platform driver registration that initializes module_init (), the platform driver is deregistered in module_exit.

[CPP]
View plaincopyprint?
  1. Static int _ init watchdog_init (void)
  2. {
  3. Printk (banner );
  4. Return platform_driver_register (& s3c2410wdt_driver );
  5. }
  6. Static void _ exit watchdog_exit (void)
  7. {
  8. Platform_driver_unregister (& s3c2410wdt_driver );
  9. }
  10. Module_init (watchdog_init );
  11. Module_exit (watchdog_exit );

Static int _ init watchdog_init (void) <br/>{< br/> printk (banner); <br/> return platform_driver_register (& s3c2410wdt_driver ); <br/>}< br/> static void _ exit watchdog_exit (void) <br/>{< br/> platform_driver_unregister (& s3c2410wdt_driver ); <br/>}</P> <p> module_init (watchdog_init); <br/> module_exit (watchdog_exit );

Related 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.