drivers/usb/serial/symbolserial.c

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

File Facts

System
Linux kernel
Corpus path
drivers/usb/serial/symbolserial.c
Extension
.c
Size
4721 bytes
Lines
194
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: implementation source
Status
source 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

struct symbol_private {
	spinlock_t lock;	/* protects the following flags */
	bool throttled;
	bool actually_throttled;
};

static void symbol_int_callback(struct urb *urb)
{
	struct usb_serial_port *port = urb->context;
	struct symbol_private *priv = usb_get_serial_port_data(port);
	unsigned char *data = urb->transfer_buffer;
	int status = urb->status;
	unsigned long flags;
	int result;
	int data_length;

	switch (status) {
	case 0:
		/* success */
		break;
	case -ECONNRESET:
	case -ENOENT:
	case -ESHUTDOWN:
		/* this urb is terminated, clean up */
		dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
			__func__, status);
		return;
	default:
		dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
			__func__, status);
		goto exit;
	}

	usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);

	/*
	 * Data from the device comes with a 1 byte header:
	 *
	 * <size of data> <data>...
	 */
	if (urb->actual_length > 1) {
		data_length = data[0];
		if (data_length > (urb->actual_length - 1))
			data_length = urb->actual_length - 1;
		tty_insert_flip_string(&port->port, &data[1], data_length);
		tty_flip_buffer_push(&port->port);
	} else {
		dev_dbg(&port->dev, "%s - short packet\n", __func__);
	}

exit:
	spin_lock_irqsave(&priv->lock, flags);

	/* Continue trying to always read if we should */
	if (!priv->throttled) {
		result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
		if (result)
			dev_err(&port->dev,
			    "%s - failed resubmitting read urb, error %d\n",
							__func__, result);
	} else
		priv->actually_throttled = true;
	spin_unlock_irqrestore(&priv->lock, flags);
}

static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port)
{
	struct symbol_private *priv = usb_get_serial_port_data(port);
	unsigned long flags;
	int result = 0;

	spin_lock_irqsave(&priv->lock, flags);
	priv->throttled = false;
	priv->actually_throttled = false;
	spin_unlock_irqrestore(&priv->lock, flags);

	/* Start reading from the device */
	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
	if (result)
		dev_err(&port->dev,
			"%s - failed resubmitting read urb, error %d\n",
			__func__, result);
	return result;
}

static void symbol_close(struct usb_serial_port *port)
{
	usb_kill_urb(port->interrupt_in_urb);
}

Annotation

Implementation Notes