Platform Bus driven design
1. Overview of the platform bus (one of the most important bus drivers)
The platform bus (Platform bus) is a virtual bus joined by the linux2.6 kernel, which
The advantage is that the bus model is used to manage the device and the drive, and the module of the bus
The device and drive are managed, which improves the portability of the program.
Develop device-driven processes through the platform bus mechanism:
Define platform_device-> Register platform_device-> definition
Platform_drivre-> Registration Platform_driver
Screen bus driver and device matching mechanism: kernel generation
In the code/DRVIVER/BASE:PLATFORM.C, it is mainly used to realize the platform bus.
struct Bus_type Platform_bus_type = {
. Name= "Platform",
. dev_attrs= Platform_dev_attrs,
. match= Platform_match,
. uevent= Platform_uevent,
. pm= &platform_dev_pm_ops,
};
Let's take a look at how the platform bus matches.
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);
/* Attempt an of style match first */
if (Of_driver_match_device (Dev, DRV))
return 1;
/* Then try to match against the ID table */
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);
}
We can see that it has a total of two matching rules-"
One is that if the driver has a id_table-> then the drive and the device will press id_table.
The. The other is to match the driver and device name (this is the main
)。
2. Platform Equipment
2.1 Platform Device Description
struct Platform_device {
Const char* name;//Device Name
intid;//device number, use with device name
struct Devicedev;
U32num_resources;
struct resource* resource;//device resources (including registers
Base address, interrupt number,)
const struct Platform_device_id*id_entry;
/* MFD cell pointer */
struct Mfd_cell *mfd_cell;
/* Arch Specific additions */
struct Pdev_archdataarchdata;
};
Structure of struct resource:
struct Resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;//type of resource
struct resource *parent, *sibling, *child;
};
2.2. Registering Platform Devices
int Platform_device_register (struct platform_device *pdev)
2.3. Unregister the Platform device
void Platform_device_unregister (struct platform_device
*pdev)
3. Platform-driven
3.1 Platform Driver description
struct Platform_driver {
Int (*probe) (struct platform_device *);//Match succeeded
will be called when the
Int (*remove) (struct platform_device *);//device is moved
is called when it is removed.
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;
};
3.2. Platform-driven registration
int Platform_driver_register (struct platform_driver *drv)
3.3. Platform-driven logoff
void Platform_driver_unregister (struct platform_driver
*DRV)
Let's complete a button registration platform program
Touch key_dev.c
chmod 777 KEY_DEV.C
#include <linux/init.d>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
Module_license ("GPL");
#define GPFCON 0x56000050//Key base Address
struct resource key_resource[] = {
[0] = {//Key resource
. Start = Gpfcon,
. end = Gpfcon+8,
. Flags = ioresource_mem,//Memory Resources
},
[1] = {//interrupt number
. Start = Irq_eint0,
. end = irq_eint2,//Use these two macros to include a header file interrupt
. Flags = ioresource_irq,//Interrupt Resource
};
};
Defining Platform Devices
struct Platform_device Key_device =
{
. Name = "My-key",
. id = 0,
. Num_resource = 2,
. resource = Key_resource,
}
int Keydev_init ()
{
Platform_device_register (&key_device);
}
void Keydev_exit ()
{
Platform_driver_unregister (&key_device);
}
Module_init (Keydev_init);
Module_exit (Keydev_exit);
CP Key_dev.ko Rootfs
Insmod Key_dev.ko
ls/sys/bus/platform/device/my-key.o
Next is the platform driver: the platform-driven overview is described above.
Copy the previously written key driver.
MV Key.c KEY_DRV.C
Vim Makefile +KEY_DRV.O
#include <linux/module.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/platform_device.h>
Module_license ("GPL");
struct Work_struct *work;
struct Timer_list buttons_timer;
unsigned int key_num = 0;
wait_queue_head_t key_q;
struct resource *res;
struct resource *res_irq;
unsigned int *key_base;
void Work_func (struct work_struct *work)
{
Mod_timer (&buttons_timer, Jiffies + (HZ/10));
}
void Buttons_timer_function (unsigned Long data)
{
unsigned int key_val;
Key_val = READW (key_base+1) &0x1; Plastic +1=+4
if (Key_val = = 0)
Key_num = 4;
Key_val = READW (key_base+1) &0x4;
if (Key_val = = 0)
Key_num = 3;
WAKE_UP (&KEY_Q);
}
irqreturn_t key_int (int irq, void *dev_id)
{
1. Detects if a key break has occurred
2. Clears the key interrupt that has occurred
3. Submit the lower half of the
Schedule_work (work);
return 0;
return irq_handled;
}
void Key_hw_init ()
{
unsigned short data;
data = READW (key_base);//Read virtual address directly
Data &= ~0b110011;
Data |= 0b100010;
Writew (data,key_base);
}
int Key_open (struct inode *node,struct file *filp)
{
return 0;
}
ssize_t key_read (struct file *filp, char __user *buf,
size_t size, loff_t *pos)
{
Wait_event (Key_q,key_num);
Copy_to_user (buf, &key_num, 4);
Key_num = 0;
return 4;
}
struct File_operations key_fops =
{
. open = Key_open,
. Read = Key_read,
};
struct Miscdevice Key_miscdev = {
. minor = 200,
. Name = "Key",
. FoPs = &key_fops,
};
int key_probe (struct platform_device *pdev)
{
int ret,size;
Registering hybrid devices
ret = Misc_register (&key_miscdev);
if (ret!=0)
PRINTK ("register fail!\n");
Get Resources
RES_IRQ = Platform_get_resource (Pdev, IORESOURCE_IRQ,
0);
Registering an interrupt handler
REQUEST_IRQ (res_irq-
>start,key_int,irqf_trigger_falling, "Key", (void *) 4);
REQUEST_IRQ (res_irq-
>end,key_int,irqf_trigger_falling, "Key", (void *) 3);
Keystroke initialization
res = Platform_get_resource (Pdev, Ioresource_mem, 0);
Size = (Res->end-res->start) + 1;//The length of the resource to be mapped
Key_base = Ioremap (res->start, size);
Key_hw_init ();
//. Create a job
Work = Kmalloc (sizeof (struct work_struct), gfp_kernel);
Init_work (work, work_func);
/* Initialize Timer */
Init_timer (&buttons_timer);
Buttons_timer.function = buttons_timer_function;
/* Register a timer with the kernel */
Add_timer (&buttons_timer);
/* Initialize the wait queue */
Init_waitqueue_head (&KEY_Q);
return 0;
}
int key_remove (struct platform_device *dev)
{
FREE_IRQ (Res_irq->start, (void *) 4);
FREE_IRQ (Res_irq->end, (void *) 3);
Iounmap (key_base);
Misc_deregister (&key_miscdev);
return 0;
}
Platform-driven definition
static struct Platform_driver Key_driver = {
. probe= Key_probe,
. remove= Key_remove,
. driver= {
. owner= This_module,
. Name= "My-key",
},
};
static int Button_init ()
{
Return Platform_driver_register (&key_driver);//Platform Drive
Dynamic registration
}
static void Button_exit ()
{
Platform_driver_unregister (&key_driver);//Platform Driver logoff
}
Module_init (Button_init);
Module_exit (Button_exit);
Insmod Key_drv.ko
Mknod/dev/2440key C 10 200
./key_app
The platform device is not necessarily a module that can be placed directly into the kernel's initialization program.
。
Platform Bus driven design