drivers/net/usb/pegasus.c

Source file repositories/reference/linux-study-clean/drivers/net/usb/pegasus.c

File Facts

System
Linux kernel
Corpus path
drivers/net/usb/pegasus.c
Extension
.c
Size
34248 bytes
Lines
1376
Domain
Driver Families
Bucket
drivers/net
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 net_device_ops pegasus_netdev_ops;

/*****/

static void async_ctrl_callback(struct urb *urb)
{
	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
	int status = urb->status;

	if (status < 0)
		dev_dbg(&urb->dev->dev, "%s failed with %d", __func__, status);
	kfree(req);
	usb_free_urb(urb);
}

static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data)
{
	return usb_control_msg_recv(pegasus->usb, 0, PEGASUS_REQ_GET_REGS,
				   PEGASUS_REQT_READ, 0, indx, data, size,
				   1000, GFP_NOIO);
}

static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size,
			 const void *data)
{
	int ret;

	ret = usb_control_msg_send(pegasus->usb, 0, PEGASUS_REQ_SET_REGS,
				    PEGASUS_REQT_WRITE, 0, indx, data, size,
				    1000, GFP_NOIO);
	if (ret < 0)
		netif_dbg(pegasus, drv, pegasus->net, "%s failed with %d\n", __func__, ret);

	return ret;
}

/*
 * There is only one way to write to a single ADM8511 register and this is via
 * specific control request.  'data' is ignored by the device, but it is here to
 * not break the API.
 */
static int set_register(pegasus_t *pegasus, __u16 indx, __u8 data)
{
	void *buf = &data;
	int ret;

	ret = usb_control_msg_send(pegasus->usb, 0, PEGASUS_REQ_SET_REG,
				    PEGASUS_REQT_WRITE, data, indx, buf, 1,
				    1000, GFP_NOIO);
	if (ret < 0)
		netif_dbg(pegasus, drv, pegasus->net, "%s failed with %d\n", __func__, ret);

	return ret;
}

static int update_eth_regs_async(pegasus_t *pegasus)
{
	int ret = -ENOMEM;
	struct urb *async_urb;
	struct usb_ctrlrequest *req;

	req = kmalloc_obj(struct usb_ctrlrequest, GFP_ATOMIC);
	if (req == NULL)
		return ret;

	async_urb = usb_alloc_urb(0, GFP_ATOMIC);
	if (async_urb == NULL) {
		kfree(req);
		return ret;
	}
	req->bRequestType = PEGASUS_REQT_WRITE;
	req->bRequest = PEGASUS_REQ_SET_REGS;
	req->wValue = cpu_to_le16(0);
	req->wIndex = cpu_to_le16(EthCtrl0);
	req->wLength = cpu_to_le16(3);

	usb_fill_control_urb(async_urb, pegasus->usb,
			     usb_sndctrlpipe(pegasus->usb, 0), (void *)req,
			     pegasus->eth_regs, 3, async_ctrl_callback, req);

	ret = usb_submit_urb(async_urb, GFP_ATOMIC);
	if (ret) {
		if (ret == -ENODEV)
			netif_device_detach(pegasus->net);
		netif_err(pegasus, drv, pegasus->net,
			  "%s returned %d\n", __func__, ret);
		usb_free_urb(async_urb);
		kfree(req);
	}
	return ret;

Annotation

Implementation Notes