Leesagacious 原创,欢迎转载,未完待续
/**
入口函数,注册了一个usb_driver
*/
static int __init usb_mouse_init(void)
{
/**所有驱动的注册,都要经过driver_register()这个函数,
同样会遍历挂在usb总线上的所有驱动,查看有没有同名的驱动,
然后将该驱动挂到总线上(bus_type_private的driver_kset容器)。设备驱动模型的详细信息请看另一篇博文
*/
int retval = usb_register(&usb_mouse_driver);
if(retval == 0){
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
DRIVER_DESC "\n");
}
return retval;
}
看一下这个usb_register()函数:
static inline int usb_register(struct usb_driver *driver)
{ //调用了这个函数来注册
return usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
}
int usb_register_driver(struct usb_driver * new_driver,struct module * owner,const char * mod_name)
{
int retval = 0;
//判断内核在启动的时候有没有禁止usb子系统启动
if(usb_disabled()){
return - ENODEV;
}
/**
驱动在usb的世界里分成了设备驱动和接口驱动两种,
为了区分这两种驱动,就中间加了一层,添加了for_device标志来判断
struct usbdrv_wrap{
struct device_driver driver;
int for_device; //0 接口驱动, 非0,设备驱动
}
*/
/**
下面的代码是对 driver的一些设置,
*/
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);
if (!retval) {
pr_info("%s: registered new interface driver %s\n",
usbcore_name, new_driver->name);
usbfs_update_special();
/**
if (usb_drv->probe != NULL)
error = driver_create_file(&usb_drv->drvwrap.driver,
&driver_attr_new_id);
上面是这个函数的源码,
如果驱动提供了probe函数,就为这个驱动创建属性文件
*/
usb_create_newid_file(new_driver);
} else {
printk(KERN_ERR "%s: error %d registering interface "
" driver %s\n",
usbcore_name, retval, new_driver->name);
}
return retval;
}
看看usb_mouse_driver usb接口驱动
static struct usb_driver usb_mouse_driver = {
.name = "usbmouse", //驱动名字
.probe = usb_mouse_probe,//匹配成功后调用的方法
.disconnect = usb_mouse_disconnect,//移除设备时出发的方法
.id_table = usb_mouse_id_table,//驱动支持的设备列表
}
匹配的依据
当插入usb鼠标的时候,会根据usb驱动中成员.id_table来匹配,id_table中存放了该驱动支持的设备列表
static struct usb_device_id usb_mouse_id_table[] = {
/**
#define USB_INTERFACE_INFO(cl,sc,pr)\
match_flags = USB_DEVICE_ID_MATCH_DEV_INFO,\
bDeviceClass = (cl),\ //设备的类型
bDeviceSubclass = (src),\//设备的子类型
bDeviceProtocol = (pr)//设备使用的协议
这个宏用来创建要给struct usb_device_id结构体,这个结构体存储了设备的类型和协议信息
*/
//设备的类型是 人机交互类设备,子类型是一种boot设备 遵循鼠标协议,那么就支持
{USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID,USB_INTERFACE_SUBCLASS_BOOT,USB_INTERFACE_PROTOCOL_MOUSE)},
{} //空项表示结束
}
如果匹配成功,那么会调用驱动提供的probe函数,会动态的创建一个usb_device,并调用device_add()将它放入到linux设备驱动模型中。其实如果总线提供了probe函数的话,内核是优先调用bus的probe函数的(详细请见另外一片博文),
匹配成功后会调用驱动提供的probe函数
/**
由于usb总线没有提供probe函数,那么就会调用驱动提供的probe函数
这个probe函数可以划分位两部分:
1 : 验证
根据HID规范: 鼠标只能有一个端点(0号端点用于控制除外,),而且这个端点一定要是中断输入端点
是怎么验证的呢:
if(interface->desc.bNumEndpoints != 1) 判断端点的数量
if (!usb_endpoint_is_int_in(endpoint)) 是否是中断输入端点
初始化 : 就是分配了一个input_dev,然后set_bit()设置支持什么事件之类的
初始化中断urb
注册输入设备
*/
static int usb_mouse_probe(struct usb_interface * intf,const struct usb_device_id *id)
{
/**
根据usb_interface获取动态创建的usb_device。
那么,usb_device是怎么被动态创建的呢,下面简单的说一下
在hub初始化的时候,会创建一个内核线程"khub",它用来监测hub状态的变化,
Hub正常工作后,usb主机控制器就会定时的询问hub,如果hub端口上有usb设备的插入、拔出的时候,hub就会把端口的状态变化告诉usb主机控制器,..........最终urb的完成函数hub_irq()会被调用
hub_irq()会调用kick_khubd(),kick_khubd()会调用wake_up(&khubd_wait);来唤醒上面的"khub"守护进程,这个守护进程会调用hub_event(),在这个函数中,最终会调用hub_port_connect_change()
下面来看这个hub_port_connect_change()函数
hub_port_connect_change( )
{
struct usb_device *udev;
udev = usb_alloc_dev(hdev, hdev->bus, port1);
usb_new_device(udev)
{
/**
看最终会调用device_add()来向设备驱动模型中添加一个设备
所以,可以看出在usb插入后,系统会自动注册设备到驱动模型中
我们要做的只是usb_driver的事情了
*/
err = device_add(&udev->dev)
}
}
*/
struct usb_device * dev = interface_to_usbdev(intf);
struct usb_host_interface * interface;
struct usb_endpoint_descriptor * endpoint;//定义usb端点描述符
struct usb_mouse *mouse; //usb鼠标结构体指针
struct input_dev * input_dev ;// 代表一个输入设备
int pipe,maxp;
int error = -ENOMEM;
/**
获取当前正在使用的设置
*/
interface = intf->cur->altsetting;
/**
interface->desc : usb接口描述符 usb_interface_descriptor
bNumEndpoints 端点的数量(端点0除外)
*/
if(interface->desc.bNumEndpoints != 1)
{
return -ENODEV;
}
/**
获取端点描述符
*/
endpoint = &interface->endpoint[0].desc;
/**
判断这个端点是不是中断输入端点
那么是怎么判断的呢? 源码 :
static inline int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor*epd)
{
return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd))
{
取bmAttributes的[1:0],判断它是不是 11
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT);
}
}
usb端点描述符中的 bmAttributes 的低两位 用于 标示 端点传输类型
#define USB_ENDPOINT_XFER_CONTROL 0
#define USB_ENDPOINT_XFER_ISOC 1
#define USB_ENDPOINT_XFER_BULK 2
#define USB_ENDPOINT_XFER_INT 3 中断传输
*/
if(!usb_endpoint_is_int_in(endpoint))
{
return -ENODEV;
}
/**
创建中断管道
实现代码:
#define usb_rcvintpipe(dev,endpoint)\
((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
static inline unsigned int __create_pipe(struct usb_device * dev,unsigned int endpoint)
{
return (dev->devnum << 8) | (endpoint << 15);
}
PIPE_INTERRUPT : 1, 表示是中断管道
USB_DIR_IN :0x80 用来表示数据传输方向,由设备向主机
pipe : 32位,
8~14 : 设备号,
15~18: 端点号
7 : 方向
bEndpointAddress :
8位
0~3 :端点号, bEndpointAddress &0x0f
7 :端点的方向 使用宏USB_DIR_IN、USB_DIR_OUT来判断短点的额方向
*/
pipe = usb_rcvintpipe(dev,endpoint->bEndpointAddress);
}