drivers/usb/serial/usb-serial.c

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

File Facts

System
Linux kernel
Corpus path
drivers/usb/serial/usb-serial.c
Extension
.c
Size
41604 bytes
Lines
1554
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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

retval = device_add(&port->dev);
		if (retval)
			dev_err(ddev, "Error registering port device, continuing\n");
	}

	if (num_ports > 0)
		usb_serial_console_init(serial->port[0]->minor);
exit:
	kfree(epds);
	module_put(type->driver.owner);
	return 0;

err_free_epds:
	kfree(epds);
err_release_sibling:
	release_sibling(serial, interface);
	usb_serial_put(serial);
err_put_module:
	module_put(type->driver.owner);

	return retval;
}

static void usb_serial_disconnect(struct usb_interface *interface)
{
	int i;
	struct usb_serial *serial = usb_get_intfdata(interface);
	struct device *dev = &interface->dev;
	struct usb_serial_port *port;

	/* sibling interface is cleaning up */
	if (!serial)
		return;

	usb_serial_console_disconnect(serial);

	mutex_lock(&serial->disc_mutex);
	/* must set a flag, to signal subdrivers */
	serial->disconnected = 1;
	mutex_unlock(&serial->disc_mutex);

	for (i = 0; i < serial->num_ports; ++i) {
		port = serial->port[i];
		tty_port_tty_vhangup(&port->port);
		usb_serial_port_poison_urbs(port);
		wake_up_interruptible(&port->port.delta_msr_wait);
		cancel_work_sync(&port->work);
		if (device_is_registered(&port->dev))
			device_del(&port->dev);
	}
	if (serial->type->disconnect)
		serial->type->disconnect(serial);

	release_sibling(serial, interface);

	/* let the last holder of this object cause it to be cleaned up */
	usb_serial_put(serial);
	dev_info(dev, "device disconnected\n");
}

int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
{
	struct usb_serial *serial = usb_get_intfdata(intf);
	int i, r;

	/* suspend when called for first sibling interface */
	if (serial->suspend_count++)
		return 0;

	/*
	 * serial->type->suspend() MUST return 0 in system sleep context,
	 * otherwise, the resume callback has to recover device from
	 * previous suspend failure.
	 */
	if (serial->type->suspend) {
		r = serial->type->suspend(serial, message);
		if (r < 0) {
			serial->suspend_count--;
			return r;
		}
	}

	for (i = 0; i < serial->num_ports; ++i)
		usb_serial_port_poison_urbs(serial->port[i]);

	return 0;
}
EXPORT_SYMBOL(usb_serial_suspend);

static void usb_serial_unpoison_port_urbs(struct usb_serial *serial)

Annotation

Implementation Notes