drivers/gnss/usb.c

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

File Facts

System
Linux kernel
Corpus path
drivers/gnss/usb.c
Extension
.c
Size
4579 bytes
Lines
215
Domain
Driver Families
Bucket
drivers/gnss
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 gnss_usb {
	struct usb_device *udev;
	struct usb_interface *intf;
	struct gnss_device *gdev;
	struct urb *read_urb;
	unsigned int write_pipe;
};

static void gnss_usb_rx_complete(struct urb *urb)
{
	struct gnss_usb *gusb = urb->context;
	struct gnss_device *gdev = gusb->gdev;
	int status = urb->status;
	int len;
	int ret;

	switch (status) {
	case 0:
		break;
	case -ENOENT:
	case -ECONNRESET:
	case -ESHUTDOWN:
		dev_dbg(&gdev->dev, "urb stopped: %d\n", status);
		return;
	case -EPIPE:
		dev_err(&gdev->dev, "urb stopped: %d\n", status);
		return;
	default:
		dev_dbg(&gdev->dev, "nonzero urb status: %d\n", status);
		goto resubmit;
	}

	len = urb->actual_length;
	if (len == 0)
		goto resubmit;

	ret = gnss_insert_raw(gdev, urb->transfer_buffer, len);
	if (ret < len)
		dev_dbg(&gdev->dev, "dropped %d bytes\n", len - ret);
resubmit:
	ret = usb_submit_urb(urb, GFP_ATOMIC);
	if (ret && ret != -EPERM && ret != -ENODEV)
		dev_err(&gdev->dev, "failed to resubmit urb: %d\n", ret);
}

static int gnss_usb_open(struct gnss_device *gdev)
{
	struct gnss_usb *gusb = gnss_get_drvdata(gdev);
	int ret;

	ret = usb_submit_urb(gusb->read_urb, GFP_KERNEL);
	if (ret) {
		if (ret != -EPERM && ret != -ENODEV)
			dev_err(&gdev->dev, "failed to submit urb: %d\n", ret);
		return ret;
	}

	return 0;
}

static void gnss_usb_close(struct gnss_device *gdev)
{
	struct gnss_usb *gusb = gnss_get_drvdata(gdev);

	usb_kill_urb(gusb->read_urb);
}

static int gnss_usb_write_raw(struct gnss_device *gdev,
		const unsigned char *buf, size_t count)
{
	struct gnss_usb *gusb = gnss_get_drvdata(gdev);
	void *tbuf;
	int ret;

	tbuf = kmemdup(buf, count, GFP_KERNEL);
	if (!tbuf)
		return -ENOMEM;

	ret = usb_bulk_msg(gusb->udev, gusb->write_pipe, tbuf, count, NULL,
			GNSS_USB_WRITE_TIMEOUT);
	kfree(tbuf);
	if (ret)
		return ret;

	return count;
}

static const struct gnss_operations gnss_usb_gnss_ops = {
	.open		= gnss_usb_open,
	.close		= gnss_usb_close,

Annotation

Implementation Notes