linux usb 通用驱动程序,要开始系统学习LINUX USB驱动了(通用的驱动流程)

以USB串口驱动pl2303为例子分析。

首先是要有一个总管usb设备的驱动,就是定义在generic.c中的 usb_device_driver;该结构在usb.c中注册:

int usb_register_device_driver(struct usb_device_driver *new_udriver,

struct module *owner)

{

int retval = 0;

if (usb_disabled())

return -ENODEV;

new_udriver->drvwrap.for_devices = 1;

new_udriver->drvwrap.driver.name = (char *) new_udriver->name;

new_udriver->drvwrap.driver.bus = &usb_bus_type;

new_udriver->drvwrap.driver.probe = usb_probe_device;

new_udriver->drvwrap.driver.remove = usb_unbind_device;

new_udriver->drvwrap.driver.owner = owner;

retval = driver_register(&new_udriver->drvwrap.driver);

if (!retval) {

pr_info("%s: registered new device driver %s\n",

usbcore_name, new_udriver->name);

usbfs_update_special();

} else {

printk(KERN_ERR "%s: error %d registering device "

" driver %s\n",

usbcore_name, retval, new_udriver->name);

}

return retval;

}

usb_register_device_driver(&usb_generic_driver, THIS_MODULE) -> driver_register(这是usb device驱动,for_devices = 1);

记住,整个usb驱动架构中就注册了一个这样的设备驱动。

其次是具体设备的usb驱动usb_driver(如PL2303),他们都是用usb_register ->usb_register_driver -> driver_register来注册的(这是注册USB interface驱动,for_devices = 0):

int usb_register_driver(struct usb_driver *new_driver, struct module *owner,

const char *mod_name)

{

int retval = 0;

if (usb_disabled())

return -ENODEV;

new_driver->drvwrap.for_devices = 0;

new_driver->drvwrap.driver.name = (char *) new_driver->name;

new_driver->drvwrap.driver.bus = &usb_bus_type;

new_driver->drvwrap.driver.probe = usb_probe_interface;

new_driver->drvwrap.driver.remove = usb_unbind_interface;

new_driver->drvwrap.driver.owner = owner;

new_driver->drvwrap.driver.mod_name = mod_name;

spin_lock_init(&new_driver->dynids.lock);

INIT_LIST_HEAD(&new_driver->dynids.list);

retval = driver_register(&new_driver->drvwrap.driver);

if (retval)

goto out;

usbfs_update_special();

retval = usb_create_newid_file(new_driver);

if (retval)

goto out_newid;

retval = usb_create_removeid_file(new_driver);

if (retval)

goto out_removeid;

............................................................

这样,driver就已经添加到USB总线上来。但是还没有device;这是因为deivce是动态创建加载的。USB子系统加载后,会启动一个内核线程:

kthread_run(hub_thread, NULL, "khubd")来监控usb设备的热拔插事件,其发现设备的大体流程是:

hub_events -> hub_port_connect_change -> usb_alloc_dev -> 创建udev,并且赋值:

dev->dev.bus = &usb_bus_type;

dev->dev.type = &usb_device_type;//这是以后匹配device_driver的依据

dev->dev.groups = usb_device_groups;

->usb_new_device(udev) -> device_add,这样,就将检测到的USB设备添加到USB总线usb_bus_type上了。

而接着在device_add -> bus_probe_device中会用bus_for_each_drv遍历前面注册在usb总线上的驱动,这个时候总线上有很多device_driver,但是我们要调用前面usb_register_device_driver注册的通用设备描述符解析驱动。

这是如何匹配到的呢?进入USB总线usb_bus_type的match函数看看匹配规则就知道了:

static int usb_device_match(struct device *dev, struct device_driver *drv)

{

/* devices and interfaces are handled separately */

if (is_usb_device(dev)) {

/* interface drivers never match devices */

if (!is_usb_device_driver(drv))

return 0;

/* TODO: Add real matching code */

return 1;

} else if (is_usb_interface(dev)) {

struct usb_interface *intf;

struct usb_driver *usb_drv;

const struct usb_device_id *id;

/* device drivers never match interfaces */

if (is_usb_device_driver(drv))

return 0;

intf = to_usb_interface(dev);

usb_drv = to_usb_driver(drv);

id = usb_match_id(intf, usb_drv->id_table);

if (id)

return 1;

id = usb_match_dynamic_id(intf, usb_drv);

if (id)

return 1;

}

return 0;

}

可以猜想,现在要匹配的是设备驱动,而不是接口驱动,而is_usb_device函数的定义为:

static inline int is_usb_device(const struct device *dev)

{

return dev->type == &usb_device_type;

}

根据前面usb_alloc_dev的赋值,该条件已经符合;接着is_usb_device_driver函数的定义:

static inline int is_usb_device_driver(struct device_driver *drv)

{

return container_of(drv, struct usbdrv_wrap, driver)->

for_devices;

}

刚好这里for_devices前面赋值为1,这样usb_device_match就匹配成功了,找到了new_driver->drvwrap.driver这个device_driver,并调用他的probe方法->usb_probe_device:

static int usb_probe_device(struct device *dev)

{

.......

error = udriver->probe(udev);

.......

}

做一些简单的判断然后调用generic.c的usb_device_driver结构体的probe。再次强调,这是通用的配置描述符驱动是根据上述分,所有的usb插入设备都析的规则找到它,并调用他的probe方法来获得配置描述符:

static int generic_probe(struct usb_device *udev)

{

int err, c;

/* Choose and set the configuration. This registers the interfaces

* with the driver core and lets interface drivers bind to them.

*/

if (usb_device_is_owned(udev))

; /* Don't configure if the device is owned */

else if (udev->authorized == 0)

dev_err(&udev->dev, "Device is not authorized for usage\n");

else {

c = usb_choose_configuration(udev);

if (c >= 0) {

err = usb_set_configuration(udev, c);

if (err) {

dev_err(&udev->dev, "can't set config #%d, error %d\n",

c, err);

/* This need not be fatal. The user can try to

* set other configurations. */

}

}

}

/* USB device state == configured ... usable */

usb_notify_add_device(udev);

return 0;

}

主要工作是在usb_set_configuration中,它根据选择到的配置描述符,设置到设备中,使该配置下的接口生效,并将每个接口抽象成一个device,用device_add(&intf->dev)添加到USB总线上去。重要的代码片段如下:

int usb_set_configuration(struct usb_device *dev, int configuration)

{

int i, ret;

struct usb_host_config *cp = NULL;

struct usb_interface **new_interfaces = NULL;

struct usb_hcd *hcd = bus_to_hcd(dev->bus);

int n, nintf;

。。。。。。

new_interfaces = kmalloc(nintf * sizeof(*new_interfaces),

。。。。。。

for (; n < nintf; ++n) {

new_interfaces[n] = kzalloc(

sizeof(struct usb_interface),

GFP_NOIO);

。。。。。。

usb_enable_interface(dev, intf, true);

intf->dev.parent = &dev->dev;

intf->dev.driver = NULL;

intf->dev.bus = &usb_bus_type;

intf->dev.type = &usb_if_device_type;

intf->dev.groups = usb_interface_groups;

intf->dev.dma_mask = dev->dev.dma_mask;

INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);

。。。。。。

for (i = 0; i < nintf; ++i) {

struct usb_interface *intf = cp->interface[i];

dev_dbg(&dev->dev,

"adding %s (config #%d, interface %d)\n",

dev_name(&intf->dev), configuration,

intf->cur_altsetting->desc.bInterfaceNumber);

device_enable_async_suspend(&intf->dev);

ret = device_add(&intf->dev);

if (ret != 0) {

dev_err(&dev->dev, "device_add(%s) --> %d\n",

dev_name(&intf->dev), ret);

continue;

}

create_intf_ep_devs(intf);

。。。。。。

这一次device_add又将匹配总线上的那个device_driver呢?回去看前面的match方法可知:

static inline int is_usb_interface(const struct device *dev)

{

return dev->type == &usb_if_device_type;

}

这个条件成立,调用usb_match_id(intf, usb_drv->id_table)和usb_match_dynamic_id匹配,这样说吧,这里是把从USB设备读取道德PID,VID和驱动中定义的进行匹配,如果有则匹配成功。我们PL2303的id_table定义了很多,如果还要添加新的ID,则在该id_table添加即可。

匹配成功后,调用通用的usb_probe_interface:

static int usb_probe_interface(struct device *dev)

{

。。。。。。

if (intf->needs_altsetting0) {

error = usb_set_interface(udev, intf->altsetting[0].

desc.bInterfaceNumber, 0);

。。。。。。

error = driver->probe(intf, id);

。。。。。。

调用具体驱动的probe,这里就是PL2303的probe了:

static struct usb_driver pl2303_driver = {

.name = "pl2303",

.probe = usb_serial_probe,

.disconnect = usb_serial_disconnect,

.id_table = id_table,

.suspend = usb_serial_suspend,

.resume = usb_serial_resume,

.no_dynamic_id = 1,

.supports_autosuspend = 1,

};

usb_serial_probe,这里看到有趣的事情,usb-serial.c 中的probe也指向usb_serial_probe,按理说应该是先找到usb-serial.c 的porbe,然后再通过它找到pl2303的probe。这里可能是usb-serial.c 作为一个通用的函数接口代码,并没有定义PID,VID;但是USB核心的匹配规则偏偏是匹配该ID,所以为了迎合USB的架构,usb serial也没有别的好办法,只好把PL2303的probe指向了usb-serial.c 的porbe,在该probe中统一处理端点描述符。

从上面可以看出,USB子系统已经为我们实现了大部分架构,我们驱动要做的事情只要实现接口描述符(interface descriptor)的处理即可,这就要求根据USB协议规则和具体的USB芯片手册来操作。

下一篇就来分析常用的USB协议和一个具体的接口描述符驱动。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值