当前位置:   article > 正文

USB学习之一:USB总线驱动程序_usb_speed_super

usb_speed_super

USB总线驱动程序的作用
1. 识别USB设备
1.1 分配地址
1.2 并告诉USB设备(set address)
1.3 发出命令获取描述符
描述符的信息可以在include\linux\usb\Ch9.h看到


2. 查找并安装对应的设备驱动程序

3. 提供USB读写函数

将一个USB设备接到开发板上,看输出信息:
usb 1-1: new full speed USB device using s3c2410-ohci and address 2
usb 1-1: configuration #1 chosen from 1 choi     ce
scsi0 : SCSI emulation for USB Mass Storage devices
scsi 0:0:0:0: Direct-Access     HTC      Android Phone    0100 PQ: 0 ANSI: 2
sd 0:0:0:0: [sda] Attached SCSI removable disk
拔掉
usb 1-1: USB disconnect, address 2

再接上:
usb 1-1: new full speed USB device using s3c2410-ohci and address 3
usb 1-1: configuration #1 chosen from 1 choice
scsi1 : SCSI emulation for USB Mass Storage devices
scsi 1:0:0:0: Direct-Access     HTC      Android Phone    0100 PQ: 0 ANSI: 2
sd 1:0:0:0: [sda] Attached SCSI removable disk

全局搜索  grep "USB device using" * -nR   在2.6的内核中可以搜到相关信息。

我用的是3.0的内核,USB设备插入后,会有如下信息打印出来

[  465.520759] usb 1-2.3: new high speed USB device number 22 using s5p-ehci

因此可以搜索:grep "USB device number" -nr .

找到在linux-3.0.86/drivers/usb/core/hub.c  中hub_port_init函数中,因此我们可以通过hub_port_init函数找出USB总线驱动程序的调用关系。先上一张图。

接着从代码的角度做一些分析:

drivers/usb/core/usb.c

  1. struct bus_type usb_bus_type = {
  2. .name = "usb",
  3. .match = usb_device_match,
  4. .uevent = usb_uevent,
  5. };
  6. static int __init usb_init(void)
  7. {
  8. retval = bus_register(&usb_bus_type); //注册USB总线,USB总线和平台总线及其他总线是类似的
  9. ........ //省略了很多初始化的工作
  10. retval = usb_hub_init(); //usb hub初始化
  11. }
  1. static struct usb_driver hub_driver = {
  2. .name = "hub",
  3. .probe = hub_probe,
  4. .disconnect = hub_disconnect,
  5. .suspend = hub_suspend,
  6. .resume = hub_resume,
  7. .reset_resume = hub_reset_resume,
  8. .pre_reset = hub_pre_reset,
  9. .post_reset = hub_post_reset,
  10. .unlocked_ioctl = hub_ioctl,
  11. .id_table = hub_id_table,
  12. .supports_autosuspend = 1,
  13. };
  14. int usb_hub_init(void)
  15. {
  16. if (usb_register(&hub_driver) < 0) { //注册usb hub driver,在hub_driver中提供了一系列hub相关的操作函数
  17. }
  18. khubd_task = kthread_run(hub_thread, NULL, "khubd");//初始化一个hub 线程,这个线程在usb设备插入后会跑,后面会分析到。
  19. }
  20. //接着分析usb_register函数
  21. usb_register(&hub_driver)
  22. usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
  23. driver_register(&new_driver->drvwrap.driver)
  24. bus_add_driver(drv)
  25. driver_attach(drv)
  26. bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)
  27. __driver_attach
  28. driver_match_device(drv, dev)
  29. return drv->bus->match ? drv->bus->match(dev, drv) : 1;
  30. //因此最后是调用的是上文中提到的usb_bus_type中提供的
  31. usb_device_match(struct device *dev, struct device_driver *drv)函数。该函数是通过比较usb_driver中的id_table来确定的是否匹配并调用probe函数。
  32. 这些是跟内核的总线设备框架有关。

设备和驱动匹配到之后就会调用probe函数,即hub_probe

  1. static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
  2. {
  3. struct usb_host_interface *desc;
  4. .......//省略一些初始化工作
  5. hub = kzalloc(sizeof(*hub), GFP_KERNEL); //分配一个hub结构体
  6. .......
  7. if (hub_configure(hub, endpoint) >= 0) {
  8. }
  9. hub_configure(hub, endpoint)
  10. hub->urb = usb_alloc_urb(0, GFP_KERNEL); //分配hub->urb
  11. usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,
  12. hub, endpoint->bInterval);//注册hub中断 hub_irq,当usb设备被插入时,hub_irq会被调用

当由USB设备插入hub,hub端口的D+或者D-会由原来的低电平被拉高到3V高电平,触发hub中断,hub_irq

  1. static void hub_irq(struct urb *urb)
  2. {
  3. struct usb_hub *hub = urb->context;
  4. int status = urb->status;
  5. unsigned i;
  6. unsigned long bits;
  7. .........
  8. /* Something happened, let khubd figure it out */
  9. kick_khubd(hub); //唤醒上文中提到的hub_thread
  10. }
  11. static int hub_thread(void *__unused)
  12. {
  13. set_freezable();
  14. do {
  15. hub_events();
  16. wait_event_freezable(khubd_wait,
  17. !list_empty(&hub_event_list) ||
  18. kthread_should_stop());
  19. } while (!kthread_should_stop() || !list_empty(&hub_event_list));
  20. }
  21. //接着调用到hub_events
  22. hub_events
  23. hub_port_connect_change(hub, i,
  24. portstatus, portchange);
  25. udev = usb_alloc_dev(hdev, hdev->bus, port1);//分配一个USB DEV设备
  26. choose_devnum(udev);//设置这个dev的编号
  27. hub_port_init(hub, udev, port1, i);

在hub_port_init中做了很多事情

  1. hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
  2. int retry_counter)
  3. {
  4. static DEFINE_MUTEX(usb_address0_mutex);
  5. retval = hub_port_reset(hub, port1, udev, delay);//复位hub
  6. oldspeed = udev->speed; //获取usb设备的速度
  7. switch (udev->speed) { //根据不同速度的设备做一些设置
  8. case USB_SPEED_SUPER:
  9. case USB_SPEED_WIRELESS: /* fixed at 512 */
  10. udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
  11. break;
  12. case USB_SPEED_HIGH: /* fixed at 64 */
  13. udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
  14. break;
  15. case USB_SPEED_FULL: /* 8, 16, 32, or 64 */
  16. /* to determine the ep0 maxpacket size, try to read
  17. * the device descriptor to get bMaxPacketSize0 and
  18. * then correct our initial guess.
  19. */
  20. udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
  21. break;
  22. case USB_SPEED_LOW: /* fixed at 8 */
  23. udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8);
  24. break;
  25. }
  26. if (udev->speed != USB_SPEED_SUPER)
  27. dev_info(&udev->dev,
  28. "%s %s speed %sUSB device number %d using %s\n", //识别到usb设备后就会打印这句信息
  29. (udev->config) ? "reset" : "new", speed, type,
  30. devnum, udev->bus->controller->driver->name);
  31. for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
  32. if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) {
  33. struct usb_device_descriptor *buf;
  34. int r = 0;
  35. #undef GET_DESCRIPTOR_BUFSIZE
  36. }
  37. /*
  38. * If device is WUSB, we already assigned an
  39. * unauthorized address in the Connect Ack sequence;
  40. * authorization will assign the final address.
  41. */
  42. if (udev->wusb == 0) {
  43. for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
  44. retval = hub_set_address(udev, devnum); //设置设备的地址
  45. }
  46. if (udev->speed == USB_SPEED_SUPER) {
  47. devnum = udev->devnum;
  48. dev_info(&udev->dev,
  49. "%s SuperSpeed USB device number %d using %s\n",
  50. (udev->config) ? "reset" : "new",
  51. devnum, udev->bus->controller->driver->name);
  52. }
  53. }
  54. retval = usb_get_device_descriptor(udev, 8);//获取设备描述符,第8个字节是设备描述符的最大包长
  55. i = udev->descriptor.bMaxPacketSize0;
  56. if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
  57. if (udev->speed == USB_SPEED_LOW ||
  58. }
  59. retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);//在上文中获取到了设备描述符的最大包长,因此这里一次把设备描述符读取
  60. if (retval < (signed)sizeof(udev->descriptor)) {
  61. dev_err(&udev->dev, "device descriptor read/all, error %d\n",
  62. retval);
  63. if (retval >= 0)
  64. retval = -ENOMSG;
  65. goto fail;
  66. }
  67. }

hub_port_init初始化完成以后调用usb_new_device(udev),将usb设备添加到设备链表中去。

  1. int usb_new_device(struct usb_device *udev)
  2. device_add(&udev->dev); // 把device放入usb_bus_type的dev链表,
  3. // 从usb_bus_type的driver链表里取出usb_driver,
  4. // 把usb_interface和usb_driver的id_table比较
  5. // 如果能匹配,调用usb_driver的probe

至此USB总线驱动程序框架已经分析完了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/263477
推荐阅读
相关标签
  

闽ICP备14008679号