我们这里只是讨论usb 驱动的原理 不会涉及到usb的协议

UHCI: intel, 低速(1.5Mbps)/全速(12Mbps)

OHCI:Microsoft 低速/全速

EHCI:高速(480Mbps)

 

调用的形式为:

hub_irq->kick_khubd -> hub_thread -> hub_events -> hub_port_connect_change->hub_port_init 里面会打印出发现一个新的usb设备

 

hub_port_init 函数:

  1 static int
  2 hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
  3         int retry_counter)
  4 {
  5     struct usb_device    *hdev = hub->hdev;
  6     struct usb_hcd        *hcd = bus_to_hcd(hdev->bus);
  7     struct usb_port        *port_dev = hub->ports[port1 - 1];
  8     int            retries, operations, retval, i;
  9     unsigned        delay = HUB_SHORT_RESET_TIME;
 10     enum usb_device_speed    oldspeed = udev->speed;
 11     const char        *speed;
 12     int            devnum = udev->devnum;
 13     const char        *driver_name;
 14     bool            do_new_scheme;
 15 
 16     /* root hub ports have a slightly longer reset period
 17      * (from USB 2.0 spec, section 7.1.7.5)
 18      */
 19     if (!hdev->parent) {
 20         delay = HUB_ROOT_RESET_TIME;
 21         if (port1 == hdev->bus->otg_port)
 22             hdev->bus->b_hnp_enable = 0;
 23     }
 24 
 25     /* Some low speed devices have problems with the quick delay, so */
 26     /*  be a bit pessimistic with those devices. RHbug #23670 */
 27     if (oldspeed == USB_SPEED_LOW)
 28         delay = HUB_LONG_RESET_TIME;
 29 
 30     mutex_lock(hcd->address0_mutex);
 31 
 32     /* Reset the device; full speed may morph to high speed */
 33     /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
 34     retval = hub_port_reset(hub, port1, udev, delay, false);
 35     if (retval < 0)        /* error or disconnect */
 36         goto fail;
 37     /* success, speed is known */
 38 
 39     retval = -ENODEV;
 40 
 41     /* Don't allow speed changes at reset, except usb 3.0 to faster */
 42     if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed &&
 43         !(oldspeed == USB_SPEED_SUPER && udev->speed > oldspeed)) {
 44         dev_dbg(&udev->dev, "device reset changed speed!\n");
 45         goto fail;
 46     }
 47     oldspeed = udev->speed;
 48 
 49     /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
 50      * it's fixed size except for full speed devices.
 51      * For Wireless USB devices, ep0 max packet is always 512 (tho
 52      * reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
 53      */
 54     switch (udev->speed) {
 55     case USB_SPEED_SUPER_PLUS:
 56     case USB_SPEED_SUPER:
 57     case USB_SPEED_WIRELESS:    /* fixed at 512 */
 58         udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
 59         break;
 60     case USB_SPEED_HIGH:        /* fixed at 64 */
 61         udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
 62         break;
 63     case USB_SPEED_FULL:        /* 8, 16, 32, or 64 */
 64         /* to determine the ep0 maxpacket size, try to read
 65          * the device descriptor to get bMaxPacketSize0 and
 66          * then correct our initial guess.
 67          */
 68         udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
 69         break;
 70     case USB_SPEED_LOW:        /* fixed at 8 */
 71         udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8);
 72         break;
 73     default:
 74         goto fail;
 75     }
 76 
 77     if (udev->speed == USB_SPEED_WIRELESS)
 78         speed = "variable speed Wireless";
 79     else
 80         speed = usb_speed_string(udev->speed);
 81 
 82     /*
 83      * The controller driver may be NULL if the controller device
 84      * is the middle device between platform device and roothub.
 85      * This middle device may not need a device driver due to
 86      * all hardware control can be at platform device driver, this
 87      * platform device is usually a dual-role USB controller device.
 88      */
 89     if (udev->bus->controller->driver)
 90         driver_name = udev->bus->controller->driver->name;
 91     else
 92         driver_name = udev->bus->sysdev->driver->name;
 93 
 94     if (udev->speed < USB_SPEED_SUPER)
 95         dev_info(&udev->dev,
 96                 "%s %s USB device number %d using %s\n",
 97                 (udev->config) ? "reset" : "new", speed,
 98                 devnum, driver_name);
 99 
100     /* Set up TT records, if needed  */
101     if (hdev->tt) {
102         udev->tt = hdev->tt;
103         udev->ttport = hdev->ttport;
104     } else if (udev->speed != USB_SPEED_HIGH
105             && hdev->speed == USB_SPEED_HIGH) {
106         if (!hub->tt.hub) {
107             dev_err(&udev->dev, "parent hub has no TT\n");
108             retval = -EINVAL;
109             goto fail;
110         }
111         udev->tt = &hub->tt;
112         udev->ttport = port1;
113     }
114 
115     /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?
116      * Because device hardware and firmware is sometimes buggy in
117      * this area, and this is how Linux has done it for ages.
118      * Change it cautiously.
119      *
120      * NOTE:  If use_new_scheme() is true we will start by issuing
121      * a 64-byte GET_DESCRIPTOR request.  This is what Windows does,
122      * so it may help with some non-standards-compliant devices.
123      * Otherwise we start with SET_ADDRESS and then try to read the
124      * first 8 bytes of the device descriptor to get the ep0 maxpacket
125      * value.
126      */
127     do_new_scheme = use_new_scheme(udev, retry_counter, port_dev);
128 
129     for (retries = 0; retries < GET_DESCRIPTOR_TRIES; (++retries, msleep(100))) {
130         if (do_new_scheme) {
131             struct usb_device_descriptor *buf;
132             int r = 0;
133 
134             retval = hub_enable_device(udev);
135             if (retval < 0) {
136                 dev_err(&udev->dev,
137                     "hub failed to enable device, error %d\n",
138                     retval);
139                 goto fail;
140             }
141 
142 #define GET_DESCRIPTOR_BUFSIZE    64
143             buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
144             if (!buf) {
145                 retval = -ENOMEM;
146                 continue;
147             }
148 
149             /* Retry on all errors; some devices are flakey.
150              * 255 is for WUSB devices, we actually need to use
151              * 512 (WUSB1.0[4.8.1]).
152              */
153             for (operations = 0; operations < GET_MAXPACKET0_TRIES;
154                     ++operations) {
155                 buf->bMaxPacketSize0 = 0;
156                 r = usb_control_msg(udev, usb_rcvaddr0pipe(),
157                     USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
158                     USB_DT_DEVICE << 8, 0,
159                     buf, GET_DESCRIPTOR_BUFSIZE,
160                     initial_descriptor_timeout);
161                 switch (buf->bMaxPacketSize0) {
162                 case 8: case 16: case 32: case 64: case 255:
163                     if (buf->bDescriptorType ==
164                             USB_DT_DEVICE) {
165                         r = 0;
166                         break;
167                     }
168                     fallthrough;
169                 default:
170                     if (r == 0)
171                         r = -EPROTO;
172                     break;
173                 }
174                 /*
175                  * Some devices time out if they are powered on
176                  * when already connected. They need a second
177                  * reset. But only on the first attempt,
178                  * lest we get into a time out/reset loop
179                  */
180                 if (r == 0 || (r == -ETIMEDOUT &&
181                         retries == 0 &&
182                         udev->speed > USB_SPEED_FULL))
183                     break;
184             }
185             udev->descriptor.bMaxPacketSize0 =
186                     buf->bMaxPacketSize0;
187             kfree(buf);
188 
189             retval = hub_port_reset(hub, port1, udev, delay, false);
190             if (retval < 0)        /* error or disconnect */
191                 goto fail;
192             if (oldspeed != udev->speed) {
193                 dev_dbg(&udev->dev,
194                     "device reset changed speed!\n");
195                 retval = -ENODEV;
196                 goto fail;
197             }
198             if (r) {
199                 if (r != -ENODEV)
200                     dev_err(&udev->dev, "device descriptor read/64, error %d\n",
201                             r);
202                 retval = -EMSGSIZE;
203                 continue;
204             }
205 #undef GET_DESCRIPTOR_BUFSIZE
206         }
207 
208         /*
209          * If device is WUSB, we already assigned an
210          * unauthorized address in the Connect Ack sequence;
211          * authorization will assign the final address.
212          */
213         if (udev->wusb == 0) {
214             for (operations = 0; operations < SET_ADDRESS_TRIES; ++operations) {
215                 retval = hub_set_address(udev, devnum);
216                 if (retval >= 0)
217                     break;
218                 msleep(200);
219             }
220             if (retval < 0) {
221                 if (retval != -ENODEV)
222                     dev_err(&udev->dev, "device not accepting address %d, error %d\n",
223                             devnum, retval);
224                 goto fail;
225             }
226             if (udev->speed >= USB_SPEED_SUPER) {
227                 devnum = udev->devnum;
228                 dev_info(&udev->dev,
229                         "%s SuperSpeed%s%s USB device number %d using %s\n",
230                         (udev->config) ? "reset" : "new",
231                      (udev->speed == USB_SPEED_SUPER_PLUS) ?
232                             " Plus" : "",
233                      (udev->ssp_rate == USB_SSP_GEN_2x2) ?
234                             " Gen 2x2" :
235                      (udev->ssp_rate == USB_SSP_GEN_2x1) ?
236                             " Gen 2x1" :
237                      (udev->ssp_rate == USB_SSP_GEN_1x2) ?
238                             " Gen 1x2" : "",
239                      devnum, driver_name);
240             }
241 
242             /* cope with hardware quirkiness:
243              *  - let SET_ADDRESS settle, some device hardware wants it
244              *  - read ep0 maxpacket even for high and low speed,
245              */
246             msleep(10);
247             if (do_new_scheme)
248                 break;
249         }
250 
251         retval = usb_get_device_descriptor(udev, 8);
252         if (retval < 8) {
253             if (retval != -ENODEV)
254                 dev_err(&udev->dev,
255                     "device descriptor read/8, error %d\n",
256                     retval);
257             if (retval >= 0)
258                 retval = -EMSGSIZE;
259         } else {
260             u32 delay;
261 
262             retval = 0;
263 
264             delay = udev->parent->hub_delay;
265             udev->hub_delay = min_t(u32, delay,
266                         USB_TP_TRANSMISSION_DELAY_MAX);
267             retval = usb_set_isoch_delay(udev);
268             if (retval) {
269                 dev_dbg(&udev->dev,
270                     "Failed set isoch delay, error %d\n",
271                     retval);
272                 retval = 0;
273             }
274             break;
275         }
276     }
277     if (retval)
278         goto fail;
279 
280     /*
281      * Some superspeed devices have finished the link training process
282      * and attached to a superspeed hub port, but the device descriptor
283      * got from those devices show they aren't superspeed devices. Warm
284      * reset the port attached by the devices can fix them.
285      */
286     if ((udev->speed >= USB_SPEED_SUPER) &&
287             (le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) {
288         dev_err(&udev->dev, "got a wrong device descriptor, "
289                 "warm reset device\n");
290         hub_port_reset(hub, port1, udev,
291                 HUB_BH_RESET_TIME, true);
292         retval = -EINVAL;
293         goto fail;
294     }
295 
296     if (udev->descriptor.bMaxPacketSize0 == 0xff ||
297             udev->speed >= USB_SPEED_SUPER)
298         i = 512;
299     else
300         i = udev->descriptor.bMaxPacketSize0;
301     if (usb_endpoint_maxp(&udev->ep0.desc) != i) {
302         if (udev->speed == USB_SPEED_LOW ||
303                 !(i == 8 || i == 16 || i == 32 || i == 64)) {
304             dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", i);
305             retval = -EMSGSIZE;
306             goto fail;
307         }
308         if (udev->speed == USB_SPEED_FULL)
309             dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);
310         else
311             dev_warn(&udev->dev, "Using ep0 maxpacket: %d\n", i);
312         udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);
313         usb_ep0_reinit(udev);
314     }
315 
316     retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
317     if (retval < (signed)sizeof(udev->descriptor)) {
318         if (retval != -ENODEV)
319             dev_err(&udev->dev, "device descriptor read/all, error %d\n",
320                     retval);
321         if (retval >= 0)
322             retval = -ENOMSG;
323         goto fail;
324     }
325 
326     usb_detect_quirks(udev);
327 
328     if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) {
329         retval = usb_get_bos_descriptor(udev);
330         if (!retval) {
331             udev->lpm_capable = usb_device_supports_lpm(udev);
332             usb_set_lpm_parameters(udev);
333         }
334     }
335 
336     retval = 0;
337     /* notify HCD that we have a device connected and addressed */
338     if (hcd->driver->update_device)
339         hcd->driver->update_device(hcd, udev);
340     hub_set_initial_usb2_lpm_policy(udev);
341 fail:
342     if (retval) {
343         hub_port_disable(hub, port1, 0);
344         update_devnum(udev, devnum);    /* for disconnect processing */
345     }
346     mutex_unlock(hcd->address0_mutex);
347     return retval;
348 }

 

在这个函数中首先重新连接了一次usb口

line34 行:retval = hub_port_reset(hub, port1, udev, delay, false);  

line42行: 

if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed &&
!(oldspeed == USB_SPEED_SUPER && udev->speed > oldspeed)) {
dev_dbg(&udev->dev, "device reset changed speed!\n");

这里 查看usb的速度是不是变化了 如果变化了则报错

后面从P54行到P75行表示的是速度和msg的packetsize的对应关系

line 127:

use_new_scheme 在usb3.0 中此enumeration scheme会造成USB3 在默认的状态下接收到数据。所以usb3 需要禁止这个枚举。

 

line 251:retval = usb_get_device_descriptor(udev, 8);

获得usb的描述符

如果得到描述符 那么我们就分配一个地址

 

usb_control_msg(udev, usb_rcvaddr0pipe) 这个函数是建立一个控制的urb 

 

 

 

 

USB 总线驱动程序的作用

1. 识别USB设备

1.1 分配地址 并告诉USB设备(set address)

1.2 发出命令获取描述符

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

 

3. 提供USB读写的函数

 

由于最新的linux版本usb的源码和之前的相差比较大所以我们直接参考官方文档给出的方法去做:

1.首先完成usb_driver 这个结构体

 

 

 其中,supports_autosuspend 表示的是是否支持usb自动悬挂。

USB 初始化

 

 

 ubs_register函数会把skel_driver 结构体注册到总线设备中。

 

 

 usb_deregister 会把注册的driver注销掉。

为了支持usb热插拔 我们需要MODULE_DEVICE_TABLE

 

上面的表只是一个例子 下面给一个真的table

static const struct usb_device_id usb_kbd_id_table[] = {
    { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
        USB_INTERFACE_PROTOCOL_KEYBOARD) },
    { }                        /* Terminating entry */
};

这个就是真的keyboard的table

 最后就是当usb的deviceID和driver注册的一样的时候就会call probe函数。

请注意 这里面driver的名字可以随便写因为usb设备貌似不看名字。

 

probe函数中经常用的知识点:

static int usb_kbd_probe(struct usb_interface *iface,
const struct usb_device_id *id)

 

1.struct usb_device *dev = interface_to_usbdev(iface) //这句说是把usb_interface 结构体转化为usb_device.

2. USB endpoint: endpoints指的是usb硬件的一个buffer 主设备都是从这个buffer中读或者写数据。usb设备中至少有一个endpoint 在地址0的位置可读可写这个endpoint是为了hotplug上去之后识别用的。

3.usb_host_interface 这是一个usb主的结构体。

4. bNumEndpoints 表示双向的Endpoints 必须只有一个 且在address0

5. usb_endpoint_is_int_in 是否endpoint是输入 方向(一边的device都是输入 从机)

6.pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); 创建一个和end point相连接的pipe 注意pipe是一个软件的概念 通道

7. URB:usb传输的数据块,包含usb信息的所有元素 可以用usb_submit_urb()去发送 如果发送出去返回成功信号。

8. usb_buff =  usb_alloc_coherent(dev, len, GFP_ATOMIC, &usb_buf_phys) 这个函数分配usb的buffer  表示最后存到哪里

9. usb_make_path(dev, mouse->phys, sizeof(mouse->phys)); 找到mouse->phy 的绝对路径
10. usb_fill_bulk_urb: 把数据写入urb

11.usb_submit_urb 此函数会把数据发送出去

 

12 usb_bulk_msg  函数是作为读usb里面的数据

 

posted on 2021-12-06 17:58  闲云潭影  阅读(213)  评论(0)    收藏  举报