drivers/gpio/gpio-mpsse.c

Source file repositories/reference/linux-study-clean/drivers/gpio/gpio-mpsse.c

File Facts

System
Linux kernel
Corpus path
drivers/gpio/gpio-mpsse.c
Extension
.c
Size
18812 bytes
Lines
730
Domain
Driver Families
Bucket
drivers/gpio
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 mpsse_priv {
	struct gpio_chip gpio;
	struct usb_device *udev;     /* USB device encompassing all MPSSEs */
	struct usb_interface *intf;  /* USB interface for this MPSSE */
	u8 intf_id;                  /* USB interface number for this MPSSE */
	struct list_head workers;    /* polling work threads */
	struct mutex irq_mutex;	     /* lock over irq_data */
	struct mutex irq_race;	     /* race for polling worker teardown */
	raw_spinlock_t irq_spin;     /* protects worker list */
	atomic_t irq_type[16];	     /* pin -> edge detection type */
	atomic_t irq_enabled;
	int id;

	u8 gpio_outputs[2];	     /* Output states for GPIOs [L, H] */
	u8 gpio_dir[2];		     /* Directions for GPIOs [L, H] */

	unsigned long dir_in;        /* Bitmask of valid input pins  */
	unsigned long dir_out;       /* Bitmask of valid output pins */

	u8 *bulk_in_buf;	     /* Extra recv buffer to grab status bytes */

	struct usb_endpoint_descriptor *bulk_in;
	struct usb_endpoint_descriptor *bulk_out;

	struct mutex io_mutex;	    /* sync I/O with disconnect */
};

struct mpsse_worker {
	struct mpsse_priv  *priv;
	struct work_struct  work;
	atomic_t       cancelled;
	struct list_head    list;   /* linked list */
	struct list_head destroy;   /* teardown linked list */
};

struct bulk_desc {
	bool tx;	            /* direction of bulk transfer */
	u8 *data;                   /* input (tx) or output (rx) */
	int len;                    /* Length of `data` if tx, or length of */
				    /* Data to read if rx */
	int len_actual;		    /* Length successfully transferred */
	int timeout;
};

#define MPSSE_NGPIO 16

struct mpsse_quirk {
	const char   *names[MPSSE_NGPIO]; /* Pin names, if applicable     */
	unsigned long dir_in;             /* Bitmask of valid input pins  */
	unsigned long dir_out;            /* Bitmask of valid output pins */
};

static struct mpsse_quirk bryx_brik_quirk = {
	.names = {
		[3] = "Push to Talk",
		[5] = "Channel Activity",
	},
	.dir_out = BIT(3),	/* Push to Talk     */
	.dir_in  = BIT(5),	/* Channel Activity */
};

static const struct usb_device_id gpio_mpsse_table[] = {
	{ USB_DEVICE(0x0c52, 0xa064) },   /* SeaLevel Systems, Inc. */
	{ USB_DEVICE(0x0403, 0x6988),     /* FTDI, assigned to Bryx */
	  .driver_info = (kernel_ulong_t)&bryx_brik_quirk},
	{ }                               /* Terminating entry */
};

MODULE_DEVICE_TABLE(usb, gpio_mpsse_table);

static DEFINE_IDA(gpio_mpsse_ida);

/* MPSSE commands */
#define SET_BITS_CMD 0x80
#define GET_BITS_CMD 0x81

#define SET_BITMODE_REQUEST 0x0B
#define MODE_MPSSE (2 << 8)
#define MODE_RESET 0

/* Arbitrarily decided. This could probably be much less */
#define MPSSE_WRITE_TIMEOUT 5000
#define MPSSE_READ_TIMEOUT 5000

/* 1 millisecond, also pretty arbitrary */
#define MPSSE_POLL_INTERVAL 1000

static int mpsse_bulk_xfer(struct usb_interface *intf, struct bulk_desc *desc)
{
	struct mpsse_priv *priv = usb_get_intfdata(intf);

Annotation

Implementation Notes