drivers/usb/serial/quatech2.c

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

File Facts

System
Linux kernel
Corpus path
drivers/usb/serial/quatech2.c
Extension
.c
Size
24109 bytes
Lines
958
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 qt2_device_detail {
	int product_id;
	int num_ports;
};

#define QT_DETAILS(prod, ports)	\
	.product_id = (prod),   \
	.num_ports = (ports)

static const struct qt2_device_detail qt2_device_details[] = {
	{QT_DETAILS(QUATECH_SSU2_100, 1)},
	{QT_DETAILS(QUATECH_DSU2_400, 2)},
	{QT_DETAILS(QUATECH_DSU2_100, 2)},
	{QT_DETAILS(QUATECH_QSU2_400, 4)},
	{QT_DETAILS(QUATECH_QSU2_100, 4)},
	{QT_DETAILS(QUATECH_ESU2_400, 8)},
	{QT_DETAILS(QUATECH_ESU2_100, 8)},
	{QT_DETAILS(0, 0)}	/* Terminating entry */
};

static const struct usb_device_id id_table[] = {
	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU2_100)},
	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_100)},
	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_400)},
	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_100)},
	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_400)},
	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_100)},
	{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_400)},
	{}			/* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table);

struct qt2_serial_private {
	unsigned char current_port;  /* current port for incoming data */

	struct urb	*read_urb;   /* shared among all ports */
	char		*read_buffer;
};

struct qt2_port_private {
	u8   device_port;

	spinlock_t urb_lock;
	bool       urb_in_use;
	struct urb *write_urb;
	char       *write_buffer;

	spinlock_t  lock;
	u8          shadowLSR;
	u8          shadowMSR;

	struct usb_serial_port *port;
};

static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch);
static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch);
static void qt2_write_bulk_callback(struct urb *urb);
static void qt2_read_bulk_callback(struct urb *urb);

static void qt2_release(struct usb_serial *serial)
{
	struct qt2_serial_private *serial_priv;

	serial_priv = usb_get_serial_data(serial);

	usb_kill_urb(serial_priv->read_urb);
	usb_free_urb(serial_priv->read_urb);
	kfree(serial_priv->read_buffer);
	kfree(serial_priv);
}

static inline int calc_baud_divisor(int baudrate)
{
	int divisor, rem;

	divisor = MAX_BAUD_RATE / baudrate;
	rem = MAX_BAUD_RATE % baudrate;
	/* Round to nearest divisor */
	if (((rem * 2) >= baudrate) && (baudrate != 110))
		divisor++;

	return divisor;
}

static inline int qt2_set_port_config(struct usb_device *dev,
				      unsigned char port_number,
				      u16 baudrate, u16 lcr)
{
	int divisor = calc_baud_divisor(baudrate);
	u16 index = ((u16) (lcr << 8) | (u16) (port_number));

Annotation

Implementation Notes