linux安装usb总线驱动,Linux下的USB总线驱动

二.USB驱动分析

内核代码分析包括USB驱动框架、鼠标驱动、键盘驱动、U盘驱动。

USB驱动编写的主要框架usb-skeleton.c

USB鼠标驱动 usbmouse.c

USB键盘驱动usbkbd.c

USB Mass Storage是一类USB存储设备, U盘便是其中之一,主要分析的驱动文件是usb.c

1.USB驱动框架usb-skeleton.c

USB骨架程序可以被看做一个最简单的USB设备驱动的实例。

首先看看USB骨架程序的usb_driver的定义

static struct usb_driver skel_driver = {

.name =          "skeleton",

.probe =  skel_probe,    //设备探测

.disconnect =  skel_disconnect,

.suspend =      skel_suspend,

.resume =      skel_resume,

.pre_reset =    skel_pre_reset,

.post_reset =  skel_post_reset,

.id_table =      skel_table,  //设备支持项

.supports_autosuspend = 1,

};

#define USB_SKEL_VENDOR_ID      0xfff0

#define USB_SKEL_PRODUCT_ID    0xfff0

static struct usb_device_id skel_table[] = {

{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },

{ }

};

MODULE_DEVICE_TABLE(usb, skel_table);

由上面代码可见,通过USB_DEVICE宏定义了设备支持项。

对上面usb_driver的注册和注销发送在USB骨架程序的模块加载和卸载函数中。

static int __init usb_skel_init(void)

{

int result;

result = usb_register(&skel_driver);  //将该驱动挂在USB总线上

if (result)

err("usb_register failed. Error number %d", result);

return result;

}

一个设备被安装或者有设备插入后,当USB总线上经过match匹配成功,就会调用设备驱动程序中的probe探测函数,向探测函数传递设备的信息,以便确定驱动程序是否支持该设备。

static int skel_probe(struct usb_interface *interface,

const struct usb_device_id *id)

{

struct usb_skel *dev;    //特定设备结构体

struct usb_host_interface *iface_desc;  //设置结构体

struct usb_endpoint_descriptor *endpoint;  //端点描述符

size_t buffer_size;

int i;

int retval = -ENOMEM;

dev = kzalloc(sizeof(*dev), GFP_KERNEL);  //分配内存

if (!dev) {

err("Out of memory");

goto error;

}

kref_init(&dev->kref);

sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);  //初始化信号量

mutex_init(&dev->io_mutex);          //初始化互斥锁

spin_lock_init(&dev->err_lock);        //初始化信号量

init_usb_anchor(&dev->submitted);

init_completion(&dev->bulk_in_completion);  //初始化完成量

dev->udev = usb_get_dev(interface_to_usbdev(interface)); //获取usb_device结构体

dev->interface = interface;  //获取usb_interface结构体

iface_desc = interface->cur_altsetting;  //由接口获取当前设置

for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {  //根据端点个数逐一扫描端点

endpoint = &iface_desc->endpoint[i].desc; //由设置获取端点描述符

if (!dev->bulk_in_endpointAddr &&

usb_endpoint_is_bulk_in(endpoint)) { //如果该端点为批量输入端点

buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);  //缓冲大小

dev->bulk_in_size = buffer_size;            //缓冲大小

dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;  //端点地址

dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);  //缓冲区

if (!dev->bulk_in_buffer) {

err("Could not allocate bulk_in_buffer");

goto error;

}

dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL); //分配urb空间

if (!dev->bulk_in_urb) {

err("Could not allocate bulk_in_urb");

goto error;

}

}

if (!dev->bulk_out_endpointAddr &&

usb_endpoint_is_bulk_out(endpoint)) {  //如果该端点为批量输出端点

dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;  //端点地址

}

}

if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {//都不是批量端点

err("Could not find both bulk-in and bulk-out endpoints");

goto error;

}

usb_set_intfdata(interface, dev);  //将特定设备结构体设置为接口的私有数据

retval = usb_register_dev(interface, &skel_class);  //注册USB设备

if (retval) {

err("Not able to get a minor for this device.");

usb_set_intfdata(interface, NULL);

goto error;

}

dev_info(&interface->dev,

"USB Skeleton device now attached to USBSkel-%d",

interface->minor);

return 0;

error:

if (dev)

kref_put(&dev->kref, skel_delete);

return retval;

}

通过上面分析,我们知道,usb_driver的probe函数中根据usb_interface的成员寻找第一个批量输入和输出的端点,将端点地址、缓冲区等信息存入USB骨架程序定义的usb_skel结构体中,并将usb_skel通过usb_set_intfdata传为USB接口的私有数据,最后注册USB设备。0b1331709591d260c1c78e86d0c51c18.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值