转载地址:http://blog.csdn.net/Deadline_h/article/details/78709142
linux usb子系统使用的总线设备驱动模型。
在linux内核里有一条usb总线为usb_bus_type
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match,
.uevent = usb_uevent,
};
在该总线下挂有usb设备和usb驱动。
根据设备和驱动的类型又分为两大类
一类为usb设备,一类为usb接口设备。
usb设备和usb设备驱动进行匹配,usb接口设备和usb接口驱动进行匹配。
通过match函数,这两类的匹配进入不同的分支
static int usb_device_match(struct device *dev, struct device_driver *drv)
{
/* devices and interfaces are handled separately 设备和接口设备分开处理*/
if (is_usb_device(dev)) {//usb设备
/* 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)) {//usb接口设备
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)) // ==0代表接口驱动 非0代表设备驱动
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;
}
/* ———————————————— */
usb接口设备(设备类型 == usb_if_device_type) 通过 device_add注册
usb接口驱动(struct usb_driver ,需要我们实现) 通过 usb_register 注册
/* ———————————————— */
usb设备(设备类型 == usb_device_type) 通过 device_add 注册
usb设备驱动() 通过usb_register_device_driver()注册
1、usb设备插入usb接口,usb差分信号线上电平变化,导致usb控制器产生中断hub_irq,通知系统有usb设备接入。
2、usb hub线程(hub_thread)被hub_irq唤醒,发生如下函数调用
hub_irq
kick_khubd
hub_thread
hub_events
hub_port_connect_change//端口连接发生改变
udev = usb_alloc_dev//分配一个usb设备
hub_port_init//获取设备描述符
usb_new_device(udev)
usb_enumerate_device//枚举设备
usb_get_configuration//获取配置描述符
for(; cfgno < ncfg; cfgno++)//有多少个配置都获取出来
{
usb_get_descriptor //获取配置描述符,得到大小
usb_parse_configuration//解析配置描述符
usb_parse_interface//解析接口描述符
usb_parse_endpoint//解析端点描述符
}
device_add(注册的设备类型是:usb_device_type) //调用usb_bus_type->match函数,如果匹配成功,会导致usb_device_driver的probe函数被调用
usb设备驱动在哪里注册?
在/driver/usb/core/usb.c注册
struct usb_device_driver usb_generic_driver = {
.name = "usb",
.probe = generic_probe,
.disconnect = generic_disconnect,
#ifdef CONFIG_PM
.suspend = generic_suspend,
.resume = generic_resume,
#endif
.supports_autosuspend = 1,
};
usb_init
usb_register_device_driver(&usb_generic_driver )
generic_probe //如果跟usb设备匹配上的话,会导致probe函数被调用
usb_set_configuration //设置配置
for (i = 0; i < nintf; ++i) //有多少个接口,就注册多少个usb_if_device_type接口设备
{
struct usb_interface *intf = cp->interface[i];
。。。
intf->dev.bus = &usb_bus_type;
intf->dev.type = &usb_if_device_type;//usb接口设备
ret = device_add(&intf->dev); // 把device放入usb_bus_type的dev链表,
// 从 usb_bus_type 的driver链表里取出usb_driver,
// 把usb_interface和usb_driver的id_table比较
// 如果能匹配,调用usb_driver的probe
// 所以一个接口就对应一个usb驱动
。。。
}
从上述代码中可知,在接入usb设备引发如下事件
注册usb设备 -> 根据usb设备的接口描述符,注册usb接口设备(有多少个接口就有多少个usb接口设备)
所以我们要实现接口设备驱动用来驱动usb接口设备(类型为usb_if_device_type的设备)
参考:h:\linux_source_code\linux-3.0.1\drivers\hid\usbhid\Usbmouse.c
static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
int pipe;
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
/* a. 分配一个input_dev */
uk_dev = input_allocate_device();
/* b. 设置 */
/* b.1 能产生哪类事件 */
set_bit(EV_KEY, uk_dev->evbit);
set_bit(EV_REP, uk_dev->evbit);
/* b.2 能产生哪些事件 */
set_bit(KEY_L, uk_dev->keybit);
set_bit(KEY_S, uk_dev->keybit);
set_bit(KEY_ENTER, uk_dev->keybit);
/* c. 注册 */
input_register_device(uk_dev);
/* d. 硬件相关操作 */
/* 数据传输3要素: 源,目的,长度 */
/* 源: USB设备的某个端点 */
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
/* 长度: */
len = endpoint->wMaxPacketSize;
/* 目的: */
usb_buf = usb_buffer_alloc(dev, len, GFP_ATOMIC, &usb_buf_phys);
/* 使用"3要素" */
/* 分配usb request block */
uk_urb = usb_alloc_urb(0, GFP_KERNEL);
/* 使用"3要素设置urb" */
usb_fill_int_urb(uk_urb, dev, pipe, usb_buf, len, usbmouse_as_key_irq, NULL, endpoint->bInterval);
uk_urb->transfer_dma = usb_buf_phys;
uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/* 使用URB */
usb_submit_urb(uk_urb, GFP_KERNEL);
return 0;
}
//接口匹配idtable
static struct usb_device_id usb_mouse_id_table [] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE) },
{ } /* Terminating entry */
};
//usb接口驱动结构体
static struct usb_driver usb_mouse_driver = {
.name = "usbmouse",
.probe = usb_mouse_probe,
.disconnect = usb_mouse_disconnect,
.id_table = usb_mouse_id_table,
};
static int __init usb_mouse_init(void)
{
int retval = usb_register(&usb_mouse_driver);
}
大致讲这么多,仅供参考。