USB (Universal Serial Bus) 17) is one of the sophisticated peripheral interfaces based on the recent hardware progress. In the USB 2.0 specification announced in April 2000, a host computer controls various USB devices with 3 transfer speeds (1.5 Mbps, 12.0 Mbps, and 480 Mbps) and 4 transfer types (Control, Bulk, Interrupt, and Isochronous). These transfers are serialized and controlled by a dedicated hardware function which is named USB Host Controller. Figure 1 shows the USB device driver model in most operating systems. A USB Host Controller Driver (USB HCD) exists in the lowest layer of the device driver stack and abstracts the I/O interface of a host controller into a common API for USB device drivers. A USB PerDevice Drivers (USB PDD) is respon-sible for the control of each USB device. The key design of the USB driver stack is that a USB Host Controller and its USB HCD provide USB PDDs with abstracted data input/output for I/O buffers. Although a USB device and its USB PDD use the buffer to transfer some control data and corresponding reply data, the USB HCD do not distinguish between control and reply.
In USB device drivers, a USB Request Block (URB) presents USB I/O in a controller-independent form, which includes information about I/O;
I/O buffer
I/O direction (Input/Output)
I/O speed (1.5 Mbps/12 Mbps/480 Mbps)
I/O type (Control/Bulk/Interrupt/Isochronous)
I/O destination address
completion handler
An application or a device driver controls a USB device as follows:
A USB PDD converts I/O requests from another driver into URBs and submits these URBs to a USB HCD.
The USB HCD transfers data as de-scribed by the URB.
After I/O of the URB is completed, the completion handler of the URB is called in an interrupt context.
The USB PDD notifies the upper driver of the requested I/O completion.
A USB device and its USB PDD use 4 differ- ent transfer types depending on characteristics of the device. Control and Bulk transfer types are asynchronously scheduled into the rest of the bandwidth after the periodical transfers. Control transfer is the most fundamental one for enumeration and initialization of devices. In 480 Mbps mode, 20% of the bandwidth is reserved for Control transfer. Bulk transfer is used for the requests without any temporal re-striction, such as storage device I/O, which is the fastest transfer when the bus is available. Isochronous and Interrupt transfer types are pe-riodically scheduled. Isochronous transfer can move control data at a constant bit rate, which is useful to read image data from a USB cam-era or to write sound data to a USB speaker. Interrupt transfer confirms the maximum delay of the requested I/O. This is used for USB mice and keyboards, which move a small amount of data sporadically.
########## HOST ########## CONFIG_USB=y # += usb/core usb/storage/ usb/misc/ Support for Host-side USB # 作为 HOST 时用。要作为device,应该看 USB Gadget。EHCI HCD 代表USB2.0。USB1.1是 UHCI,OHCI # Say Y here if your computer has a host-side USB port and you want to use USB devices. You then need to say Y to at least one of the Host Controller Driver (HCD) options below. Choose a USB 1.1 controller, such as "UHCI HCD support" or "OHCI HCD support", and "EHCI HCD (USB 2.0) support" except for older systems that do not have USB 2.0 support. It doesn't normally hurt to select them all if you are not certain. # If your system has a device-side USB port, used in the peripheral side of the USB protocol, see the "USB Gadget" framework instead. #### controller driver #### CONFIG_USB_DWC2=y # usb/dwc2/dwc2.o USB HCD 驱动 CONFIG_USB_DWC2_DUAL_ROLE=y # 支持两种角色的工作模式(host/device)
########## DEVICE ########## CONFIG_USB_GADGET=y # += 作为USBdevice用。usb/gadget udc/ function/ legacy/ udc/udc-core.o CONFIG_USB_GADGET_VBUS_DRAW=2 # Maximum VBUS Power usage (2-500 mA) CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 # Number of storage pipeline buffers CONFIG_USB_LIBCOMPOSITE=y # += usb/gadget/libcomposite.o 复合设备驱动 CONFIG_USB_F_ACM=y # += usb/gadget/function/usb_f_acm.o CONFIG_USB_U_SERIAL=y # += usb/gadget/function/u_serial.o CONFIG_USB_U_ETHER=y # += usb/gadget/function/u_ether.o CONFIG_USB_U_AUDIO=y # += usb/gadget/function/u_audio.o CONFIG_USB_F_SERIAL=y # += usb/gadget/function/usb_f_serial.o CONFIG_USB_F_ECM=y # += usb/gadget/function/f_ecm.o CONFIG_USB_F_EEM=y # += usb/gadget/function/f_eem.o CONFIG_USB_F_RNDIS=y # += usb/gadget/function/usb_f_rndis.o CONFIG_USB_F_MASS_STORAGE=y # += usb/gadget/function/usb_f_mass_storage.o CONFIG_USB_F_FS=y # += usb/gadget/function/usb_f_fs.o CONFIG_USB_F_UAC1=y # += usb/gadget/function/usb_f_uac1.o CONFIG_USB_F_UVC=y # += usb/gadget/function/usb_f_uvc.o CONFIG_USB_CONFIGFS=y # 支持通过configfs对功能进行配置 USB Gadget functions configurable through configfs CONFIG_USB_CONFIGFS_SERIAL=y # Generic serial bulk in/out CONFIG_USB_CONFIGFS_ACM=y # Abstract Control Model (CDC ACM) CONFIG_USB_CONFIGFS_ECM=y # Ethernet Control Model (CDC ECM) CONFIG_USB_CONFIGFS_RNDIS=y # RNDIS CONFIG_USB_CONFIGFS_EEM=y # Ethernet Emulation Model (EEM) CONFIG_USB_CONFIGFS_MASS_STORAGE=y # Mass Storage CONFIG_USB_CONFIGFS_F_FS=y # Function filesystem (FunctionFS) # The Function Filesystem (FunctionFS) lets one create USB composite functions in user space in the same way GadgetFS lets one create USB gadgets in user space. CONFIG_USB_CONFIGFS_F_UAC1=y # Audio Class 1.0 CONFIG_USB_CONFIGFS_F_UVC=y # USB Webcam function CONFIG_USB_HID=y # hid/usbhid/usbhid.o 并非所有的PDD驱动实现都放在 usb 目录下
通过 Kconfig 文件中 tristate 的个数。只有为 tristate 才能编译为 ko 形式加载。int 的一般都只是以宏判断的形式嵌入在代码中,不过这个非绝对。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
config USB_LEDS_TRIGGER_USBPORT tristate "USB port LED trigger" depends on USB && LEDS_TRIGGERS help This driver allows LEDs to be controlled by USB events. Enabling this trigger allows specifying list of USB ports that should turn on LED when some USB device gets connected.
config USB_AUTOSUSPEND_DELAY int "Default autosuspend delay" depends on USB default 2 help The default autosuspend delay in seconds. Can be overridden with the usbcore.autosuspend command line or module parameter.
The default value Linux has always had is 2 seconds. Change this value if you want a different delay and cannot modify the command line or module parameter.
总之目前确认了 core 目录下可以编译出两个 ko 文件。usbcore.ko 以及 ledtrig-usbport.ko.
确定模块之后,就可以从 module 的init 函数去追代码。过程中自然会看到他调用其他 c 文件的方法。
/* If the device driver under consideration does not have a * id_table or a match function, then let the driver's probe * function decide. */ if (!udrv->id_table && !udrv->match) return1;
if (usb_dev->devnum < 0) { /* driver is often null here; dev_dbg() would oops */ pr_debug("usb %s: already deleted?\n", dev_name(dev)); return -ENODEV; } if (!usb_dev->bus) { pr_debug("usb %s: bus removed?\n", dev_name(dev)); return -ENODEV; }
/* per-device configurations are common */ if (add_uevent_var(env, "PRODUCT=%x/%x/%x", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), le16_to_cpu(usb_dev->descriptor.bcdDevice))) return -ENOMEM;
/* use a define to avoid include chaining to get THIS_MODULE & friends */ #define usb_register(driver) \ usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
/* * The workqueue needs to be freezable to avoid interfering with * USB-PERSIST port handover. Otherwise it might see that a full-speed * device was gone before the EHCI controller had handed its port * over to the companion full-speed controller. */ // 创建一个 workqueue to process hub events hub_wq = alloc_workqueue("usb_hub_wq", WQ_FREEZABLE, 0); if (hub_wq) return0;
/* Fall through if kernel_thread failed */ usb_deregister(&hub_driver); pr_err("%s: can't allocate workqueue for usb hub\n", usbcore_name);
staticintgeneric_probe(struct usb_device *udev) { /* Choose and set the configuration. This registers the interfaces * with the driver core and lets interface drivers bind to them. */ if (udev->authorized == 0) //至于udev->authorized,在root hub的初始化中,是会将其初始化为1的.后面的逻辑就更简单了.为root hub 选择一个配置然后再设定这个配置. dev_err(&udev->dev, "Device is not authorized for usage\n"); else { c = usb_choose_configuration(udev); //Usb2.0 spec上规定,对于hub设备,只能有一个config,一个interface,一个endpoint.实际上,在这里,对hub的选择约束不大,反正就一个配置,不管怎么样,选择和设定都是这个配置. if (c >= 0) { err = usb_set_configuration(udev, c); if (err && err != -ENODEV) { dev_err(&udev->dev, "can't set config #%d, error %d\n", c, err); /* This need not be fatal. The user can try to * set other configurations. */ } } } /* USB device state == configured ... usable */ usb_notify_add_device(udev); return0; }
root@h:usb# dmesg | tail -n 20 [45807.088223] usb 1-9.4: New USB device found, idVendor=0403, idProduct=6001, bcdDevice= 6.00 [45807.088238] usb 1-9.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [45807.088244] usb 1-9.4: Product: FT232R USB UART [45807.088248] usb 1-9.4: Manufacturer: FTDI [45807.088252] usb 1-9.4: SerialNumber: A50285BI [45807.096989] ftdi_sio 1-9.4:1.0: FTDI USB Serial Device converter detected [45807.097079] usb 1-9.4: Detected FT232R [45807.097821] usb 1-9.4: FTDI USB Serial Device converter now attached to ttyUSB0 [45956.898368] usb 1-12: new full-speed USB device number 16 using xhci_hcd [45957.039833] usb 1-12: New USB device found, idVendor=320f, idProduct=5055, bcdDevice= 1.04 [45957.039852] usb 1-12: New USB device strings: Mfr=1, Product=2, SerialNumber=0 [45957.039859] usb 1-12: Product: VGN N75 PRO [45957.039864] usb 1-12: Manufacturer: Telink [45957.049757] input: Telink VGN N75 PRO as /devices/pci0000:00/0000:00:14.0/usb1/1-12/1-12:1.0/0003:320F:5055.0007/input/input33 [45957.102483] hid-generic 0003:320F:5055.0007: input,hidraw3: USB HID v1.11 Keyboard [Telink VGN N75 PRO ] on usb-0000:00:14.0-12/input0 [45957.118181] input: Telink VGN N75 PRO Keyboard as /devices/pci0000:00/0000:00:14.0/usb1/1-12/1-12:1.1/0003:320F:5055.0008/input/input34 [45957.169742] input: Telink VGN N75 PRO as /devices/pci0000:00/0000:00:14.0/usb1/1-12/1-12:1.1/0003:320F:5055.0008/input/input35 [45957.169984] input: Telink VGN N75 PRO as /devices/pci0000:00/0000:00:14.0/usb1/1-12/1-12:1.1/0003:320F:5055.0008/input/input36 [45957.170313] input: Telink VGN N75 PRO Mouse as /devices/pci0000:00/0000:00:14.0/usb1/1-12/1-12:1.1/0003:320F:5055.0008/input/input37 [45957.170779] hid-generic 0003:320F:5055.0008: input,hiddev2,hidraw4: USB HID v1.11 Keyboard [Telink VGN N75 PRO ] on usb-0000:00:14.0-12/input1 root@h:usb# ls hiddev0 hiddev1 hiddev2 root@h:usb# ls -lh total 0 crw------- 1 root root 180, 0 9月 1 09:12 hiddev0 crw------- 1 root root 180, 1 9月 1 09:12 hiddev1 crw------- 1 root root 180, 2 9月 1 21:58 hiddev2 root@h:usb#
structusb_hub { structusb_port **ports;/* array of usb_port pointers */ };
/** * struct usb port - kernel's representation of a usb port * @child: usb device attached to the port * @dev: generic device interface * @port_owner: port's owner * @peer: related usb2 and usb3 ports (share the same connector) * @req: default pm qos request for hubs without port power control * @connect_type: port's connect type * @location: opaque representation of platform connector location * @status_lock: synchronize port_event() vs usb_port_{suspend|resume} * @portnum: port index num based one * @is_superspeed cache super-speed status * @usb3_lpm_u1_permit: whether USB3 U1 LPM is permitted. * @usb3_lpm_u2_permit: whether USB3 U2 LPM is permitted. */ structusb_port { structusb_device *child; structdevicedev; structusb_dev_state *port_owner; structusb_port *peer; structdev_pm_qos_request *req; enumusb_port_connect_typeconnect_type; usb_port_location_t location; structmutexstatus_lock; u32 over_current_count; u8 portnum; u32 quirks; unsignedint is_superspeed:1; unsignedint usb3_lpm_u1_permit:1; unsignedint usb3_lpm_u2_permit:1; };