drivers/usb/serial/metro-usb.c

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

File Facts

System
Linux kernel
Corpus path
drivers/usb/serial/metro-usb.c
Extension
.c
Size
10121 bytes
Lines
372
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 metrousb_private {
	spinlock_t lock;
	int throttled;
	unsigned long control_state;
};

/* Device table list. */
static const struct usb_device_id id_table[] = {
	{ USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_BI) },
	{ USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_UNI) },
	{ USB_DEVICE_INTERFACE_CLASS(0x0c2e, 0x0730, 0xff) },	/* MS7820 */
	{ }, /* Terminating entry. */
};
MODULE_DEVICE_TABLE(usb, id_table);

/* UNI-Directional mode commands for device configure */
#define UNI_CMD_OPEN	0x80
#define UNI_CMD_CLOSE	0xFF

static int metrousb_is_unidirectional_mode(struct usb_serial *serial)
{
	u16 product_id = le16_to_cpu(serial->dev->descriptor.idProduct);

	return product_id == FOCUS_PRODUCT_ID_UNI;
}

static int metrousb_calc_num_ports(struct usb_serial *serial,
				   struct usb_serial_endpoints *epds)
{
	if (metrousb_is_unidirectional_mode(serial)) {
		if (epds->num_interrupt_out == 0) {
			dev_err(&serial->interface->dev, "interrupt-out endpoint missing\n");
			return -ENODEV;
		}
	}

	return 1;
}

static int metrousb_send_unidirectional_cmd(u8 cmd, struct usb_serial_port *port)
{
	int ret;
	int actual_len;
	u8 *buffer_cmd = NULL;

	if (!metrousb_is_unidirectional_mode(port->serial))
		return 0;

	buffer_cmd = kzalloc(sizeof(cmd), GFP_KERNEL);
	if (!buffer_cmd)
		return -ENOMEM;

	*buffer_cmd = cmd;

	ret = usb_interrupt_msg(port->serial->dev,
		usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress),
		buffer_cmd, sizeof(cmd),
		&actual_len, USB_CTRL_SET_TIMEOUT);

	kfree(buffer_cmd);

	if (ret < 0)
		return ret;
	else if (actual_len != sizeof(cmd))
		return -EIO;
	return 0;
}

static void metrousb_read_int_callback(struct urb *urb)
{
	struct usb_serial_port *port = urb->context;
	struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
	unsigned char *data = urb->transfer_buffer;
	unsigned long flags;
	int throttled = 0;
	int result = 0;

	dev_dbg(&port->dev, "%s\n", __func__);

	switch (urb->status) {
	case 0:
		/* Success status, read from the port. */
		break;
	case -ECONNRESET:
	case -ENOENT:
	case -ESHUTDOWN:
		/* urb has been terminated. */
		dev_dbg(&port->dev,
			"%s - urb shutting down, error code=%d\n",
			__func__, urb->status);

Annotation

Implementation Notes