Skip to content

Commit d47c740

Browse files
committed
Merge tag 'gnss-5.17-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/gnss into char-misc-next
Johan writes: GNSS updates for 5.17-rc1 Here are the GNSS updates for 5.17-rc1, including: - support for GNSS receivers with USB interface - support for Sierra Wireless XM1210 All have been in linux-next with no reported issues. * tag 'gnss-5.17-rc1' of https://git.kernel.org/pub/scm/linux/kernel/git/johan/gnss: gnss: usb: add support for Sierra Wireless XM1210 gnss: add USB support gnss: drop stray semicolons
2 parents 663d8fb + 547d216 commit d47c740

File tree

7 files changed

+232
-4
lines changed

7 files changed

+232
-4
lines changed

drivers/gnss/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,15 @@ config GNSS_UBX_SERIAL
5454

5555
If unsure, say N.
5656

57+
config GNSS_USB
58+
tristate "USB GNSS receiver support"
59+
depends on USB
60+
help
61+
Say Y here if you have a GNSS receiver which uses a USB interface.
62+
63+
To compile this driver as a module, choose M here: the module will
64+
be called gnss-usb.
65+
66+
If unsure, say N.
67+
5768
endif # GNSS

drivers/gnss/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,6 @@ gnss-sirf-y := sirf.o
1717

1818
obj-$(CONFIG_GNSS_UBX_SERIAL) += gnss-ubx.o
1919
gnss-ubx-y := ubx.o
20+
21+
obj-$(CONFIG_GNSS_USB) += gnss-usb.o
22+
gnss-usb-y := usb.o

drivers/gnss/mtk.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ static void mtk_remove(struct serdev_device *serdev)
126126
if (data->vbackup)
127127
regulator_disable(data->vbackup);
128128
gnss_serial_free(gserial);
129-
};
129+
}
130130

131131
#ifdef CONFIG_OF
132132
static const struct of_device_id mtk_of_match[] = {

drivers/gnss/serial.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ void gnss_serial_free(struct gnss_serial *gserial)
165165
{
166166
gnss_put_device(gserial->gdev);
167167
kfree(gserial);
168-
};
168+
}
169169
EXPORT_SYMBOL_GPL(gnss_serial_free);
170170

171171
int gnss_serial_register(struct gnss_serial *gserial)

drivers/gnss/sirf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ static void sirf_remove(struct serdev_device *serdev)
551551
regulator_disable(data->vcc);
552552

553553
gnss_put_device(data->gdev);
554-
};
554+
}
555555

556556
#ifdef CONFIG_OF
557557
static const struct of_device_id sirf_of_match[] = {

drivers/gnss/ubx.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ static void ubx_remove(struct serdev_device *serdev)
126126
if (data->v_bckp)
127127
regulator_disable(data->v_bckp);
128128
gnss_serial_free(gserial);
129-
};
129+
}
130130

131131
#ifdef CONFIG_OF
132132
static const struct of_device_id ubx_of_match[] = {

drivers/gnss/usb.c

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Generic USB GNSS receiver driver
4+
*
5+
* Copyright (C) 2021 Johan Hovold <[email protected]>
6+
*/
7+
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>
15+
16+
#define GNSS_USB_READ_BUF_LEN 512
17+
#define GNSS_USB_WRITE_TIMEOUT 1000
18+
19+
static const struct usb_device_id gnss_usb_id_table[] = {
20+
{ USB_DEVICE(0x1199, 0xb000) }, /* Sierra Wireless XM1210 */
21+
{ }
22+
};
23+
MODULE_DEVICE_TABLE(usb, gnss_usb_id_table);
24+
25+
struct gnss_usb {
26+
struct usb_device *udev;
27+
struct usb_interface *intf;
28+
struct gnss_device *gdev;
29+
struct urb *read_urb;
30+
unsigned int write_pipe;
31+
};
32+
33+
static void gnss_usb_rx_complete(struct urb *urb)
34+
{
35+
struct gnss_usb *gusb = urb->context;
36+
struct gnss_device *gdev = gusb->gdev;
37+
int status = urb->status;
38+
int len;
39+
int ret;
40+
41+
switch (status) {
42+
case 0:
43+
break;
44+
case -ENOENT:
45+
case -ECONNRESET:
46+
case -ESHUTDOWN:
47+
dev_dbg(&gdev->dev, "urb stopped: %d\n", status);
48+
return;
49+
case -EPIPE:
50+
dev_err(&gdev->dev, "urb stopped: %d\n", status);
51+
return;
52+
default:
53+
dev_dbg(&gdev->dev, "nonzero urb status: %d\n", status);
54+
goto resubmit;
55+
}
56+
57+
len = urb->actual_length;
58+
if (len == 0)
59+
goto resubmit;
60+
61+
ret = gnss_insert_raw(gdev, urb->transfer_buffer, len);
62+
if (ret < len)
63+
dev_dbg(&gdev->dev, "dropped %d bytes\n", len - ret);
64+
resubmit:
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);
68+
}
69+
70+
static int gnss_usb_open(struct gnss_device *gdev)
71+
{
72+
struct gnss_usb *gusb = gnss_get_drvdata(gdev);
73+
int ret;
74+
75+
ret = usb_submit_urb(gusb->read_urb, GFP_KERNEL);
76+
if (ret) {
77+
if (ret != -EPERM && ret != -ENODEV)
78+
dev_err(&gdev->dev, "failed to submit urb: %d\n", ret);
79+
return ret;
80+
}
81+
82+
return 0;
83+
}
84+
85+
static void gnss_usb_close(struct gnss_device *gdev)
86+
{
87+
struct gnss_usb *gusb = gnss_get_drvdata(gdev);
88+
89+
usb_kill_urb(gusb->read_urb);
90+
}
91+
92+
static int gnss_usb_write_raw(struct gnss_device *gdev,
93+
const unsigned char *buf, size_t count)
94+
{
95+
struct gnss_usb *gusb = gnss_get_drvdata(gdev);
96+
void *tbuf;
97+
int ret;
98+
99+
tbuf = kmemdup(buf, count, GFP_KERNEL);
100+
if (!tbuf)
101+
return -ENOMEM;
102+
103+
ret = usb_bulk_msg(gusb->udev, gusb->write_pipe, tbuf, count, NULL,
104+
GNSS_USB_WRITE_TIMEOUT);
105+
kfree(tbuf);
106+
if (ret)
107+
return ret;
108+
109+
return count;
110+
}
111+
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,
116+
};
117+
118+
static int gnss_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
119+
{
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;
124+
struct urb *urb;
125+
size_t buf_len;
126+
void *buf;
127+
int ret;
128+
129+
ret = usb_find_common_endpoints(intf->cur_altsetting, &in, &out, NULL,
130+
NULL);
131+
if (ret)
132+
return ret;
133+
134+
gusb = kzalloc(sizeof(*gusb), GFP_KERNEL);
135+
if (!gusb)
136+
return -ENOMEM;
137+
138+
gdev = gnss_allocate_device(&intf->dev);
139+
if (!gdev) {
140+
ret = -ENOMEM;
141+
goto err_free_gusb;
142+
}
143+
144+
gdev->ops = &gnss_usb_gnss_ops;
145+
gdev->type = GNSS_TYPE_NMEA;
146+
gnss_set_drvdata(gdev, gusb);
147+
148+
urb = usb_alloc_urb(0, GFP_KERNEL);
149+
if (!urb) {
150+
ret = -ENOMEM;
151+
goto err_put_gdev;
152+
}
153+
154+
buf_len = max(usb_endpoint_maxp(in), GNSS_USB_READ_BUF_LEN);
155+
156+
buf = kzalloc(buf_len, GFP_KERNEL);
157+
if (!buf) {
158+
ret = -ENOMEM;
159+
goto err_free_urb;
160+
}
161+
162+
usb_fill_bulk_urb(urb, udev,
163+
usb_rcvbulkpipe(udev, usb_endpoint_num(in)),
164+
buf, buf_len, gnss_usb_rx_complete, gusb);
165+
166+
gusb->intf = intf;
167+
gusb->udev = udev;
168+
gusb->gdev = gdev;
169+
gusb->read_urb = urb;
170+
gusb->write_pipe = usb_sndbulkpipe(udev, usb_endpoint_num(out));
171+
172+
ret = gnss_register_device(gdev);
173+
if (ret)
174+
goto err_free_buf;
175+
176+
usb_set_intfdata(intf, gusb);
177+
178+
return 0;
179+
180+
err_free_buf:
181+
kfree(buf);
182+
err_free_urb:
183+
usb_free_urb(urb);
184+
err_put_gdev:
185+
gnss_put_device(gdev);
186+
err_free_gusb:
187+
kfree(gusb);
188+
189+
return ret;
190+
}
191+
192+
static void gnss_usb_disconnect(struct usb_interface *intf)
193+
{
194+
struct gnss_usb *gusb = usb_get_intfdata(intf);
195+
196+
gnss_deregister_device(gusb->gdev);
197+
198+
kfree(gusb->read_urb->transfer_buffer);
199+
usb_free_urb(gusb->read_urb);
200+
gnss_put_device(gusb->gdev);
201+
kfree(gusb);
202+
}
203+
204+
static struct usb_driver gnss_usb_driver = {
205+
.name = "gnss-usb",
206+
.probe = gnss_usb_probe,
207+
.disconnect = gnss_usb_disconnect,
208+
.id_table = gnss_usb_id_table,
209+
};
210+
module_usb_driver(gnss_usb_driver);
211+
212+
MODULE_AUTHOR("Johan Hovold <[email protected]>");
213+
MODULE_DESCRIPTION("Generic USB GNSS receiver driver");
214+
MODULE_LICENSE("GPL v2");

0 commit comments

Comments
 (0)