drivers/usb/serial/generic.c

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

File Facts

System
Linux kernel
Corpus path
drivers/usb/serial/generic.c
Extension
.c
Size
16696 bytes
Lines
658
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

if (res != -EPERM && res != -ENODEV) {
			dev_err(&port->dev,
					"%s - usb_submit_urb failed: %d\n",
					__func__, res);
		}
		set_bit(index, &port->read_urbs_free);
		return res;
	}

	return 0;
}

int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port,
					gfp_t mem_flags)
{
	int res;
	int i;

	for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
		res = usb_serial_generic_submit_read_urb(port, i, mem_flags);
		if (res)
			goto err;
	}

	return 0;
err:
	for (; i >= 0; --i)
		usb_kill_urb(port->read_urbs[i]);

	return res;
}
EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urbs);

void usb_serial_generic_process_read_urb(struct urb *urb)
{
	struct usb_serial_port *port = urb->context;
	char *ch = urb->transfer_buffer;
	int i;

	if (!urb->actual_length)
		return;
	/*
	 * The per character mucking around with sysrq path it too slow for
	 * stuff like 3G modems, so shortcircuit it in the 99.9999999% of
	 * cases where the USB serial is not a console anyway.
	 */
	if (port->sysrq) {
		for (i = 0; i < urb->actual_length; i++, ch++) {
			if (!usb_serial_handle_sysrq_char(port, *ch))
				tty_insert_flip_char(&port->port, *ch, TTY_NORMAL);
		}
	} else {
		tty_insert_flip_string(&port->port, ch, urb->actual_length);
	}
	tty_flip_buffer_push(&port->port);
}
EXPORT_SYMBOL_GPL(usb_serial_generic_process_read_urb);

void usb_serial_generic_read_bulk_callback(struct urb *urb)
{
	struct usb_serial_port *port = urb->context;
	unsigned char *data = urb->transfer_buffer;
	bool stopped = false;
	int status = urb->status;
	int i;

	for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
		if (urb == port->read_urbs[i])
			break;
	}

	dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i,
							urb->actual_length);
	switch (status) {
	case 0:
		usb_serial_debug_data(&port->dev, __func__, urb->actual_length,
							data);
		port->serial->type->process_read_urb(urb);
		break;
	case -ENOENT:
	case -ECONNRESET:
	case -ESHUTDOWN:
		dev_dbg(&port->dev, "%s - urb stopped: %d\n",
							__func__, status);
		stopped = true;
		break;
	case -EPIPE:
		dev_err(&port->dev, "%s - urb stopped: %d\n",
							__func__, status);
		stopped = true;

Annotation

Implementation Notes