1 // SPDX-License-Identifier: GPL-2.0
3 * Generic USB GNSS receiver driver
5 * Copyright (C) 2021 Johan Hovold <johan@kernel.org>
8 #include <linux/errno.h>
9 #include <linux/gnss.h>
10 #include <linux/init.h>
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/slab.h>
14 #include <linux/usb.h>
16 #define GNSS_USB_READ_BUF_LEN 512
17 #define GNSS_USB_WRITE_TIMEOUT 1000
19 static const struct usb_device_id gnss_usb_id_table[] = {
20 { USB_DEVICE(0x1199, 0xb000) }, /* Sierra Wireless XM1210 */
23 MODULE_DEVICE_TABLE(usb, gnss_usb_id_table);
26 struct usb_device *udev;
27 struct usb_interface *intf;
28 struct gnss_device *gdev;
30 unsigned int write_pipe;
33 static void gnss_usb_rx_complete(struct urb *urb)
35 struct gnss_usb *gusb = urb->context;
36 struct gnss_device *gdev = gusb->gdev;
37 int status = urb->status;
47 dev_dbg(&gdev->dev, "urb stopped: %d\n", status);
50 dev_err(&gdev->dev, "urb stopped: %d\n", status);
53 dev_dbg(&gdev->dev, "nonzero urb status: %d\n", status);
57 len = urb->actual_length;
61 ret = gnss_insert_raw(gdev, urb->transfer_buffer, len);
63 dev_dbg(&gdev->dev, "dropped %d bytes\n", len - ret);
65 ret = usb_submit_urb(urb, GFP_ATOMIC);
66 if (ret && ret != -EPERM && ret != -ENODEV)
67 dev_err(&gdev->dev, "failed to resubmit urb: %d\n", ret);
70 static int gnss_usb_open(struct gnss_device *gdev)
72 struct gnss_usb *gusb = gnss_get_drvdata(gdev);
75 ret = usb_submit_urb(gusb->read_urb, GFP_KERNEL);
77 if (ret != -EPERM && ret != -ENODEV)
78 dev_err(&gdev->dev, "failed to submit urb: %d\n", ret);
85 static void gnss_usb_close(struct gnss_device *gdev)
87 struct gnss_usb *gusb = gnss_get_drvdata(gdev);
89 usb_kill_urb(gusb->read_urb);
92 static int gnss_usb_write_raw(struct gnss_device *gdev,
93 const unsigned char *buf, size_t count)
95 struct gnss_usb *gusb = gnss_get_drvdata(gdev);
99 tbuf = kmemdup(buf, count, GFP_KERNEL);
103 ret = usb_bulk_msg(gusb->udev, gusb->write_pipe, tbuf, count, NULL,
104 GNSS_USB_WRITE_TIMEOUT);
112 static const struct gnss_operations gnss_usb_gnss_ops = {
113 .open = gnss_usb_open,
114 .close = gnss_usb_close,
115 .write_raw = gnss_usb_write_raw,
118 static int gnss_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
120 struct usb_device *udev = interface_to_usbdev(intf);
121 struct usb_endpoint_descriptor *in, *out;
122 struct gnss_device *gdev;
123 struct gnss_usb *gusb;
129 ret = usb_find_common_endpoints(intf->cur_altsetting, &in, &out, NULL,
134 gusb = kzalloc(sizeof(*gusb), GFP_KERNEL);
138 gdev = gnss_allocate_device(&intf->dev);
144 gdev->ops = &gnss_usb_gnss_ops;
145 gdev->type = GNSS_TYPE_NMEA;
146 gnss_set_drvdata(gdev, gusb);
148 urb = usb_alloc_urb(0, GFP_KERNEL);
154 buf_len = max(usb_endpoint_maxp(in), GNSS_USB_READ_BUF_LEN);
156 buf = kzalloc(buf_len, GFP_KERNEL);
162 usb_fill_bulk_urb(urb, udev,
163 usb_rcvbulkpipe(udev, usb_endpoint_num(in)),
164 buf, buf_len, gnss_usb_rx_complete, gusb);
169 gusb->read_urb = urb;
170 gusb->write_pipe = usb_sndbulkpipe(udev, usb_endpoint_num(out));
172 ret = gnss_register_device(gdev);
176 usb_set_intfdata(intf, gusb);
185 gnss_put_device(gdev);
192 static void gnss_usb_disconnect(struct usb_interface *intf)
194 struct gnss_usb *gusb = usb_get_intfdata(intf);
196 gnss_deregister_device(gusb->gdev);
198 kfree(gusb->read_urb->transfer_buffer);
199 usb_free_urb(gusb->read_urb);
200 gnss_put_device(gusb->gdev);
204 static struct usb_driver gnss_usb_driver = {
206 .probe = gnss_usb_probe,
207 .disconnect = gnss_usb_disconnect,
208 .id_table = gnss_usb_id_table,
210 module_usb_driver(gnss_usb_driver);
212 MODULE_AUTHOR("Johan Hovold <johan@kernel.org>");
213 MODULE_DESCRIPTION("Generic USB GNSS receiver driver");
214 MODULE_LICENSE("GPL v2");