drivers/usb/class/cdc-wdm.c

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

File Facts

System
Linux kernel
Corpus path
drivers/usb/class/cdc-wdm.c
Extension
.c
Size
33884 bytes
Lines
1381
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 wdm_fops = {
	.owner =	THIS_MODULE,
	.read =		wdm_read,
	.write =	wdm_write,
	.fsync =	wdm_fsync,
	.open =		wdm_open,
	.flush =	wdm_flush,
	.release =	wdm_release,
	.poll =		wdm_poll,
	.unlocked_ioctl = wdm_ioctl,
	.compat_ioctl = compat_ptr_ioctl,
	.llseek =	noop_llseek,
};

static struct usb_class_driver wdm_class = {
	.name =		"cdc-wdm%d",
	.fops =		&wdm_fops,
	.minor_base =	WDM_MINOR_BASE,
};

/* --- WWAN framework integration --- */
#ifdef CONFIG_WWAN
static int wdm_wwan_port_start(struct wwan_port *port)
{
	struct wdm_device *desc = wwan_port_get_drvdata(port);
	int rv;

	/* The interface is both exposed via the WWAN framework and as a
	 * legacy usbmisc chardev. If chardev is already open, just fail
	 * to prevent concurrent usage. Otherwise, switch to WWAN mode.
	 */
	mutex_lock(&wdm_mutex);
	if (desc->count) {
		mutex_unlock(&wdm_mutex);
		return -EBUSY;
	}
	set_bit(WDM_WWAN_IN_USE, &desc->flags);
	mutex_unlock(&wdm_mutex);

	desc->manage_power(desc->intf, 1);

	/* tx is allowed */
	wwan_port_txon(port);

	/* Start getting events */
	rv = usb_submit_urb(desc->validity, GFP_KERNEL);
	if (rv < 0) {
		wwan_port_txoff(port);
		desc->manage_power(desc->intf, 0);
		/* this must be last lest we race with chardev open */
		clear_bit(WDM_WWAN_IN_USE, &desc->flags);
	}

	return rv;
}

static void wdm_wwan_port_stop(struct wwan_port *port)
{
	struct wdm_device *desc = wwan_port_get_drvdata(port);

	/* Stop all transfers and disable WWAN mode */
	poison_urbs(desc);
	desc->manage_power(desc->intf, 0);
	clear_bit(WDM_READ, &desc->flags);
	unpoison_urbs(desc);
	smp_wmb(); /* ordered against wdm_open() */
	/* this must be last lest we open a poisoned device */
	clear_bit(WDM_WWAN_IN_USE, &desc->flags);
}

static void wdm_wwan_port_tx_complete(struct urb *urb)
{
	struct sk_buff *skb = urb->context;
	struct wdm_device *desc = skb_shinfo(skb)->destructor_arg;

	usb_autopm_put_interface_async(desc->intf);
	wwan_port_txon(desc->wwanp);
	kfree_skb(skb);
}

static int wdm_wwan_port_tx(struct wwan_port *port, struct sk_buff *skb)
{
	struct wdm_device *desc = wwan_port_get_drvdata(port);
	struct usb_interface *intf = desc->intf;
	struct usb_ctrlrequest *req = desc->orq;
	int rv;

	rv = usb_autopm_get_interface(intf);
	if (rv)
		return rv;

Annotation

Implementation Notes