drivers/usb/serial/keyspan_pda.c

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

File Facts

System
Linux kernel
Corpus path
drivers/usb/serial/keyspan_pda.c
Extension
.c
Size
18283 bytes
Lines
723
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 keyspan_pda_private {
	int			tx_room;
	struct work_struct	unthrottle_work;
	struct usb_serial	*serial;
	struct usb_serial_port	*port;
};

static int keyspan_pda_write_start(struct usb_serial_port *port);

#define KEYSPAN_VENDOR_ID		0x06cd
#define KEYSPAN_PDA_FAKE_ID		0x0103
#define KEYSPAN_PDA_ID			0x0104 /* no clue */

/* For Xircom PGSDB9 and older Entrega version of the same device */
#define XIRCOM_VENDOR_ID		0x085a
#define XIRCOM_FAKE_ID			0x8027
#define XIRCOM_FAKE_ID_2		0x8025 /* "PGMFHUB" serial */
#define ENTREGA_VENDOR_ID		0x1645
#define ENTREGA_FAKE_ID			0x8093

static const struct usb_device_id id_table_combined[] = {
	{ USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_FAKE_ID) },
	{ USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) },
	{ USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID_2) },
	{ USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) },
	{ USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) },
	{ }						/* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table_combined);

static const struct usb_device_id id_table_std[] = {
	{ USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) },
	{ }						/* Terminating entry */
};

static const struct usb_device_id id_table_fake[] = {
	{ USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_FAKE_ID) },
	{ USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) },
	{ USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID_2) },
	{ USB_DEVICE(ENTREGA_VENDOR_ID, ENTREGA_FAKE_ID) },
	{ }						/* Terminating entry */
};

static int keyspan_pda_get_write_room(struct keyspan_pda_private *priv)
{
	struct usb_serial_port *port = priv->port;
	struct usb_serial *serial = port->serial;
	u8 room;
	int rc;

	rc = usb_control_msg_recv(serial->dev,
				  0,
				  6, /* write_room */
				  USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_IN,
				  0, /* value: 0 means "remaining room" */
				  0, /* index */
				  &room,
				  1,
				  2000,
				  GFP_KERNEL);
	if (rc) {
		dev_dbg(&port->dev, "roomquery failed: %d\n", rc);
		return rc;
	}

	dev_dbg(&port->dev, "roomquery says %d\n", room);

	return room;
}

static void keyspan_pda_request_unthrottle(struct work_struct *work)
{
	struct keyspan_pda_private *priv =
		container_of(work, struct keyspan_pda_private, unthrottle_work);
	struct usb_serial_port *port = priv->port;
	struct usb_serial *serial = port->serial;
	unsigned long flags;
	int result;

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

	/*
	 * Ask the device to tell us when the tx buffer becomes
	 * sufficiently empty.
	 */
	result = usb_control_msg(serial->dev,
				 usb_sndctrlpipe(serial->dev, 0),
				 7, /* request_unthrottle */
				 USB_TYPE_VENDOR | USB_RECIP_INTERFACE
				 | USB_DIR_OUT,

Annotation

Implementation Notes