drivers/usb/core/generic.c

Source file repositories/reference/linux-study-clean/drivers/usb/core/generic.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/core/generic.c
Extension
.c
Size
9502 bytes
Lines
337
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

static int __check_for_non_generic_match(struct device_driver *drv, void *data)
{
	struct usb_device *udev = data;
	struct usb_device_driver *udrv;

	if (!is_usb_device_driver(drv))
		return 0;
	udrv = to_usb_device_driver(drv);
	if (udrv == &usb_generic_driver)
		return 0;
	return usb_driver_applicable(udev, udrv);
}

static bool usb_generic_driver_match(struct usb_device *udev)
{
	if (udev->use_generic_driver)
		return true;

	/*
	 * If any other driver wants the device, leave the device to this other
	 * driver.
	 */
	if (bus_for_each_drv(&usb_bus_type, NULL, udev, __check_for_non_generic_match))
		return false;

	return true;
}

int usb_generic_driver_probe(struct usb_device *udev)
{
	int err, c;

	/* Choose and set the configuration.  This registers the interfaces
	 * with the driver core and lets interface drivers bind to them.
	 */
	if (udev->authorized == 0)
		dev_info(&udev->dev, "Device is not authorized for usage\n");
	else {
		c = usb_choose_configuration(udev);
		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);

	return 0;
}

void usb_generic_driver_disconnect(struct usb_device *udev)
{
	usb_notify_remove_device(udev);

	/* if this is only an unbind, not a physical disconnect, then
	 * unconfigure the device */
	if (udev->actconfig)
		usb_set_configuration(udev, -1);
}

#ifdef	CONFIG_PM

int usb_generic_driver_suspend(struct usb_device *udev, pm_message_t msg)
{
	int rc;

	/* Normal USB devices suspend through their upstream port.
	 * Root hubs don't have upstream ports to suspend,
	 * so we have to shut down their downstream HC-to-USB
	 * interfaces manually by doing a bus (or "global") suspend.
	 */
	if (!udev->parent)
		rc = hcd_bus_suspend(udev, msg);

	/*
	 * Non-root USB2 devices don't need to do anything for FREEZE
	 * or PRETHAW. USB3 devices don't support global suspend and
	 * needs to be selectively suspended.
	 */
	else if ((msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
		 && (udev->speed < USB_SPEED_SUPER))
		rc = 0;
	else
		rc = usb_port_suspend(udev, msg);

Annotation

Implementation Notes