平台总线模型

平台总线模型主要分为3个部分,1.driver 2.device 3.bus


device主要放硬件相关的东西

driver里面主要存放的比较稳定的代码

我们依然可以查看gpio_keys.c这个代码来学习


平台总线是一种虚拟的总线


driver这个结构体会通过调用platform_driver_register这个函数

platform_driver_register这个函数又会调用driver_register这个函数把这个driver放到bus中driver的一个链表里面去


device这个结构体会通过调用platform_device_register这个函数

platform_device_register这个函数会调用platform_device_add这个函数,platform_device_add这个函数又会调用device_add这个函数把device放到Bus中的device的这个链表里面去,这个注册除了把这个结构体放到这个平台里面去,还diver里面取出来跟他比较,用什么函数来跟它比较呢,总线里面有个函数.match函数。用这个函数来比较这个driver能不能支持这个device  能够支持的话就调用driver里面的probe.


device_add做了什么事情

1.把device放入bus中的device链表里面

2.device_add函数会从bus的driver链表取出每个driver,用总线的match函数判断这个driver能否支持device

3.如果能够支持的话调用这个probe函数


driver_add做了什么事情呢

1.把driver放入bus总线的driver链表

2从device链表中拿出每一个device,用总线的match函数来一一比较

3.如果能够支持,调用probe函数


注意:这只不过是这么一种机制,device和driver建立联系的机制,在probe函数里面做什么事情,由你决定,你打印一句话,注册一个字符设备什么的,都是由你决定的


driver里放比较稳定的东西,我们改的话,主要是改device这边的代码

我们来看这个gpio_keys.c这个代码

static int __init gpio_keys_init(void)
{
return platform_driver_register(&gpio_keys_device_driver);这是注册一个driver,来看看这个driver里面有什么东西


static struct platform_driver gpio_keys_device_driver = {
.probe = gpio_keys_probe,
.remove = __devexit_p(gpio_keys_remove),
.driver = {
.name = "gpio-keys",
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &gpio_keys_pm_ops,
#endif
}
};


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);
}


struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};


平台总线上有一个函数platform_match这个函数,我们来看一下这个匹配函数

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);
}

由此可以看出,匹配的方法,我们这里用的是下面这种,用名字匹配的方法

}


static void __exit gpio_keys_exit(void)
{
platform_driver_unregister(&gpio_keys_device_driver);
}



范例代码如下


device驱动如下

#include

#include
#include
#include
#include
#include
#include
#include
#include
#include


static struct resource led_resource[]={
[0]={
.start = 0xe0200280,
.end = 0xe0200284,
.flags = IORESOURCE_MEM,
},


};


static void led_release(struct device * dev)
{
//我们先什么都不放,到时候可以放一些硬件相关的代码
}
/*分配/设置/注册一个platform_device*/
static struct platform_device led_dev={
.name = "myled",//名字要与driver里面的名字一样,因为match函数是根据这个来匹配的
.num_resources = ARRAY_SIZE(led_resource),
.resource = led_resource,
.dev=
{
.release = led_release, 
},
};


static int led_dev_init(void)
{
platform_device_register(&led_dev);
return 0;
}


static void led_dev_exit(void)
{
platform_device_unregister(&led_dev);
}


module_init(led_dev_init);
module_exit(led_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EIGHT");


driver程序如下

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include




struct class *my_class;
struct cdev cdev;
dev_t devno;
static volatile unsigned long *con;
static volatile unsigned long *data;


#define LED_MAGIC 'm'
#define LED_ON _IO(LED_MAGIC,0)
#define LED_OFF _IO(LED_MAGIC,1)


static int led_open(struct inode *inode,struct file *file)
{
writel(0x00001111,con);
return 0;
}
long led_ioctl (struct file *file, unsigned int cmd, unsigned long arg)
{
switch(cmd)
{
case LED_ON:
writel(0x00,data);
break;
case LED_OFF:
writel(0x0f,data);
break;
default:
return -EINVAL;
}
return 0;
}




static struct file_operations myled_fops =
{
.owner = THIS_MODULE,
.open = led_open,
.unlocked_ioctl =led_ioctl,
};


static int led_probe(struct platform_device *pdev)
{
//根据platform_device的资源来ioremap
struct resource *res_mem;
res_mem=platform_get_resource(pdev,IORESOURCE_MEM,0);
con=ioremap(res_mem->start,res_mem->end-res_mem->start+1);
data=con+1;




//注册字符设备驱动
cdev_init(&cdev,&myled_fops); 
alloc_chrdev_region(&devno, 0 , 1 , "myled");
cdev_add(&cdev, devno, 1);
my_class = class_create(THIS_MODULE, "led_class");
if(IS_ERR(my_class))
{
printk("Err: failed in creating class.\n");
return -1;
}
device_create(my_class, NULL, devno,NULL,"led_driver");
return 0;
}


static int led_remove(struct platform_device *dev)
{
//根据platform_device的资源来进行iounmap
iounmap(con);
iounmap(data);
//卸载字符设备驱动
device_destroy(my_class,devno);
class_destroy(my_class);


cdev_del(&cdev);
unregister_chrdev_region(devno,1);
return 0;


}
struct platform_driver key_driver={
.probe = led_probe,
.remove= led_remove,
.driver={
.name="myled",//要与device里面的名字一样。因为match函数就是根据名字匹配的
},
};


/*分配/设置/注册一个platform_driver结构体*/
static int led_drv_init(void)
{
platform_driver_register(&key_driver);
return 0;
}


static void led_drv_exit(void)
{
platform_driver_unregister(&key_driver);
}


module_init(led_drv_init);
module_exit(led_drv_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EIGHT");


测试程序跟前面led的测试程序一样

你可能感兴趣的:(linux学习之路)