Chinaunix首页 | 论坛 | 博客
  • 博客访问: 203409
  • 博文数量: 68
  • 博客积分: 529
  • 博客等级: 中士
  • 技术积分: 721
  • 用 户 组: 普通用户
  • 注册时间: 2007-08-10 16:38
文章分类

全部博文(68)

文章存档

2014年(2)

2013年(4)

2012年(16)

2011年(34)

2010年(4)

2009年(8)

分类: LINUX

2012-11-05 10:11:04

1) 写一个usb driver需要调用 usb_register_driver 来注册。

点击(此处)折叠或打开

  1. /**
  2. * usb_register_driver - register a USB interface driver
  3. * @new_driver: USB operations for the interface driver
  4. * @owner: module owner of this driver.
  5. * @mod_name: module name string
  6. *
  7. * Registers a USB interface driver with the USB core. The list of
  8. * unattached interfaces will be rescanned whenever a new driver is
  9. * added, allowing the new driver to attach to any recognized interfaces.
  10. * Returns a negative error code on failure and 0 on success.
  11. *
  12. * NOTE: if you want your driver to use the USB major number, you must call
  13. * usb_register_dev() to enable that functionality. This function no longer
  14. * takes care of that.
  15. */
  16. int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
  17. const char *mod_name)
  18. {
  19. int retval = 0;
  20. if (usb_disabled())
  21. return -ENODEV;
  22. new_driver->drvwrap.for_devices = 0;
  23. new_driver->drvwrap.driver.name = (char *) new_driver->name;
  24. new_driver->drvwrap.driver.bus = &usb_bus_type;
  25. new_driver->drvwrap.driver.probe = usb_probe_interface;
  26. new_driver->drvwrap.driver.remove = usb_unbind_interface;
  27. new_driver->drvwrap.driver.owner = owner;
  28. new_driver->drvwrap.driver.mod_name = mod_name;
  29. spin_lock_init(&new_driver->dynids.lock);
  30. INIT_LIST_HEAD(&new_driver->dynids.list);
  31. retval = driver_register(&new_driver->drvwrap.driver);
  32. if (retval)
  33. goto out;
  34. usbfs_update_special();
  35. retval = usb_create_newid_file(new_driver);
  36. if (retval)
  37. goto out_newid;
  38. retval = usb_create_removeid_file(new_driver);
  39. if (retval)
  40. goto out_removeid;
  41. pr_info("%s: registered new interface driver %s\n",
  42. usbcore_name, new_driver->name);
  43. out:
  44. return retval;
  45. out_removeid:
  46. usb_remove_newid_file(new_driver);
  47. out_newid:
  48. driver_unregister(&new_driver->drvwrap.driver);
  49. printk(KERN_ERR "%s: error %d registering interface "
  50. " driver %s\n",
  51. usbcore_name, retval, new_driver->name);
  52. goto out;
  53. }
2) usb bus

点击(此处)折叠或打开

  1. struct bus_type usb_bus_type = {
  2. .name = "usb",
  3. .match = usb_device_match,
  4. .uevent = usb_uevent,
  5. .pm = &usb_bus_pm_ops,
  6. };
这个函数定义了usb 设备如何mach usb  driver 的。

点击(此处)折叠或打开

  1. /**
  2. * usb_match_id - find first usb_device_id matching device or interface
  3. * @interface: the interface of interest
  4. * @id: array of usb_device_id structures, terminated by zero entry
  5. *
  6. * usb_match_id searches an array of usb_device_id's and returns
  7. * the first one matching the device or interface, or null.
  8. * This is used when binding (or rebinding) a driver to an interface.
  9. * Most USB device drivers will use this indirectly, through the usb core,
  10. * but some layered driver frameworks use it directly.
  11. * These device tables are exported with MODULE_DEVICE_TABLE, through
  12. * modutils, to support the driver loading functionality of USB hotplugging.
  13. *
  14. * What Matches:
  15. *
  16. * The "match_flags" element in a usb_device_id controls which
  17. * members are used. If the corresponding bit is set, the
  18. * value in the device_id must match its corresponding member
  19. * in the device or interface descriptor, or else the device_id
  20. * does not match.
  21. *
  22. * "driver_info" is normally used only by device drivers,
  23. * but you can create a wildcard "matches anything" usb_device_id
  24. * as a driver's "modules.usbmap" entry if you provide an id with
  25. * only a nonzero "driver_info" field. If you do this, the USB device
  26. * driver's probe() routine should use additional intelligence to
  27. * decide whether to bind to the specified interface.
  28. *
  29. * What Makes Good usb_device_id Tables:
  30. *
  31. * The match algorithm is very simple, so that intelligence in
  32. * driver selection must come from smart driver id records.
  33. * Unless you have good reasons to use another selection policy,
  34. * provide match elements only in related groups, and order match
  35. * specifiers from specific to general. Use the macros provided
  36. * for that purpose if you can.
  37. *
  38. * The most specific match specifiers use device descriptor
  39. * data. These are commonly used with product-specific matches;
  40. * the USB_DEVICE macro lets you provide vendor and product IDs,
  41. * and you can also match against ranges of product revisions.
  42. * These are widely used for devices with application or vendor
  43. * specific bDeviceClass values.
  44. *
  45. * Matches based on device class/subclass/protocol specifications
  46. * are slightly more general; use the USB_DEVICE_INFO macro, or
  47. * its siblings. These are used with single-function devices
  48. * where bDeviceClass doesn't specify that each interface has
  49. * its own class.
  50. *
  51. * Matches based on interface class/subclass/protocol are the
  52. * most general; they let drivers bind to any interface on a
  53. * multiple-function device. Use the USB_INTERFACE_INFO
  54. * macro, or its siblings, to match class-per-interface style
  55. * devices (as recorded in bInterfaceClass).
  56. *
  57. * Note that an entry created by USB_INTERFACE_INFO won't match
  58. * any interface if the device class is set to Vendor-Specific.
  59. * This is deliberate; according to the USB spec the meanings of
  60. * the interface class/subclass/protocol for these devices are also
  61. * vendor-specific, and hence matching against a standard product
  62. * class wouldn't work anyway. If you really want to use an
  63. * interface-based match for such a device, create a match record
  64. * that also specifies the vendor ID. (Unforunately there isn't a
  65. * standard macro for creating records like this.)
  66. *
  67. * Within those groups, remember that not all combinations are
  68. * meaningful. For example, don't give a product version range
  69. * without vendor and product IDs; or specify a protocol without
  70. * its associated class and subclass.
  71. */
  72. const struct usb_device_id *usb_match_id(struct usb_interface *interface,
  73. const struct usb_device_id *id)
  74. {
  75. /* proc_connectinfo in devio.c may call us with id == NULL. */
  76. if (id == NULL)
  77. return NULL;
  78. /* It is important to check that id->driver_info is nonzero,
  79. since an entry that is all zeroes except for a nonzero
  80. id->driver_info is the way to create an entry that
  81. indicates that the driver want to examine every
  82. device and interface. */
  83. for (; id->idVendor || id->idProduct || id->bDeviceClass ||
  84. id->bInterfaceClass || id->driver_info; id++) {
  85. if (usb_match_one_id(interface, id))
  86. return id;
  87. }
  88. return NULL;
  89. }
for 3G modem serial usb driver , 我们用venderid 和productid以及接口来匹配。

点击(此处)折叠或打开

  1. /* returns 0 if no match, 1 if match */
  2. int usb_match_one_id(struct usb_interface *interface,
  3. const struct usb_device_id *id)
  4. {
  5. struct usb_host_interface *intf;
  6. struct usb_device *dev;
  7. /* proc_connectinfo in devio.c may call us with id == NULL. */
  8. if (id == NULL)
  9. return 0;
  10. intf = interface->cur_altsetting;
  11. dev = interface_to_usbdev(interface);
  12. if (!usb_match_device(dev, id))
  13. return 0;
  14. /* The interface class, subclass, and protocol should never be
  15. * checked for a match if the device class is Vendor Specific,
  16. * unless the match record specifies the Vendor ID. */
  17. if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC &&
  18. !(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
  19. (id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |
  20. USB_DEVICE_ID_MATCH_INT_SUBCLASS |
  21. USB_DEVICE_ID_MATCH_INT_PROTOCOL)))
  22. return 0;
  23. if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
  24. (id->bInterfaceClass != intf->desc.bInterfaceClass))
  25. return 0;
  26. if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
  27. (id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))
  28. return 0;
  29. if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
  30. (id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
  31. return 0;
  32. return 1;
  33. }


这个是usb driver pm 的调用栈,我们可以看到它采用了runtime pm的机制。

点击(此处)折叠或打开

  1. [<c003e5a0>] (unwind_backtrace+0x0/0xf0) from [<c02b6448>] (option_suspend+0x6c/0x98)
  2. [<c02b6448>] (option_suspend+0x6c/0x98) from [<c02b2b18>] (usb_serial_suspend+0x38/0x8c)
  3. [<c02b2b18>] (usb_serial_suspend+0x38/0x8c) from [<c029cd70>] (usb_suspend_both+0x7c/0x1d0)
  4. [<c029cd70>] (usb_suspend_both+0x7c/0x1d0) from [<c029cf04>] (usb_runtime_suspend+0x40/0x8c)
  5. [<c029cf04>] (usb_runtime_suspend+0x40/0x8c) from [<c023ce04>] (__pm_runtime_suspend+0x1e0/0x46c)
  6. [<c023ce04>] (__pm_runtime_suspend+0x1e0/0x46c) from [<c023d0fc>] (pm_runtime_work+0x6c/0xa8)
  7. [<c023d0fc>] (pm_runtime_work+0x6c/0xa8) from [<c007d888>] (worker_thread+0x180/0x22c)
  8. [<c007d888>] (worker_thread+0x180/0x22c) from [<c0080ed8>] (kthread+0x78/0x80)
  9. [<c0080ed8>] (kthread+0x78/0x80) from [<c003a9e0>] (kernel_thread_exit+0x0/0x8)



usb 设备的探测:当有设备插入和拔出时, 此函数会调用,


/* 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_and_verify_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)
{
struct usb_device *hdev = hub->hdev;
struct device *hub_dev = hub->intfdev;
struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
unsigned wHubCharacteristics =
le16_to_cpu(hub->descriptor->wHubCharacteristics);
struct usb_device *udev;
int status, i;

dev_dbg (hub_dev,
"port %d, status %04x, change %04x, %s\n",
port1, portstatus, portchange, portspeed (portstatus));

#ifdef MXS_USB_HOST_HACK
{
struct device *dev = hcd->self.controller;
struct fsl_usb2_platform_data *pdata;

pdata = (struct fsl_usb2_platform_data *)dev->platform_data;
if (dev->parent && dev->type) {
if (port1 == 1 && pdata->platform_init)
pdata->platform_init(NULL);
}
if (port1 == 1) {
if (!(portstatus&USB_PORT_STAT_CONNECTION)) {
/* Must clear HOSTDISCONDETECT when disconnect*/
fsl_platform_set_usb_phy_dis(pdata, 0);
}
}
}
#endif

if (hub->has_indicators) {
set_port_led(hub, port1, HUB_LED_AUTO);
hub->indicator[port1-1] = INDICATOR_AUTO;
}

#ifdef CONFIG_USB_OTG
/* during HNP, don't repeat the debounce */
if (hdev->bus->is_b_host)
portchange &= ~(USB_PORT_STAT_C_CONNECTION |
USB_PORT_STAT_C_ENABLE);
#endif

/* Try to resuscitate an existing device */
udev = hdev->children[port1-1];
if ((portstatus & USB_PORT_STAT_CONNECTION) && udev &&
udev->state != USB_STATE_NOTATTACHED) {
usb_lock_device(udev);
if (portstatus & USB_PORT_STAT_ENABLE) {
status = 0; /* Nothing to do */

#ifdef CONFIG_USB_SUSPEND
} else if (udev->state == USB_STATE_SUSPENDED &&
udev->persist_enabled) {
/* For a suspended device, treat this as a
* remote wakeup event.
*/
status = usb_remote_wakeup(udev);
#endif

} else {
status = -ENODEV; /* Don't resuscitate */
}
usb_unlock_device(udev);

if (status == 0) {
clear_bit(port1, hub->change_bits);
return;
}
}

/* Disconnect any existing devices under this port */
if (udev)
usb_disconnect(&hdev->children[port1-1]);
clear_bit(port1, hub->change_bits);

/* We can forget about a "removed" device when there's a physical
* disconnect or the connect status changes.
*/
if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
(portchange & USB_PORT_STAT_C_CONNECTION))
clear_bit(port1, hub->removed_bits);

if (portchange & (USB_PORT_STAT_C_CONNECTION |
USB_PORT_STAT_C_ENABLE)) {
status = hub_port_debounce(hub, port1);
if (status < 0) {
if (printk_ratelimit())
dev_err(hub_dev, "connect-debounce failed, "
"port %d disabled\n", port1);
portstatus &= ~USB_PORT_STAT_CONNECTION;
} else {
portstatus = status;
}
}

/* Return now if debouncing failed or nothing is connected or
* the device was "removed".
*/
if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
test_bit(port1, hub->removed_bits)) {

/* maybe switch power back on (e.g. root hub was reset) */
if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
&& !(portstatus & USB_PORT_STAT_POWER))
set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);

if (portstatus & USB_PORT_STAT_ENABLE)
  goto done;
return;
}

for (i = 0; i < SET_CONFIG_TRIES; i++) {

/* reallocate for each attempt, since references
* to the previous one can escape in various ways
*/
udev = usb_alloc_dev(hdev, hdev->bus, port1);
if (!udev) {
dev_err (hub_dev,
"couldn't allocate port %d usb_device\n",
port1);
goto done;
}

usb_set_device_state(udev, USB_STATE_POWERED);
  udev->bus_mA = hub->mA_per_port;
udev->level = hdev->level + 1;
udev->wusb = hub_is_wusb(hub);

/*
* USB 3.0 devices are reset automatically before the connect
* port status change appears, and the root hub port status
* shows the correct speed.  We also get port change
* notifications for USB 3.0 devices from the USB 3.0 portion of
* an external USB 3.0 hub, but this isn't handled correctly yet
* FIXME.
*/

if (!(hcd->driver->flags & HCD_USB3))
udev->speed = USB_SPEED_UNKNOWN;
else if ((hdev->parent == NULL) &&
(portstatus & USB_PORT_STAT_SUPER_SPEED))
udev->speed = USB_SPEED_SUPER;
else
udev->speed = USB_SPEED_UNKNOWN;

/*
* xHCI needs to issue an address device command later
* in the hub_port_init sequence for SS/HS/FS/LS devices.
*/
if (!(hcd->driver->flags & HCD_USB3)) {
/* set the address */
choose_address(udev);
if (udev->devnum <= 0) {
status = -ENOTCONN; /* Don't retry */
goto loop;
}
}

/* reset (non-USB 3.0 devices) and get descriptor */
status = hub_port_init(hub, udev, port1, i);
if (status < 0)
goto loop;

usb_detect_quirks(udev);
if (udev->quirks & USB_QUIRK_DELAY_INIT)
msleep(1000);

/* consecutive bus-powered hubs aren't reliable; they can
* violate the voltage drop budget.  if the new child has
* a "powered" LED, users should notice we didn't enable it
* (without reading syslog), even without per-port LEDs
* on the parent.
*/
if (udev->descriptor.bDeviceClass == USB_CLASS_HUB
&& udev->bus_mA <= 100) {
u16 devstat;

status = usb_get_status(udev, USB_RECIP_DEVICE, 0,
&devstat);
if (status < 2) {
dev_dbg(&udev->dev, "get status %d ?\n", status);
goto loop_disable;
}
le16_to_cpus(&devstat);
if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
dev_err(&udev->dev,
"can't connect bus-powered hub "
"to this port\n");
if (hub->has_indicators) {
hub->indicator[port1-1] =
INDICATOR_AMBER_BLINK;
schedule_delayed_work (&hub->leds, 0);
}
status = -ENOTCONN; /* Don't retry */
goto loop_disable;
}
}
 
/* 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);

/* Store the parent's children[] pointer.  At this point
* udev becomes globally accessible, although presumably
* no one will look at it until hdev is unlocked.
*/
status = 0;

/* We mustn't add new devices if the parent hub has
* been disconnected; we would race with the
* recursively_mark_NOTATTACHED() routine.
*/
spin_lock_irq(&device_state_lock);
if (hdev->state == USB_STATE_NOTATTACHED)
status = -ENOTCONN;
else
hdev->children[port1-1] = udev;
spin_unlock_irq(&device_state_lock);

/* 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);
}
}

if (status)
goto loop_disable;

status = hub_power_remaining(hub);
if (status)
dev_dbg(hub_dev, "%dmA power budget left\n", status);

return;

loop_disable:
hub_port_disable(hub, port1, 1);
loop:
usb_ep0_reinit(udev);
release_address(udev);
hub_free_dev(udev);
usb_put_dev(udev);
if ((status == -ENOTCONN) || (status == -ENOTSUPP))
break;
}
if (hub->hdev->parent ||
!hcd->driver->port_handed_over ||
!(hcd->driver->port_handed_over)(hcd, port1))
dev_err(hub_dev, "unable to enumerate USB device on port %d\n",
port1);
 
done:
hub_port_disable(hub, port1, 1);
if (hcd->driver->relinquish_port && !hub->hdev->parent)
hcd->driver->relinquish_port(hcd, port1);
}




usb driver的probe 


new_driver->drvwrap.for_devices = 0;
new_driver->drvwrap.driver.name = (char *) new_driver->name;
new_driver->drvwrap.driver.bus = &usb_bus_type;
new_driver->drvwrap.driver.probe = usb_probe_interface;
new_driver->drvwrap.driver.remove = usb_unbind_interface;
new_driver->drvwrap.driver.owner = owner;
new_driver->drvwrap.driver.mod_name = mod_name;
spin_lock_init(&new_driver->dynids.lock);
INIT_LIST_HEAD(&new_driver->dynids.list);


/* 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 = to_usb_interface(dev);
struct usb_device *udev = interface_to_usbdev(intf);
const struct usb_device_id *id;
int error = -ENODEV;

dev_dbg(dev, "%s\n", __func__);

intf->needs_binding = 0;

if (usb_device_is_owned(udev))
return error;

if (udev->authorized == 0) {
dev_err(&intf->dev, "Device is not authorized for usage\n");
return error;
}

id = usb_match_id(intf, driver->id_table);
if (!id)
id = usb_match_dynamic_id(intf, driver);
if (!id)
return error;

dev_dbg(dev, "%s - got id\n", __func__);

error = usb_autoresume_device(udev);
if (error)
return error;

intf->condition = USB_INTERFACE_BINDING;

/* Probed interfaces are initially active.  They are
* runtime-PM-enabled only if the driver has autosuspend support.
* They are sensitive to their children's power states.
*/
pm_runtime_set_active(dev);
pm_suspend_ignore_children(dev, false);
if (driver->supports_autosuspend)
pm_runtime_enable(dev);

/* Carry out a deferred switch to altsetting 0 */
if (intf->needs_altsetting0) {
error = usb_set_interface(udev, intf->altsetting[0].
desc.bInterfaceNumber, 0);
if (error < 0)
goto err;
intf->needs_altsetting0 = 0;
}

error = driver->probe(intf, id);   /* 调用新的驱动的probe */
if (error)
goto err;

intf->condition = USB_INTERFACE_BOUND;
usb_autosuspend_device(udev);
return error;

 err:
intf->needs_remote_wakeup = 0;
intf->condition = USB_INTERFACE_UNBOUND;
usb_cancel_queued_reset(intf);

/* Unbound interfaces are always runtime-PM-disabled and -suspended */
if (driver->supports_autosuspend)
pm_runtime_disable(dev);
pm_runtime_set_suspended(dev);

usb_autosuspend_device(udev);
return error;
}


阅读(955) | 评论(0) | 转发(0) |
0

上一篇:linux程序崩溃调试技术

下一篇:vim使用

给主人留下些什么吧!~~