drivers/usb/class/usbtmc.c

Source file repositories/reference/linux-study-clean/drivers/usb/class/usbtmc.c

File Facts

System
Linux kernel
Corpus path
drivers/usb/class/usbtmc.c
Extension
.c
Size
63199 bytes
Lines
2626
Domain
Driver Families
Bucket
drivers/usb
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern 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

static const struct file_operations fops = {
	.owner		= THIS_MODULE,
	.read		= usbtmc_read,
	.write		= usbtmc_write,
	.open		= usbtmc_open,
	.release	= usbtmc_release,
	.flush		= usbtmc_flush,
	.unlocked_ioctl	= usbtmc_ioctl,
	.compat_ioctl	= compat_ptr_ioctl,
	.fasync         = usbtmc_fasync,
	.poll           = usbtmc_poll,
	.llseek		= default_llseek,
};

static struct usb_class_driver usbtmc_class = {
	.name =		"usbtmc%d",
	.fops =		&fops,
	.minor_base =	USBTMC_MINOR_BASE,
};

static void usbtmc_interrupt(struct urb *urb)
{
	struct usbtmc_device_data *data = urb->context;
	struct device *dev = &data->intf->dev;
	int status = urb->status;
	int rv;

	dev_dbg(&data->intf->dev, "int status: %d len %d\n",
		status, urb->actual_length);

	switch (status) {
	case 0: /* SUCCESS */
		/* ensure at least two bytes of headers were transferred */
		if (urb->actual_length < 2) {
			dev_warn(dev,
				"actual length %d not sufficient for interrupt headers\n",
				urb->actual_length);
			goto exit;
		}

		/* check for valid STB notification */
		if (data->iin_buffer[0] > 0x81) {
			data->bNotify1 = data->iin_buffer[0];
			data->bNotify2 = data->iin_buffer[1];
			atomic_set(&data->iin_data_valid, 1);
			wake_up_interruptible(&data->waitq);
			goto exit;
		}
		/* check for SRQ notification */
		if (data->iin_buffer[0] == 0x81) {
			unsigned long flags;
			struct list_head *elem;

			if (data->fasync)
				kill_fasync(&data->fasync,
					SIGIO, POLL_PRI);

			spin_lock_irqsave(&data->dev_lock, flags);
			list_for_each(elem, &data->file_list) {
				struct usbtmc_file_data *file_data;

				file_data = list_entry(elem,
						       struct usbtmc_file_data,
						       file_elem);
				file_data->srq_byte = data->iin_buffer[1];
				atomic_set(&file_data->srq_asserted, 1);
			}
			spin_unlock_irqrestore(&data->dev_lock, flags);

			dev_dbg(dev, "srq received bTag %x stb %x\n",
				(unsigned int)data->iin_buffer[0],
				(unsigned int)data->iin_buffer[1]);
			wake_up_interruptible_all(&data->waitq);
			goto exit;
		}
		dev_warn(dev, "invalid notification: %x\n",
			 data->iin_buffer[0]);
		break;
	case -EOVERFLOW:
		dev_err(dev, "overflow with length %d, actual length is %d\n",
			data->iin_wMaxPacketSize, urb->actual_length);
		fallthrough;
	default:
		/* urb terminated, clean up */
		dev_dbg(dev, "urb terminated, status: %d\n", status);
		return;
	}
exit:
	rv = usb_submit_urb(urb, GFP_ATOMIC);
	if (rv)

Annotation

Implementation Notes