drivers/net/wireless/zydas/zd1211rw/zd_usb.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/zydas/zd1211rw/zd_usb.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/zydas/zd1211rw/zd_usb.c
Extension
.c
Size
50757 bytes
Lines
2033
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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

module_init(usb_init);
module_exit(usb_exit);

static int zd_ep_regs_out_msg(struct usb_device *udev, void *data, int len,
			      int *actual_length, int timeout)
{
	/* In USB 2.0 mode EP_REGS_OUT endpoint is interrupt type. However in
	 * USB 1.1 mode endpoint is bulk. Select correct type URB by endpoint
	 * descriptor.
	 */
	struct usb_host_endpoint *ep;
	unsigned int pipe;

	pipe = usb_sndintpipe(udev, EP_REGS_OUT);
	ep = usb_pipe_endpoint(udev, pipe);
	if (!ep)
		return -EINVAL;

	if (usb_endpoint_xfer_int(&ep->desc)) {
		return usb_interrupt_msg(udev, pipe, data, len,
					 actual_length, timeout);
	} else {
		pipe = usb_sndbulkpipe(udev, EP_REGS_OUT);
		return usb_bulk_msg(udev, pipe, data, len, actual_length,
				    timeout);
	}
}

static void prepare_read_regs_int(struct zd_usb *usb,
				  struct usb_req_read_regs *req,
				  unsigned int count)
{
	struct zd_usb_interrupt *intr = &usb->intr;

	spin_lock_irq(&intr->lock);
	atomic_set(&intr->read_regs_enabled, 1);
	intr->read_regs.req = req;
	intr->read_regs.req_count = count;
	reinit_completion(&intr->read_regs.completion);
	spin_unlock_irq(&intr->lock);
}

static void disable_read_regs_int(struct zd_usb *usb)
{
	struct zd_usb_interrupt *intr = &usb->intr;

	spin_lock_irq(&intr->lock);
	atomic_set(&intr->read_regs_enabled, 0);
	spin_unlock_irq(&intr->lock);
}

static bool check_read_regs(struct zd_usb *usb, struct usb_req_read_regs *req,
			    unsigned int count)
{
	int i;
	struct zd_usb_interrupt *intr = &usb->intr;
	struct read_regs_int *rr = &intr->read_regs;
	struct usb_int_regs *regs = (struct usb_int_regs *)rr->buffer;

	/* The created block size seems to be larger than expected.
	 * However results appear to be correct.
	 */
	if (rr->length < struct_size(regs, regs, count)) {
		dev_dbg_f(zd_usb_dev(usb),
			 "error: actual length %d less than expected %zu\n",
			 rr->length, struct_size(regs, regs, count));
		return false;
	}

	if (rr->length > sizeof(rr->buffer)) {
		dev_dbg_f(zd_usb_dev(usb),
			 "error: actual length %d exceeds buffer size %zu\n",
			 rr->length, sizeof(rr->buffer));
		return false;
	}

	for (i = 0; i < count; i++) {
		struct reg_data *rd = &regs->regs[i];
		if (rd->addr != req->addr[i]) {
			dev_dbg_f(zd_usb_dev(usb),
				 "rd[%d] addr %#06hx expected %#06hx\n", i,
				 le16_to_cpu(rd->addr),
				 le16_to_cpu(req->addr[i]));
			return false;
		}
	}

	return true;
}

Annotation

Implementation Notes