0>目标:
写一个模仿platform的例子, 通过学习此例更容易理解后面的platform平台
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
1>问题:
通过上一篇设备模型1》初识:,知道了把驱动程序,分成bus,device和driver3大模块,device和driver通过bus的mach()函数匹配,并调设备对应driver的probe()。
×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
现在要实现在一个总线上,多个设备对应一套驱动,怎么办?例:要对3个U盘写数据。
难点:probe(
)问题:任何1个设备与驱动匹配成功后,都会调驱动的probe(),这样都调同1个probe(),怎么区分多个设备呢?也许你在想,现在看看下面这种方法:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
2>创建总线:
-
/*匹配规则*/
-
static int mymatch(struct device *dev, struct device_driver *drv)
-
{
-
-
struct mydev_t *mydev = container_of(dev, struct mydev_t, base_dev);
-
struct mydrv_t *mydrv = container_of(drv, struct mydrv_t, base_drv);
-
-
if(mydev->vender_id == mydrv->vender_id && mydev->product_id == mydrv->product_id) {
-
return 1;
-
}else{
-
return 0;
-
};
-
-
}
-
/*实例化总线*/
-
static struct bus_typemybus= {
-
.name = "plat_lsx",
-
.match = mymatch,
-
-
};
-
/*注册&&移除总线*/
-
-
static int __init my_init(void)
-
{
-
return bus_register(&mybus);
-
}
-
-
static void __exit my_exit(void)
-
{
-
bus_unregister(&mybus);
-
}
-
-
module_init(my_init);
-
module_exit(my_exit);
-
MODULE_LICENSE("GPL");
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3>设备:
1》封装自己的1套设备框架:
-
extern struct bus_typemybus;
-
-
//外部声明总线
-
/*抽象自己的设备类型*/
-
struct mydev_t
-
{
-
int irqno;
-
void *conf;
-
void *data;
-
-
unsigned int vender_id;
-
unsigned int product_id;
-
struct device base_dev; //嵌入标准的设备结构体,多思考会这个。
-
-
};
-
-
/*必须指定release成员*/
-
static void myrelease(struct device *dev)
-
{
-
struct mydev_t *mydev = container_of(dev, struct mydev_t, base_dev);
-
printk("ID: %#x device is released\n", mydev->product_id);
-
}
-
/*注册设备*/
-
-
int mydev_register(struct mydev_t *mydev)
-
{
-
mydev->base_dev.bus = &mybus; //挂载总线
-
mydev->base_dev.release = myrelease;
-
return device_register(&mydev->base_dev); //借用标准设备注册函数
-
}
-
EXPORT_SYMBOL_GPL(mydev_register);
-
-
/*移除设备*/
-
void mydev_unregister(struct mydev_t *mydev)
-
{
-
device_unregister(&mydev->base_dev); //借用标准设备移除函数
-
}
-
EXPORT_SYMBOL_GPL(mydev_unregister);
………………………………………………………………………………………………
2》注册实际设备:
-
/*实例化设备*/
-
struct mydev_t mydev = {
-
.irqno = 1111,
-
.conf = (void *)0x2222,
-
.data = (void *)0x3333,
-
.vender_id = 0x1234,
-
.product_id = 0x5678,
-
.base_dev = {
-
.init_name = "mydev1",
-
},
-
};
-
-
-
static int __init test_init(void)
-
{
-
return mydev_register(&mydev); //注册设备
-
}
-
-
static void __exit test_exit(void)
-
{
-
mydev_unregister(&mydev); //移出设备
-
}
-
-
module_init(test_init);
-
module_exit(test_exit);
-
MODULE_LICENSE("GPL");
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
4>驱动(重点)
1》封装自己的驱动类型:
-
extern struct bus_typemybus; //外部声明总线
-
-
struct mydrv_t {
-
char *drv_name;
-
int (*probe)(struct mydev_t *mydev); //自己的probe
-
int (*remove)(struct mydev_t *mydev); //自己的remove
-
unsigned int vender_id;
-
unsigned int product_id;
-
struct device_driver base_drv; //将标准设备驱动结构体嵌入,多思考会。
-
};
/*
*struct
device {
*struct
device_driver*driver;
*//标准设备结构体中有指向对应驱动的结构体指针,内核维护.
*}
*/
-
/*封装自己的一套驱动函数*/
-
static int myprobe(structdevice*dev)
-
{
-
struct mydev_t *mydev = container_of(dev, struct mydev_t, base_dev);
-
struct mydrv_t *mydrv = container_of(dev->driver, struct mydrv_t, base_drv);
-
-
return mydrv->probe(mydev); //调我们的probe
-
-
}
-
-
static int myremove(struct device *dev)
-
{
-
-
struct mydev_t *mydev = container_of(dev, struct mydev_t, base_dev);
-
struct mydrv_t *mydrv = container_of(dev->driver, struct mydrv_t, base_drv);
-
-
return mydrv->remove(mydev);
-
}
-
-
-
int mydrv_register(struct mydrv_t *mydrv)
-
{
-
-
mydrv->base_drv.name = mydrv->drv_name;
-
mydrv->base_drv.bus = &mybus;
-
mydrv->base_drv.probe = myprobe;
-
mydrv->base_drv.remove = myremove;
-
-
return driver_register(&mydrv->base_drv);
-
-
-
}
-
-
-
EXPORT_SYMBOL_GPL(mydrv_register);
-
-
void mydrv_unregister(struct mydrv_t *mydrv)
-
{
-
driver_unregister(&mydrv->base_drv);
-
}
-
-
EXPORT_SYMBOL_GPL(mydrv_unregister);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2》驱动注册:
-
/*实例化驱动注册*/
-
static int lsx_probe(struct mydev_t *mydev) //最终的probe
-
{
-
printk("device's driver probe\n");
-
printk("device info:\n");
-
printk("vender_id = %#x\n", mydev->vender_id);
-
printk("product_id = %#x\n", mydev->product_id);
-
printk("irqno = %d\n", mydev->irqno);
-
printk("conf = %#x\n", (unsigned int)mydev->conf);
-
printk("data = %#x\n", (unsigned int)mydev->data);
-
-
return 0;
-
}
-
-
static int lsx_remove(struct mydev_t *mydev)
-
{
-
printk("device's driver remove\n");
-
printk("device info:\n");
-
printk("vender_id = %#x\n", mydev->vender_id);
-
printk("product_id = %#x\n", mydev->product_id);
-
-
return 0;
-
-
}
-
-
-
static structmydrv_tmydrv= {
-
.drv_name = "mydrv1",
-
.probe = lsx_probe,
-
.remove = lsx_remove,
-
.vender_id = 0x00001234,
-
.product_id = 0x00005678,
-
-
};
-
-
-
static int __init test_init(void)
-
{
-
return mydrv_register(&mydrv);
-
}
-
-
static void __exit test_exit(void)
-
{
-
mydrv_unregister(&mydrv);
-
}
-
-
module_init(test_init);
-
module_exit(test_exit);
-
MODULE_LICENSE("GPL");
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
总结:
重点是驱动,封装自己的驱动类型,将标准的驱动结构体嵌入,有自己的probe成员,当驱动与设备匹配成功,会调标准驱动的base_drv.probe,就是myprobe(),并将标准设备结构体指针传过去,然后,我们可以得到我们封装设备结构体和设备驱动,然后调,我们设备驱动的lsx_probe()。
这样不管再多的同类设备,都是在同一套驱动下,仅仅是都有各自的probe()。
Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
思考:
从以上看出抽象的设备类型,是固定的,怎么能抽象出可以包罗万象的设备类型?
阅读(2228) | 评论(0) | 转发(0) |