USB驱动与设备
1. 在嵌入式设备中使用platform总线
#define PLATFORM_DRIVER platform_driver_rtl8672
struct platform_driver platform_driver_rtl8672 = {
.probe = ehci_rtl8672_drv_probe,
#ifdef CONFIG_HOTPLUG
.remove = ehci_rtl8672_drv_remove,
#endif
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "rtl8672-ehci",
},
};
static struct platform_device rtl8672_ehci = {
.name = "rtl8672-ehci",
.id = 0,
.dev = {
.release = usb_release,
.dma_mask = (void *)~0,
//.coherent_dma_mask = ~0,
},
.num_resources = ARRAY_SIZE(rtl8672_ehci_resources),
.resource = rtl8672_ehci_resources, /* 定义了中断号及寄存器地址等. */
};
int __init ehci_hcd_init(void)
{
int retval = 0;
retval = platform_driver_register(&PLATFORM_DRIVER);
if (retval < 0)
return retval;
retval = platform_device_register(&rtl8672_ehci);
return retval;
}
/*
* platform的驱动和设备使用简单匹配, 只比较驱动和设备的name是否一样. 如上面的"rtl8672-ehci".
*/
1. 怎样找到U盘的驱动程序呢?
当U盘插入到USB口时, hub_port_connect_change()函数被调用, 注意最后有一个usb_new_device(), 这里
将会调用usb_probe_interface(), 此函数由usb_register_driver注册的, 即usb_stor_register(&usb_stor_driver)
->usb_register->usb_register_driver.
/* Handle physical or logical connection change events.
* This routine is called when:
* a port connection-change occurs;
* a port enable-change occurs (often caused by EMI);
* usb_reset_device() encounters changed descriptors (as from
* a firmware download)
* caller already locked the hub
*/
static void hub_port_connect_change(struct usb_hub *hub, int port1,
u16 portstatus, u16 portchange)
{
// 精简版, 去除了错误处理 :-)
for (i = 0; i < SET_CONFIG_TRIES; i++) { /* 最大重试次数 */
struct usb_device *udev;
/* reallocate for each attempt, since references
* to the previous one can escape in various ways
*/
udev = usb_alloc_dev(hdev, hdev->bus, port1);
usb_set_device_state(udev, USB_STATE_POWERED);
/* set the address */
choose_address(udev);
/* reset and get descriptor */
status = hub_port_init(hub, udev, port1, i);
/* check for devices running slower than they could */
if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200
&& udev->speed == USB_SPEED_FULL
&& highspeed_hubs != 0)
check_highspeed (hub, udev, port1);
/* Run it through the hoops (find a driver, etc) */
if (!status) {
status = usb_new_device(udev);
if (status) {
spin_lock_irq(&device_state_lock);
hdev->children[port1-1] = NULL;
spin_unlock_irq(&device_state_lock);
}
}
status = hub_power_remaining(hub);
return;
}
}
/* called from driver core with dev locked */
static int usb_probe_interface(struct device *dev)
{
struct usb_driver *driver = to_usb_driver(dev->driver);
struct usb_interface *intf;
struct usb_device *udev;
const struct usb_device_id *id;
int error = -ENODEV;
if (is_usb_device(dev)) /* Sanity check */
return error;
intf = to_usb_interface(dev);
udev = interface_to_usbdev(intf);
id = usb_match_id(intf, driver->id_table);
if (!id)
id = usb_match_dynamic_id(intf, driver);
if (id) {
usb_autoresume_device(udev, 1);
/* Interface "power state" doesn't correspond to any hardware
* state whatsoever. We use it to record when it's bound to
* a driver that may start I/0: it's not frozen/quiesced.
*/
mark_active(intf);
intf->condition = USB_INTERFACE_BINDING;
/* The interface should always appear to be in use
* unless the driver suports autosuspend.
*/
intf->pm_usage_cnt = !(driver->supports_autosuspend);
error = driver->probe(intf, id);
if (error) {
mark_quiesced(intf);
intf->needs_remote_wakeup = 0;
intf->condition = USB_INTERFACE_UNBOUND;
} else
intf->condition = USB_INTERFACE_BOUND;
usb_autosuspend_device(udev, 1);
}
return error;
}