drivers/input/joystick/iforce/iforce-usb.c

Source file repositories/reference/linux-study-clean/drivers/input/joystick/iforce/iforce-usb.c

File Facts

System
Linux kernel
Corpus path
drivers/input/joystick/iforce/iforce-usb.c
Extension
.c
Size
7851 bytes
Lines
299
Domain
Driver Families
Bucket
drivers/input
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 iforce_usb {
	struct iforce iforce;

	struct usb_device *usbdev;
	struct usb_interface *intf;
	struct urb *irq, *out;

	u8 data_in[IFORCE_MAX_LENGTH] ____cacheline_aligned;
	u8 data_out[IFORCE_MAX_LENGTH] ____cacheline_aligned;
};

static void __iforce_usb_xmit(struct iforce *iforce)
{
	struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
						     iforce);
	int n, c;

	guard(spinlock_irqsave)(&iforce->xmit_lock);

	if (iforce->xmit.head == iforce->xmit.tail) {
		iforce_clear_xmit_and_wake(iforce);
		return;
	}

	((char *)iforce_usb->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail];
	XMIT_INC(iforce->xmit.tail, 1);
	n = iforce->xmit.buf[iforce->xmit.tail];
	XMIT_INC(iforce->xmit.tail, 1);

	iforce_usb->out->transfer_buffer_length = n + 1;
	iforce_usb->out->dev = iforce_usb->usbdev;

	/* Copy rest of data then */
	c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE);
	if (n < c)
		c = n;

	memcpy(iforce_usb->out->transfer_buffer + 1,
	       &iforce->xmit.buf[iforce->xmit.tail],
	       c);
	if (n != c) {
		memcpy(iforce_usb->out->transfer_buffer + 1 + c,
		       &iforce->xmit.buf[0],
		       n - c);
	}
	XMIT_INC(iforce->xmit.tail, n);

	n=usb_submit_urb(iforce_usb->out, GFP_ATOMIC);
	if (n) {
		dev_warn(&iforce_usb->intf->dev,
			 "usb_submit_urb failed %d\n", n);
		iforce_clear_xmit_and_wake(iforce);
	}

	/* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
	 * As long as the urb completion handler is not called, the transmiting
	 * is considered to be running */
}

static void iforce_usb_xmit(struct iforce *iforce)
{
	if (!test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags))
		__iforce_usb_xmit(iforce);
}

static int iforce_usb_get_id(struct iforce *iforce, u8 id,
			     u8 *response_data, size_t *response_len)
{
	struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
						     iforce);
	u8 *buf;
	int status;

	buf = kmalloc(IFORCE_MAX_LENGTH, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	status = usb_control_msg(iforce_usb->usbdev,
				 usb_rcvctrlpipe(iforce_usb->usbdev, 0),
				 id,
				 USB_TYPE_VENDOR | USB_DIR_IN |
					USB_RECIP_INTERFACE,
				 0, 0, buf, IFORCE_MAX_LENGTH, 1000);
	if (status < 0) {
		dev_err(&iforce_usb->intf->dev,
			"usb_submit_urb failed: %d\n", status);
	} else if (buf[0] != id) {
		status = -EIO;
	} else {
		memcpy(response_data, buf, status);

Annotation

Implementation Notes