1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * AirSpy SDR driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/module.h>
9*4882a593Smuzhiyun #include <linux/slab.h>
10*4882a593Smuzhiyun #include <linux/usb.h>
11*4882a593Smuzhiyun #include <media/v4l2-device.h>
12*4882a593Smuzhiyun #include <media/v4l2-ioctl.h>
13*4882a593Smuzhiyun #include <media/v4l2-ctrls.h>
14*4882a593Smuzhiyun #include <media/v4l2-event.h>
15*4882a593Smuzhiyun #include <media/videobuf2-v4l2.h>
16*4882a593Smuzhiyun #include <media/videobuf2-vmalloc.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun /* AirSpy USB API commands (from AirSpy Library) */
19*4882a593Smuzhiyun enum {
20*4882a593Smuzhiyun CMD_INVALID = 0x00,
21*4882a593Smuzhiyun CMD_RECEIVER_MODE = 0x01,
22*4882a593Smuzhiyun CMD_SI5351C_WRITE = 0x02,
23*4882a593Smuzhiyun CMD_SI5351C_READ = 0x03,
24*4882a593Smuzhiyun CMD_R820T_WRITE = 0x04,
25*4882a593Smuzhiyun CMD_R820T_READ = 0x05,
26*4882a593Smuzhiyun CMD_SPIFLASH_ERASE = 0x06,
27*4882a593Smuzhiyun CMD_SPIFLASH_WRITE = 0x07,
28*4882a593Smuzhiyun CMD_SPIFLASH_READ = 0x08,
29*4882a593Smuzhiyun CMD_BOARD_ID_READ = 0x09,
30*4882a593Smuzhiyun CMD_VERSION_STRING_READ = 0x0a,
31*4882a593Smuzhiyun CMD_BOARD_PARTID_SERIALNO_READ = 0x0b,
32*4882a593Smuzhiyun CMD_SET_SAMPLE_RATE = 0x0c,
33*4882a593Smuzhiyun CMD_SET_FREQ = 0x0d,
34*4882a593Smuzhiyun CMD_SET_LNA_GAIN = 0x0e,
35*4882a593Smuzhiyun CMD_SET_MIXER_GAIN = 0x0f,
36*4882a593Smuzhiyun CMD_SET_VGA_GAIN = 0x10,
37*4882a593Smuzhiyun CMD_SET_LNA_AGC = 0x11,
38*4882a593Smuzhiyun CMD_SET_MIXER_AGC = 0x12,
39*4882a593Smuzhiyun CMD_SET_PACKING = 0x13,
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun /*
43*4882a593Smuzhiyun * bEndpointAddress 0x81 EP 1 IN
44*4882a593Smuzhiyun * Transfer Type Bulk
45*4882a593Smuzhiyun * wMaxPacketSize 0x0200 1x 512 bytes
46*4882a593Smuzhiyun */
47*4882a593Smuzhiyun #define MAX_BULK_BUFS (6)
48*4882a593Smuzhiyun #define BULK_BUFFER_SIZE (128 * 512)
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun static const struct v4l2_frequency_band bands[] = {
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun .tuner = 0,
53*4882a593Smuzhiyun .type = V4L2_TUNER_ADC,
54*4882a593Smuzhiyun .index = 0,
55*4882a593Smuzhiyun .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
56*4882a593Smuzhiyun .rangelow = 20000000,
57*4882a593Smuzhiyun .rangehigh = 20000000,
58*4882a593Smuzhiyun },
59*4882a593Smuzhiyun };
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun static const struct v4l2_frequency_band bands_rf[] = {
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun .tuner = 1,
64*4882a593Smuzhiyun .type = V4L2_TUNER_RF,
65*4882a593Smuzhiyun .index = 0,
66*4882a593Smuzhiyun .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
67*4882a593Smuzhiyun .rangelow = 24000000,
68*4882a593Smuzhiyun .rangehigh = 1750000000,
69*4882a593Smuzhiyun },
70*4882a593Smuzhiyun };
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun /* stream formats */
73*4882a593Smuzhiyun struct airspy_format {
74*4882a593Smuzhiyun u32 pixelformat;
75*4882a593Smuzhiyun u32 buffersize;
76*4882a593Smuzhiyun };
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun /* format descriptions for capture and preview */
79*4882a593Smuzhiyun static struct airspy_format formats[] = {
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun .pixelformat = V4L2_SDR_FMT_RU12LE,
82*4882a593Smuzhiyun .buffersize = BULK_BUFFER_SIZE,
83*4882a593Smuzhiyun },
84*4882a593Smuzhiyun };
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun static const unsigned int NUM_FORMATS = ARRAY_SIZE(formats);
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun /* intermediate buffers with raw data from the USB device */
89*4882a593Smuzhiyun struct airspy_frame_buf {
90*4882a593Smuzhiyun /* common v4l buffer stuff -- must be first */
91*4882a593Smuzhiyun struct vb2_v4l2_buffer vb;
92*4882a593Smuzhiyun struct list_head list;
93*4882a593Smuzhiyun };
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun struct airspy {
96*4882a593Smuzhiyun #define POWER_ON 1
97*4882a593Smuzhiyun #define USB_STATE_URB_BUF 2
98*4882a593Smuzhiyun unsigned long flags;
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun struct device *dev;
101*4882a593Smuzhiyun struct usb_device *udev;
102*4882a593Smuzhiyun struct video_device vdev;
103*4882a593Smuzhiyun struct v4l2_device v4l2_dev;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun /* videobuf2 queue and queued buffers list */
106*4882a593Smuzhiyun struct vb2_queue vb_queue;
107*4882a593Smuzhiyun struct list_head queued_bufs;
108*4882a593Smuzhiyun spinlock_t queued_bufs_lock; /* Protects queued_bufs */
109*4882a593Smuzhiyun unsigned sequence; /* Buffer sequence counter */
110*4882a593Smuzhiyun unsigned int vb_full; /* vb is full and packets dropped */
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun /* Note if taking both locks v4l2_lock must always be locked first! */
113*4882a593Smuzhiyun struct mutex v4l2_lock; /* Protects everything else */
114*4882a593Smuzhiyun struct mutex vb_queue_lock; /* Protects vb_queue and capt_file */
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun struct urb *urb_list[MAX_BULK_BUFS];
117*4882a593Smuzhiyun int buf_num;
118*4882a593Smuzhiyun unsigned long buf_size;
119*4882a593Smuzhiyun u8 *buf_list[MAX_BULK_BUFS];
120*4882a593Smuzhiyun dma_addr_t dma_addr[MAX_BULK_BUFS];
121*4882a593Smuzhiyun int urbs_initialized;
122*4882a593Smuzhiyun int urbs_submitted;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun /* USB control message buffer */
125*4882a593Smuzhiyun #define BUF_SIZE 128
126*4882a593Smuzhiyun u8 buf[BUF_SIZE];
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun /* Current configuration */
129*4882a593Smuzhiyun unsigned int f_adc;
130*4882a593Smuzhiyun unsigned int f_rf;
131*4882a593Smuzhiyun u32 pixelformat;
132*4882a593Smuzhiyun u32 buffersize;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun /* Controls */
135*4882a593Smuzhiyun struct v4l2_ctrl_handler hdl;
136*4882a593Smuzhiyun struct v4l2_ctrl *lna_gain_auto;
137*4882a593Smuzhiyun struct v4l2_ctrl *lna_gain;
138*4882a593Smuzhiyun struct v4l2_ctrl *mixer_gain_auto;
139*4882a593Smuzhiyun struct v4l2_ctrl *mixer_gain;
140*4882a593Smuzhiyun struct v4l2_ctrl *if_gain;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun /* Sample rate calc */
143*4882a593Smuzhiyun unsigned long jiffies_next;
144*4882a593Smuzhiyun unsigned int sample;
145*4882a593Smuzhiyun unsigned int sample_measured;
146*4882a593Smuzhiyun };
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun #define airspy_dbg_usb_control_msg(_dev, _r, _t, _v, _i, _b, _l) { \
149*4882a593Smuzhiyun char *_direction; \
150*4882a593Smuzhiyun if (_t & USB_DIR_IN) \
151*4882a593Smuzhiyun _direction = "<<<"; \
152*4882a593Smuzhiyun else \
153*4882a593Smuzhiyun _direction = ">>>"; \
154*4882a593Smuzhiyun dev_dbg(_dev, "%02x %02x %02x %02x %02x %02x %02x %02x %s %*ph\n", \
155*4882a593Smuzhiyun _t, _r, _v & 0xff, _v >> 8, _i & 0xff, _i >> 8, \
156*4882a593Smuzhiyun _l & 0xff, _l >> 8, _direction, _l, _b); \
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun /* execute firmware command */
airspy_ctrl_msg(struct airspy * s,u8 request,u16 value,u16 index,u8 * data,u16 size)160*4882a593Smuzhiyun static int airspy_ctrl_msg(struct airspy *s, u8 request, u16 value, u16 index,
161*4882a593Smuzhiyun u8 *data, u16 size)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun int ret;
164*4882a593Smuzhiyun unsigned int pipe;
165*4882a593Smuzhiyun u8 requesttype;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun switch (request) {
168*4882a593Smuzhiyun case CMD_RECEIVER_MODE:
169*4882a593Smuzhiyun case CMD_SET_FREQ:
170*4882a593Smuzhiyun pipe = usb_sndctrlpipe(s->udev, 0);
171*4882a593Smuzhiyun requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
172*4882a593Smuzhiyun break;
173*4882a593Smuzhiyun case CMD_BOARD_ID_READ:
174*4882a593Smuzhiyun case CMD_VERSION_STRING_READ:
175*4882a593Smuzhiyun case CMD_BOARD_PARTID_SERIALNO_READ:
176*4882a593Smuzhiyun case CMD_SET_LNA_GAIN:
177*4882a593Smuzhiyun case CMD_SET_MIXER_GAIN:
178*4882a593Smuzhiyun case CMD_SET_VGA_GAIN:
179*4882a593Smuzhiyun case CMD_SET_LNA_AGC:
180*4882a593Smuzhiyun case CMD_SET_MIXER_AGC:
181*4882a593Smuzhiyun pipe = usb_rcvctrlpipe(s->udev, 0);
182*4882a593Smuzhiyun requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
183*4882a593Smuzhiyun break;
184*4882a593Smuzhiyun default:
185*4882a593Smuzhiyun dev_err(s->dev, "Unknown command %02x\n", request);
186*4882a593Smuzhiyun ret = -EINVAL;
187*4882a593Smuzhiyun goto err;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun /* write request */
191*4882a593Smuzhiyun if (!(requesttype & USB_DIR_IN))
192*4882a593Smuzhiyun memcpy(s->buf, data, size);
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun ret = usb_control_msg(s->udev, pipe, request, requesttype, value,
195*4882a593Smuzhiyun index, s->buf, size, 1000);
196*4882a593Smuzhiyun airspy_dbg_usb_control_msg(s->dev, request, requesttype, value,
197*4882a593Smuzhiyun index, s->buf, size);
198*4882a593Smuzhiyun if (ret < 0) {
199*4882a593Smuzhiyun dev_err(s->dev, "usb_control_msg() failed %d request %02x\n",
200*4882a593Smuzhiyun ret, request);
201*4882a593Smuzhiyun goto err;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun /* read request */
205*4882a593Smuzhiyun if (requesttype & USB_DIR_IN)
206*4882a593Smuzhiyun memcpy(data, s->buf, size);
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun return 0;
209*4882a593Smuzhiyun err:
210*4882a593Smuzhiyun return ret;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun /* Private functions */
airspy_get_next_fill_buf(struct airspy * s)214*4882a593Smuzhiyun static struct airspy_frame_buf *airspy_get_next_fill_buf(struct airspy *s)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun unsigned long flags;
217*4882a593Smuzhiyun struct airspy_frame_buf *buf = NULL;
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun spin_lock_irqsave(&s->queued_bufs_lock, flags);
220*4882a593Smuzhiyun if (list_empty(&s->queued_bufs))
221*4882a593Smuzhiyun goto leave;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun buf = list_entry(s->queued_bufs.next,
224*4882a593Smuzhiyun struct airspy_frame_buf, list);
225*4882a593Smuzhiyun list_del(&buf->list);
226*4882a593Smuzhiyun leave:
227*4882a593Smuzhiyun spin_unlock_irqrestore(&s->queued_bufs_lock, flags);
228*4882a593Smuzhiyun return buf;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun
airspy_convert_stream(struct airspy * s,void * dst,void * src,unsigned int src_len)231*4882a593Smuzhiyun static unsigned int airspy_convert_stream(struct airspy *s,
232*4882a593Smuzhiyun void *dst, void *src, unsigned int src_len)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun unsigned int dst_len;
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun if (s->pixelformat == V4L2_SDR_FMT_RU12LE) {
237*4882a593Smuzhiyun memcpy(dst, src, src_len);
238*4882a593Smuzhiyun dst_len = src_len;
239*4882a593Smuzhiyun } else {
240*4882a593Smuzhiyun dst_len = 0;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun /* calculate sample rate and output it in 10 seconds intervals */
244*4882a593Smuzhiyun if (unlikely(time_is_before_jiffies(s->jiffies_next))) {
245*4882a593Smuzhiyun #define MSECS 10000UL
246*4882a593Smuzhiyun unsigned int msecs = jiffies_to_msecs(jiffies -
247*4882a593Smuzhiyun s->jiffies_next + msecs_to_jiffies(MSECS));
248*4882a593Smuzhiyun unsigned int samples = s->sample - s->sample_measured;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun s->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
251*4882a593Smuzhiyun s->sample_measured = s->sample;
252*4882a593Smuzhiyun dev_dbg(s->dev, "slen=%u samples=%u msecs=%u sample rate=%lu\n",
253*4882a593Smuzhiyun src_len, samples, msecs,
254*4882a593Smuzhiyun samples * 1000UL / msecs);
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun /* total number of samples */
258*4882a593Smuzhiyun s->sample += src_len / 2;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun return dst_len;
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun /*
264*4882a593Smuzhiyun * This gets called for the bulk stream pipe. This is done in interrupt
265*4882a593Smuzhiyun * time, so it has to be fast, not crash, and not stall. Neat.
266*4882a593Smuzhiyun */
airspy_urb_complete(struct urb * urb)267*4882a593Smuzhiyun static void airspy_urb_complete(struct urb *urb)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun struct airspy *s = urb->context;
270*4882a593Smuzhiyun struct airspy_frame_buf *fbuf;
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun dev_dbg_ratelimited(s->dev, "status=%d length=%d/%d errors=%d\n",
273*4882a593Smuzhiyun urb->status, urb->actual_length,
274*4882a593Smuzhiyun urb->transfer_buffer_length, urb->error_count);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun switch (urb->status) {
277*4882a593Smuzhiyun case 0: /* success */
278*4882a593Smuzhiyun case -ETIMEDOUT: /* NAK */
279*4882a593Smuzhiyun break;
280*4882a593Smuzhiyun case -ECONNRESET: /* kill */
281*4882a593Smuzhiyun case -ENOENT:
282*4882a593Smuzhiyun case -ESHUTDOWN:
283*4882a593Smuzhiyun return;
284*4882a593Smuzhiyun default: /* error */
285*4882a593Smuzhiyun dev_err_ratelimited(s->dev, "URB failed %d\n", urb->status);
286*4882a593Smuzhiyun break;
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun if (likely(urb->actual_length > 0)) {
290*4882a593Smuzhiyun void *ptr;
291*4882a593Smuzhiyun unsigned int len;
292*4882a593Smuzhiyun /* get free framebuffer */
293*4882a593Smuzhiyun fbuf = airspy_get_next_fill_buf(s);
294*4882a593Smuzhiyun if (unlikely(fbuf == NULL)) {
295*4882a593Smuzhiyun s->vb_full++;
296*4882a593Smuzhiyun dev_notice_ratelimited(s->dev,
297*4882a593Smuzhiyun "videobuf is full, %d packets dropped\n",
298*4882a593Smuzhiyun s->vb_full);
299*4882a593Smuzhiyun goto skip;
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun /* fill framebuffer */
303*4882a593Smuzhiyun ptr = vb2_plane_vaddr(&fbuf->vb.vb2_buf, 0);
304*4882a593Smuzhiyun len = airspy_convert_stream(s, ptr, urb->transfer_buffer,
305*4882a593Smuzhiyun urb->actual_length);
306*4882a593Smuzhiyun vb2_set_plane_payload(&fbuf->vb.vb2_buf, 0, len);
307*4882a593Smuzhiyun fbuf->vb.vb2_buf.timestamp = ktime_get_ns();
308*4882a593Smuzhiyun fbuf->vb.sequence = s->sequence++;
309*4882a593Smuzhiyun vb2_buffer_done(&fbuf->vb.vb2_buf, VB2_BUF_STATE_DONE);
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun skip:
312*4882a593Smuzhiyun usb_submit_urb(urb, GFP_ATOMIC);
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
airspy_kill_urbs(struct airspy * s)315*4882a593Smuzhiyun static int airspy_kill_urbs(struct airspy *s)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun int i;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun for (i = s->urbs_submitted - 1; i >= 0; i--) {
320*4882a593Smuzhiyun dev_dbg(s->dev, "kill urb=%d\n", i);
321*4882a593Smuzhiyun /* stop the URB */
322*4882a593Smuzhiyun usb_kill_urb(s->urb_list[i]);
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun s->urbs_submitted = 0;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun return 0;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun
airspy_submit_urbs(struct airspy * s)329*4882a593Smuzhiyun static int airspy_submit_urbs(struct airspy *s)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun int i, ret;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun for (i = 0; i < s->urbs_initialized; i++) {
334*4882a593Smuzhiyun dev_dbg(s->dev, "submit urb=%d\n", i);
335*4882a593Smuzhiyun ret = usb_submit_urb(s->urb_list[i], GFP_ATOMIC);
336*4882a593Smuzhiyun if (ret) {
337*4882a593Smuzhiyun dev_err(s->dev, "Could not submit URB no. %d - get them all back\n",
338*4882a593Smuzhiyun i);
339*4882a593Smuzhiyun airspy_kill_urbs(s);
340*4882a593Smuzhiyun return ret;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun s->urbs_submitted++;
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun return 0;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
airspy_free_stream_bufs(struct airspy * s)348*4882a593Smuzhiyun static int airspy_free_stream_bufs(struct airspy *s)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun if (test_bit(USB_STATE_URB_BUF, &s->flags)) {
351*4882a593Smuzhiyun while (s->buf_num) {
352*4882a593Smuzhiyun s->buf_num--;
353*4882a593Smuzhiyun dev_dbg(s->dev, "free buf=%d\n", s->buf_num);
354*4882a593Smuzhiyun usb_free_coherent(s->udev, s->buf_size,
355*4882a593Smuzhiyun s->buf_list[s->buf_num],
356*4882a593Smuzhiyun s->dma_addr[s->buf_num]);
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun clear_bit(USB_STATE_URB_BUF, &s->flags);
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun return 0;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun
airspy_alloc_stream_bufs(struct airspy * s)364*4882a593Smuzhiyun static int airspy_alloc_stream_bufs(struct airspy *s)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun s->buf_num = 0;
367*4882a593Smuzhiyun s->buf_size = BULK_BUFFER_SIZE;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun dev_dbg(s->dev, "all in all I will use %u bytes for streaming\n",
370*4882a593Smuzhiyun MAX_BULK_BUFS * BULK_BUFFER_SIZE);
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun for (s->buf_num = 0; s->buf_num < MAX_BULK_BUFS; s->buf_num++) {
373*4882a593Smuzhiyun s->buf_list[s->buf_num] = usb_alloc_coherent(s->udev,
374*4882a593Smuzhiyun BULK_BUFFER_SIZE, GFP_ATOMIC,
375*4882a593Smuzhiyun &s->dma_addr[s->buf_num]);
376*4882a593Smuzhiyun if (!s->buf_list[s->buf_num]) {
377*4882a593Smuzhiyun dev_dbg(s->dev, "alloc buf=%d failed\n", s->buf_num);
378*4882a593Smuzhiyun airspy_free_stream_bufs(s);
379*4882a593Smuzhiyun return -ENOMEM;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun dev_dbg(s->dev, "alloc buf=%d %p (dma %llu)\n", s->buf_num,
383*4882a593Smuzhiyun s->buf_list[s->buf_num],
384*4882a593Smuzhiyun (long long)s->dma_addr[s->buf_num]);
385*4882a593Smuzhiyun set_bit(USB_STATE_URB_BUF, &s->flags);
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun return 0;
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
airspy_free_urbs(struct airspy * s)391*4882a593Smuzhiyun static int airspy_free_urbs(struct airspy *s)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun int i;
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun airspy_kill_urbs(s);
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun for (i = s->urbs_initialized - 1; i >= 0; i--) {
398*4882a593Smuzhiyun if (s->urb_list[i]) {
399*4882a593Smuzhiyun dev_dbg(s->dev, "free urb=%d\n", i);
400*4882a593Smuzhiyun /* free the URBs */
401*4882a593Smuzhiyun usb_free_urb(s->urb_list[i]);
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun s->urbs_initialized = 0;
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun return 0;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun
airspy_alloc_urbs(struct airspy * s)409*4882a593Smuzhiyun static int airspy_alloc_urbs(struct airspy *s)
410*4882a593Smuzhiyun {
411*4882a593Smuzhiyun int i, j;
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun /* allocate the URBs */
414*4882a593Smuzhiyun for (i = 0; i < MAX_BULK_BUFS; i++) {
415*4882a593Smuzhiyun dev_dbg(s->dev, "alloc urb=%d\n", i);
416*4882a593Smuzhiyun s->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
417*4882a593Smuzhiyun if (!s->urb_list[i]) {
418*4882a593Smuzhiyun for (j = 0; j < i; j++)
419*4882a593Smuzhiyun usb_free_urb(s->urb_list[j]);
420*4882a593Smuzhiyun return -ENOMEM;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun usb_fill_bulk_urb(s->urb_list[i],
423*4882a593Smuzhiyun s->udev,
424*4882a593Smuzhiyun usb_rcvbulkpipe(s->udev, 0x81),
425*4882a593Smuzhiyun s->buf_list[i],
426*4882a593Smuzhiyun BULK_BUFFER_SIZE,
427*4882a593Smuzhiyun airspy_urb_complete, s);
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun s->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
430*4882a593Smuzhiyun s->urb_list[i]->transfer_dma = s->dma_addr[i];
431*4882a593Smuzhiyun s->urbs_initialized++;
432*4882a593Smuzhiyun }
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun return 0;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun /* Must be called with vb_queue_lock hold */
airspy_cleanup_queued_bufs(struct airspy * s)438*4882a593Smuzhiyun static void airspy_cleanup_queued_bufs(struct airspy *s)
439*4882a593Smuzhiyun {
440*4882a593Smuzhiyun unsigned long flags;
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun dev_dbg(s->dev, "\n");
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun spin_lock_irqsave(&s->queued_bufs_lock, flags);
445*4882a593Smuzhiyun while (!list_empty(&s->queued_bufs)) {
446*4882a593Smuzhiyun struct airspy_frame_buf *buf;
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun buf = list_entry(s->queued_bufs.next,
449*4882a593Smuzhiyun struct airspy_frame_buf, list);
450*4882a593Smuzhiyun list_del(&buf->list);
451*4882a593Smuzhiyun vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun spin_unlock_irqrestore(&s->queued_bufs_lock, flags);
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun /* The user yanked out the cable... */
airspy_disconnect(struct usb_interface * intf)457*4882a593Smuzhiyun static void airspy_disconnect(struct usb_interface *intf)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun struct v4l2_device *v = usb_get_intfdata(intf);
460*4882a593Smuzhiyun struct airspy *s = container_of(v, struct airspy, v4l2_dev);
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun dev_dbg(s->dev, "\n");
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun mutex_lock(&s->vb_queue_lock);
465*4882a593Smuzhiyun mutex_lock(&s->v4l2_lock);
466*4882a593Smuzhiyun /* No need to keep the urbs around after disconnection */
467*4882a593Smuzhiyun s->udev = NULL;
468*4882a593Smuzhiyun v4l2_device_disconnect(&s->v4l2_dev);
469*4882a593Smuzhiyun video_unregister_device(&s->vdev);
470*4882a593Smuzhiyun mutex_unlock(&s->v4l2_lock);
471*4882a593Smuzhiyun mutex_unlock(&s->vb_queue_lock);
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun v4l2_device_put(&s->v4l2_dev);
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun /* Videobuf2 operations */
airspy_queue_setup(struct vb2_queue * vq,unsigned int * nbuffers,unsigned int * nplanes,unsigned int sizes[],struct device * alloc_devs[])477*4882a593Smuzhiyun static int airspy_queue_setup(struct vb2_queue *vq,
478*4882a593Smuzhiyun unsigned int *nbuffers,
479*4882a593Smuzhiyun unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[])
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun struct airspy *s = vb2_get_drv_priv(vq);
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun dev_dbg(s->dev, "nbuffers=%d\n", *nbuffers);
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun /* Need at least 8 buffers */
486*4882a593Smuzhiyun if (vq->num_buffers + *nbuffers < 8)
487*4882a593Smuzhiyun *nbuffers = 8 - vq->num_buffers;
488*4882a593Smuzhiyun *nplanes = 1;
489*4882a593Smuzhiyun sizes[0] = PAGE_ALIGN(s->buffersize);
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun dev_dbg(s->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]);
492*4882a593Smuzhiyun return 0;
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun
airspy_buf_queue(struct vb2_buffer * vb)495*4882a593Smuzhiyun static void airspy_buf_queue(struct vb2_buffer *vb)
496*4882a593Smuzhiyun {
497*4882a593Smuzhiyun struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
498*4882a593Smuzhiyun struct airspy *s = vb2_get_drv_priv(vb->vb2_queue);
499*4882a593Smuzhiyun struct airspy_frame_buf *buf =
500*4882a593Smuzhiyun container_of(vbuf, struct airspy_frame_buf, vb);
501*4882a593Smuzhiyun unsigned long flags;
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun /* Check the device has not disconnected between prep and queuing */
504*4882a593Smuzhiyun if (unlikely(!s->udev)) {
505*4882a593Smuzhiyun vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
506*4882a593Smuzhiyun return;
507*4882a593Smuzhiyun }
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun spin_lock_irqsave(&s->queued_bufs_lock, flags);
510*4882a593Smuzhiyun list_add_tail(&buf->list, &s->queued_bufs);
511*4882a593Smuzhiyun spin_unlock_irqrestore(&s->queued_bufs_lock, flags);
512*4882a593Smuzhiyun }
513*4882a593Smuzhiyun
airspy_start_streaming(struct vb2_queue * vq,unsigned int count)514*4882a593Smuzhiyun static int airspy_start_streaming(struct vb2_queue *vq, unsigned int count)
515*4882a593Smuzhiyun {
516*4882a593Smuzhiyun struct airspy *s = vb2_get_drv_priv(vq);
517*4882a593Smuzhiyun int ret;
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun dev_dbg(s->dev, "\n");
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun if (!s->udev)
522*4882a593Smuzhiyun return -ENODEV;
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun mutex_lock(&s->v4l2_lock);
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun s->sequence = 0;
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun set_bit(POWER_ON, &s->flags);
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun ret = airspy_alloc_stream_bufs(s);
531*4882a593Smuzhiyun if (ret)
532*4882a593Smuzhiyun goto err_clear_bit;
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun ret = airspy_alloc_urbs(s);
535*4882a593Smuzhiyun if (ret)
536*4882a593Smuzhiyun goto err_free_stream_bufs;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun ret = airspy_submit_urbs(s);
539*4882a593Smuzhiyun if (ret)
540*4882a593Smuzhiyun goto err_free_urbs;
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun /* start hardware streaming */
543*4882a593Smuzhiyun ret = airspy_ctrl_msg(s, CMD_RECEIVER_MODE, 1, 0, NULL, 0);
544*4882a593Smuzhiyun if (ret)
545*4882a593Smuzhiyun goto err_kill_urbs;
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun goto exit_mutex_unlock;
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun err_kill_urbs:
550*4882a593Smuzhiyun airspy_kill_urbs(s);
551*4882a593Smuzhiyun err_free_urbs:
552*4882a593Smuzhiyun airspy_free_urbs(s);
553*4882a593Smuzhiyun err_free_stream_bufs:
554*4882a593Smuzhiyun airspy_free_stream_bufs(s);
555*4882a593Smuzhiyun err_clear_bit:
556*4882a593Smuzhiyun clear_bit(POWER_ON, &s->flags);
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun /* return all queued buffers to vb2 */
559*4882a593Smuzhiyun {
560*4882a593Smuzhiyun struct airspy_frame_buf *buf, *tmp;
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun list_for_each_entry_safe(buf, tmp, &s->queued_bufs, list) {
563*4882a593Smuzhiyun list_del(&buf->list);
564*4882a593Smuzhiyun vb2_buffer_done(&buf->vb.vb2_buf,
565*4882a593Smuzhiyun VB2_BUF_STATE_QUEUED);
566*4882a593Smuzhiyun }
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun exit_mutex_unlock:
570*4882a593Smuzhiyun mutex_unlock(&s->v4l2_lock);
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun return ret;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun
airspy_stop_streaming(struct vb2_queue * vq)575*4882a593Smuzhiyun static void airspy_stop_streaming(struct vb2_queue *vq)
576*4882a593Smuzhiyun {
577*4882a593Smuzhiyun struct airspy *s = vb2_get_drv_priv(vq);
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun dev_dbg(s->dev, "\n");
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun mutex_lock(&s->v4l2_lock);
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun /* stop hardware streaming */
584*4882a593Smuzhiyun airspy_ctrl_msg(s, CMD_RECEIVER_MODE, 0, 0, NULL, 0);
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun airspy_kill_urbs(s);
587*4882a593Smuzhiyun airspy_free_urbs(s);
588*4882a593Smuzhiyun airspy_free_stream_bufs(s);
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun airspy_cleanup_queued_bufs(s);
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun clear_bit(POWER_ON, &s->flags);
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun mutex_unlock(&s->v4l2_lock);
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun static const struct vb2_ops airspy_vb2_ops = {
598*4882a593Smuzhiyun .queue_setup = airspy_queue_setup,
599*4882a593Smuzhiyun .buf_queue = airspy_buf_queue,
600*4882a593Smuzhiyun .start_streaming = airspy_start_streaming,
601*4882a593Smuzhiyun .stop_streaming = airspy_stop_streaming,
602*4882a593Smuzhiyun .wait_prepare = vb2_ops_wait_prepare,
603*4882a593Smuzhiyun .wait_finish = vb2_ops_wait_finish,
604*4882a593Smuzhiyun };
605*4882a593Smuzhiyun
airspy_querycap(struct file * file,void * fh,struct v4l2_capability * cap)606*4882a593Smuzhiyun static int airspy_querycap(struct file *file, void *fh,
607*4882a593Smuzhiyun struct v4l2_capability *cap)
608*4882a593Smuzhiyun {
609*4882a593Smuzhiyun struct airspy *s = video_drvdata(file);
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
612*4882a593Smuzhiyun strscpy(cap->card, s->vdev.name, sizeof(cap->card));
613*4882a593Smuzhiyun usb_make_path(s->udev, cap->bus_info, sizeof(cap->bus_info));
614*4882a593Smuzhiyun return 0;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun
airspy_enum_fmt_sdr_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)617*4882a593Smuzhiyun static int airspy_enum_fmt_sdr_cap(struct file *file, void *priv,
618*4882a593Smuzhiyun struct v4l2_fmtdesc *f)
619*4882a593Smuzhiyun {
620*4882a593Smuzhiyun if (f->index >= NUM_FORMATS)
621*4882a593Smuzhiyun return -EINVAL;
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun f->pixelformat = formats[f->index].pixelformat;
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun return 0;
626*4882a593Smuzhiyun }
627*4882a593Smuzhiyun
airspy_g_fmt_sdr_cap(struct file * file,void * priv,struct v4l2_format * f)628*4882a593Smuzhiyun static int airspy_g_fmt_sdr_cap(struct file *file, void *priv,
629*4882a593Smuzhiyun struct v4l2_format *f)
630*4882a593Smuzhiyun {
631*4882a593Smuzhiyun struct airspy *s = video_drvdata(file);
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun f->fmt.sdr.pixelformat = s->pixelformat;
634*4882a593Smuzhiyun f->fmt.sdr.buffersize = s->buffersize;
635*4882a593Smuzhiyun memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun return 0;
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun
airspy_s_fmt_sdr_cap(struct file * file,void * priv,struct v4l2_format * f)640*4882a593Smuzhiyun static int airspy_s_fmt_sdr_cap(struct file *file, void *priv,
641*4882a593Smuzhiyun struct v4l2_format *f)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun struct airspy *s = video_drvdata(file);
644*4882a593Smuzhiyun struct vb2_queue *q = &s->vb_queue;
645*4882a593Smuzhiyun int i;
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun if (vb2_is_busy(q))
648*4882a593Smuzhiyun return -EBUSY;
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
651*4882a593Smuzhiyun for (i = 0; i < NUM_FORMATS; i++) {
652*4882a593Smuzhiyun if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
653*4882a593Smuzhiyun s->pixelformat = formats[i].pixelformat;
654*4882a593Smuzhiyun s->buffersize = formats[i].buffersize;
655*4882a593Smuzhiyun f->fmt.sdr.buffersize = formats[i].buffersize;
656*4882a593Smuzhiyun return 0;
657*4882a593Smuzhiyun }
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun s->pixelformat = formats[0].pixelformat;
661*4882a593Smuzhiyun s->buffersize = formats[0].buffersize;
662*4882a593Smuzhiyun f->fmt.sdr.pixelformat = formats[0].pixelformat;
663*4882a593Smuzhiyun f->fmt.sdr.buffersize = formats[0].buffersize;
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun return 0;
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun
airspy_try_fmt_sdr_cap(struct file * file,void * priv,struct v4l2_format * f)668*4882a593Smuzhiyun static int airspy_try_fmt_sdr_cap(struct file *file, void *priv,
669*4882a593Smuzhiyun struct v4l2_format *f)
670*4882a593Smuzhiyun {
671*4882a593Smuzhiyun int i;
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
674*4882a593Smuzhiyun for (i = 0; i < NUM_FORMATS; i++) {
675*4882a593Smuzhiyun if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
676*4882a593Smuzhiyun f->fmt.sdr.buffersize = formats[i].buffersize;
677*4882a593Smuzhiyun return 0;
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun f->fmt.sdr.pixelformat = formats[0].pixelformat;
682*4882a593Smuzhiyun f->fmt.sdr.buffersize = formats[0].buffersize;
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun return 0;
685*4882a593Smuzhiyun }
686*4882a593Smuzhiyun
airspy_s_tuner(struct file * file,void * priv,const struct v4l2_tuner * v)687*4882a593Smuzhiyun static int airspy_s_tuner(struct file *file, void *priv,
688*4882a593Smuzhiyun const struct v4l2_tuner *v)
689*4882a593Smuzhiyun {
690*4882a593Smuzhiyun int ret;
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun if (v->index == 0)
693*4882a593Smuzhiyun ret = 0;
694*4882a593Smuzhiyun else if (v->index == 1)
695*4882a593Smuzhiyun ret = 0;
696*4882a593Smuzhiyun else
697*4882a593Smuzhiyun ret = -EINVAL;
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun return ret;
700*4882a593Smuzhiyun }
701*4882a593Smuzhiyun
airspy_g_tuner(struct file * file,void * priv,struct v4l2_tuner * v)702*4882a593Smuzhiyun static int airspy_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
703*4882a593Smuzhiyun {
704*4882a593Smuzhiyun int ret;
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun if (v->index == 0) {
707*4882a593Smuzhiyun strscpy(v->name, "AirSpy ADC", sizeof(v->name));
708*4882a593Smuzhiyun v->type = V4L2_TUNER_ADC;
709*4882a593Smuzhiyun v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
710*4882a593Smuzhiyun v->rangelow = bands[0].rangelow;
711*4882a593Smuzhiyun v->rangehigh = bands[0].rangehigh;
712*4882a593Smuzhiyun ret = 0;
713*4882a593Smuzhiyun } else if (v->index == 1) {
714*4882a593Smuzhiyun strscpy(v->name, "AirSpy RF", sizeof(v->name));
715*4882a593Smuzhiyun v->type = V4L2_TUNER_RF;
716*4882a593Smuzhiyun v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
717*4882a593Smuzhiyun v->rangelow = bands_rf[0].rangelow;
718*4882a593Smuzhiyun v->rangehigh = bands_rf[0].rangehigh;
719*4882a593Smuzhiyun ret = 0;
720*4882a593Smuzhiyun } else {
721*4882a593Smuzhiyun ret = -EINVAL;
722*4882a593Smuzhiyun }
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun return ret;
725*4882a593Smuzhiyun }
726*4882a593Smuzhiyun
airspy_g_frequency(struct file * file,void * priv,struct v4l2_frequency * f)727*4882a593Smuzhiyun static int airspy_g_frequency(struct file *file, void *priv,
728*4882a593Smuzhiyun struct v4l2_frequency *f)
729*4882a593Smuzhiyun {
730*4882a593Smuzhiyun struct airspy *s = video_drvdata(file);
731*4882a593Smuzhiyun int ret;
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun if (f->tuner == 0) {
734*4882a593Smuzhiyun f->type = V4L2_TUNER_ADC;
735*4882a593Smuzhiyun f->frequency = s->f_adc;
736*4882a593Smuzhiyun dev_dbg(s->dev, "ADC frequency=%u Hz\n", s->f_adc);
737*4882a593Smuzhiyun ret = 0;
738*4882a593Smuzhiyun } else if (f->tuner == 1) {
739*4882a593Smuzhiyun f->type = V4L2_TUNER_RF;
740*4882a593Smuzhiyun f->frequency = s->f_rf;
741*4882a593Smuzhiyun dev_dbg(s->dev, "RF frequency=%u Hz\n", s->f_rf);
742*4882a593Smuzhiyun ret = 0;
743*4882a593Smuzhiyun } else {
744*4882a593Smuzhiyun ret = -EINVAL;
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun return ret;
748*4882a593Smuzhiyun }
749*4882a593Smuzhiyun
airspy_s_frequency(struct file * file,void * priv,const struct v4l2_frequency * f)750*4882a593Smuzhiyun static int airspy_s_frequency(struct file *file, void *priv,
751*4882a593Smuzhiyun const struct v4l2_frequency *f)
752*4882a593Smuzhiyun {
753*4882a593Smuzhiyun struct airspy *s = video_drvdata(file);
754*4882a593Smuzhiyun int ret;
755*4882a593Smuzhiyun u8 buf[4];
756*4882a593Smuzhiyun
757*4882a593Smuzhiyun if (f->tuner == 0) {
758*4882a593Smuzhiyun s->f_adc = clamp_t(unsigned int, f->frequency,
759*4882a593Smuzhiyun bands[0].rangelow,
760*4882a593Smuzhiyun bands[0].rangehigh);
761*4882a593Smuzhiyun dev_dbg(s->dev, "ADC frequency=%u Hz\n", s->f_adc);
762*4882a593Smuzhiyun ret = 0;
763*4882a593Smuzhiyun } else if (f->tuner == 1) {
764*4882a593Smuzhiyun s->f_rf = clamp_t(unsigned int, f->frequency,
765*4882a593Smuzhiyun bands_rf[0].rangelow,
766*4882a593Smuzhiyun bands_rf[0].rangehigh);
767*4882a593Smuzhiyun dev_dbg(s->dev, "RF frequency=%u Hz\n", s->f_rf);
768*4882a593Smuzhiyun buf[0] = (s->f_rf >> 0) & 0xff;
769*4882a593Smuzhiyun buf[1] = (s->f_rf >> 8) & 0xff;
770*4882a593Smuzhiyun buf[2] = (s->f_rf >> 16) & 0xff;
771*4882a593Smuzhiyun buf[3] = (s->f_rf >> 24) & 0xff;
772*4882a593Smuzhiyun ret = airspy_ctrl_msg(s, CMD_SET_FREQ, 0, 0, buf, 4);
773*4882a593Smuzhiyun } else {
774*4882a593Smuzhiyun ret = -EINVAL;
775*4882a593Smuzhiyun }
776*4882a593Smuzhiyun
777*4882a593Smuzhiyun return ret;
778*4882a593Smuzhiyun }
779*4882a593Smuzhiyun
airspy_enum_freq_bands(struct file * file,void * priv,struct v4l2_frequency_band * band)780*4882a593Smuzhiyun static int airspy_enum_freq_bands(struct file *file, void *priv,
781*4882a593Smuzhiyun struct v4l2_frequency_band *band)
782*4882a593Smuzhiyun {
783*4882a593Smuzhiyun int ret;
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun if (band->tuner == 0) {
786*4882a593Smuzhiyun if (band->index >= ARRAY_SIZE(bands)) {
787*4882a593Smuzhiyun ret = -EINVAL;
788*4882a593Smuzhiyun } else {
789*4882a593Smuzhiyun *band = bands[band->index];
790*4882a593Smuzhiyun ret = 0;
791*4882a593Smuzhiyun }
792*4882a593Smuzhiyun } else if (band->tuner == 1) {
793*4882a593Smuzhiyun if (band->index >= ARRAY_SIZE(bands_rf)) {
794*4882a593Smuzhiyun ret = -EINVAL;
795*4882a593Smuzhiyun } else {
796*4882a593Smuzhiyun *band = bands_rf[band->index];
797*4882a593Smuzhiyun ret = 0;
798*4882a593Smuzhiyun }
799*4882a593Smuzhiyun } else {
800*4882a593Smuzhiyun ret = -EINVAL;
801*4882a593Smuzhiyun }
802*4882a593Smuzhiyun
803*4882a593Smuzhiyun return ret;
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun
806*4882a593Smuzhiyun static const struct v4l2_ioctl_ops airspy_ioctl_ops = {
807*4882a593Smuzhiyun .vidioc_querycap = airspy_querycap,
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun .vidioc_enum_fmt_sdr_cap = airspy_enum_fmt_sdr_cap,
810*4882a593Smuzhiyun .vidioc_g_fmt_sdr_cap = airspy_g_fmt_sdr_cap,
811*4882a593Smuzhiyun .vidioc_s_fmt_sdr_cap = airspy_s_fmt_sdr_cap,
812*4882a593Smuzhiyun .vidioc_try_fmt_sdr_cap = airspy_try_fmt_sdr_cap,
813*4882a593Smuzhiyun
814*4882a593Smuzhiyun .vidioc_reqbufs = vb2_ioctl_reqbufs,
815*4882a593Smuzhiyun .vidioc_create_bufs = vb2_ioctl_create_bufs,
816*4882a593Smuzhiyun .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
817*4882a593Smuzhiyun .vidioc_querybuf = vb2_ioctl_querybuf,
818*4882a593Smuzhiyun .vidioc_qbuf = vb2_ioctl_qbuf,
819*4882a593Smuzhiyun .vidioc_dqbuf = vb2_ioctl_dqbuf,
820*4882a593Smuzhiyun
821*4882a593Smuzhiyun .vidioc_streamon = vb2_ioctl_streamon,
822*4882a593Smuzhiyun .vidioc_streamoff = vb2_ioctl_streamoff,
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun .vidioc_g_tuner = airspy_g_tuner,
825*4882a593Smuzhiyun .vidioc_s_tuner = airspy_s_tuner,
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun .vidioc_g_frequency = airspy_g_frequency,
828*4882a593Smuzhiyun .vidioc_s_frequency = airspy_s_frequency,
829*4882a593Smuzhiyun .vidioc_enum_freq_bands = airspy_enum_freq_bands,
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
832*4882a593Smuzhiyun .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
833*4882a593Smuzhiyun .vidioc_log_status = v4l2_ctrl_log_status,
834*4882a593Smuzhiyun };
835*4882a593Smuzhiyun
836*4882a593Smuzhiyun static const struct v4l2_file_operations airspy_fops = {
837*4882a593Smuzhiyun .owner = THIS_MODULE,
838*4882a593Smuzhiyun .open = v4l2_fh_open,
839*4882a593Smuzhiyun .release = vb2_fop_release,
840*4882a593Smuzhiyun .read = vb2_fop_read,
841*4882a593Smuzhiyun .poll = vb2_fop_poll,
842*4882a593Smuzhiyun .mmap = vb2_fop_mmap,
843*4882a593Smuzhiyun .unlocked_ioctl = video_ioctl2,
844*4882a593Smuzhiyun };
845*4882a593Smuzhiyun
846*4882a593Smuzhiyun static const struct video_device airspy_template = {
847*4882a593Smuzhiyun .name = "AirSpy SDR",
848*4882a593Smuzhiyun .release = video_device_release_empty,
849*4882a593Smuzhiyun .fops = &airspy_fops,
850*4882a593Smuzhiyun .ioctl_ops = &airspy_ioctl_ops,
851*4882a593Smuzhiyun };
852*4882a593Smuzhiyun
airspy_video_release(struct v4l2_device * v)853*4882a593Smuzhiyun static void airspy_video_release(struct v4l2_device *v)
854*4882a593Smuzhiyun {
855*4882a593Smuzhiyun struct airspy *s = container_of(v, struct airspy, v4l2_dev);
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun v4l2_ctrl_handler_free(&s->hdl);
858*4882a593Smuzhiyun v4l2_device_unregister(&s->v4l2_dev);
859*4882a593Smuzhiyun kfree(s);
860*4882a593Smuzhiyun }
861*4882a593Smuzhiyun
airspy_set_lna_gain(struct airspy * s)862*4882a593Smuzhiyun static int airspy_set_lna_gain(struct airspy *s)
863*4882a593Smuzhiyun {
864*4882a593Smuzhiyun int ret;
865*4882a593Smuzhiyun u8 u8tmp;
866*4882a593Smuzhiyun
867*4882a593Smuzhiyun dev_dbg(s->dev, "lna auto=%d->%d val=%d->%d\n",
868*4882a593Smuzhiyun s->lna_gain_auto->cur.val, s->lna_gain_auto->val,
869*4882a593Smuzhiyun s->lna_gain->cur.val, s->lna_gain->val);
870*4882a593Smuzhiyun
871*4882a593Smuzhiyun ret = airspy_ctrl_msg(s, CMD_SET_LNA_AGC, 0, s->lna_gain_auto->val,
872*4882a593Smuzhiyun &u8tmp, 1);
873*4882a593Smuzhiyun if (ret)
874*4882a593Smuzhiyun goto err;
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun if (s->lna_gain_auto->val == false) {
877*4882a593Smuzhiyun ret = airspy_ctrl_msg(s, CMD_SET_LNA_GAIN, 0, s->lna_gain->val,
878*4882a593Smuzhiyun &u8tmp, 1);
879*4882a593Smuzhiyun if (ret)
880*4882a593Smuzhiyun goto err;
881*4882a593Smuzhiyun }
882*4882a593Smuzhiyun err:
883*4882a593Smuzhiyun if (ret)
884*4882a593Smuzhiyun dev_dbg(s->dev, "failed=%d\n", ret);
885*4882a593Smuzhiyun
886*4882a593Smuzhiyun return ret;
887*4882a593Smuzhiyun }
888*4882a593Smuzhiyun
airspy_set_mixer_gain(struct airspy * s)889*4882a593Smuzhiyun static int airspy_set_mixer_gain(struct airspy *s)
890*4882a593Smuzhiyun {
891*4882a593Smuzhiyun int ret;
892*4882a593Smuzhiyun u8 u8tmp;
893*4882a593Smuzhiyun
894*4882a593Smuzhiyun dev_dbg(s->dev, "mixer auto=%d->%d val=%d->%d\n",
895*4882a593Smuzhiyun s->mixer_gain_auto->cur.val, s->mixer_gain_auto->val,
896*4882a593Smuzhiyun s->mixer_gain->cur.val, s->mixer_gain->val);
897*4882a593Smuzhiyun
898*4882a593Smuzhiyun ret = airspy_ctrl_msg(s, CMD_SET_MIXER_AGC, 0, s->mixer_gain_auto->val,
899*4882a593Smuzhiyun &u8tmp, 1);
900*4882a593Smuzhiyun if (ret)
901*4882a593Smuzhiyun goto err;
902*4882a593Smuzhiyun
903*4882a593Smuzhiyun if (s->mixer_gain_auto->val == false) {
904*4882a593Smuzhiyun ret = airspy_ctrl_msg(s, CMD_SET_MIXER_GAIN, 0,
905*4882a593Smuzhiyun s->mixer_gain->val, &u8tmp, 1);
906*4882a593Smuzhiyun if (ret)
907*4882a593Smuzhiyun goto err;
908*4882a593Smuzhiyun }
909*4882a593Smuzhiyun err:
910*4882a593Smuzhiyun if (ret)
911*4882a593Smuzhiyun dev_dbg(s->dev, "failed=%d\n", ret);
912*4882a593Smuzhiyun
913*4882a593Smuzhiyun return ret;
914*4882a593Smuzhiyun }
915*4882a593Smuzhiyun
airspy_set_if_gain(struct airspy * s)916*4882a593Smuzhiyun static int airspy_set_if_gain(struct airspy *s)
917*4882a593Smuzhiyun {
918*4882a593Smuzhiyun int ret;
919*4882a593Smuzhiyun u8 u8tmp;
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun dev_dbg(s->dev, "val=%d->%d\n", s->if_gain->cur.val, s->if_gain->val);
922*4882a593Smuzhiyun
923*4882a593Smuzhiyun ret = airspy_ctrl_msg(s, CMD_SET_VGA_GAIN, 0, s->if_gain->val,
924*4882a593Smuzhiyun &u8tmp, 1);
925*4882a593Smuzhiyun if (ret)
926*4882a593Smuzhiyun dev_dbg(s->dev, "failed=%d\n", ret);
927*4882a593Smuzhiyun
928*4882a593Smuzhiyun return ret;
929*4882a593Smuzhiyun }
930*4882a593Smuzhiyun
airspy_s_ctrl(struct v4l2_ctrl * ctrl)931*4882a593Smuzhiyun static int airspy_s_ctrl(struct v4l2_ctrl *ctrl)
932*4882a593Smuzhiyun {
933*4882a593Smuzhiyun struct airspy *s = container_of(ctrl->handler, struct airspy, hdl);
934*4882a593Smuzhiyun int ret;
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun switch (ctrl->id) {
937*4882a593Smuzhiyun case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO:
938*4882a593Smuzhiyun case V4L2_CID_RF_TUNER_LNA_GAIN:
939*4882a593Smuzhiyun ret = airspy_set_lna_gain(s);
940*4882a593Smuzhiyun break;
941*4882a593Smuzhiyun case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO:
942*4882a593Smuzhiyun case V4L2_CID_RF_TUNER_MIXER_GAIN:
943*4882a593Smuzhiyun ret = airspy_set_mixer_gain(s);
944*4882a593Smuzhiyun break;
945*4882a593Smuzhiyun case V4L2_CID_RF_TUNER_IF_GAIN:
946*4882a593Smuzhiyun ret = airspy_set_if_gain(s);
947*4882a593Smuzhiyun break;
948*4882a593Smuzhiyun default:
949*4882a593Smuzhiyun dev_dbg(s->dev, "unknown ctrl: id=%d name=%s\n",
950*4882a593Smuzhiyun ctrl->id, ctrl->name);
951*4882a593Smuzhiyun ret = -EINVAL;
952*4882a593Smuzhiyun }
953*4882a593Smuzhiyun
954*4882a593Smuzhiyun return ret;
955*4882a593Smuzhiyun }
956*4882a593Smuzhiyun
957*4882a593Smuzhiyun static const struct v4l2_ctrl_ops airspy_ctrl_ops = {
958*4882a593Smuzhiyun .s_ctrl = airspy_s_ctrl,
959*4882a593Smuzhiyun };
960*4882a593Smuzhiyun
airspy_probe(struct usb_interface * intf,const struct usb_device_id * id)961*4882a593Smuzhiyun static int airspy_probe(struct usb_interface *intf,
962*4882a593Smuzhiyun const struct usb_device_id *id)
963*4882a593Smuzhiyun {
964*4882a593Smuzhiyun struct airspy *s;
965*4882a593Smuzhiyun int ret;
966*4882a593Smuzhiyun u8 u8tmp, buf[BUF_SIZE];
967*4882a593Smuzhiyun
968*4882a593Smuzhiyun s = kzalloc(sizeof(struct airspy), GFP_KERNEL);
969*4882a593Smuzhiyun if (s == NULL) {
970*4882a593Smuzhiyun dev_err(&intf->dev, "Could not allocate memory for state\n");
971*4882a593Smuzhiyun return -ENOMEM;
972*4882a593Smuzhiyun }
973*4882a593Smuzhiyun
974*4882a593Smuzhiyun mutex_init(&s->v4l2_lock);
975*4882a593Smuzhiyun mutex_init(&s->vb_queue_lock);
976*4882a593Smuzhiyun spin_lock_init(&s->queued_bufs_lock);
977*4882a593Smuzhiyun INIT_LIST_HEAD(&s->queued_bufs);
978*4882a593Smuzhiyun s->dev = &intf->dev;
979*4882a593Smuzhiyun s->udev = interface_to_usbdev(intf);
980*4882a593Smuzhiyun s->f_adc = bands[0].rangelow;
981*4882a593Smuzhiyun s->f_rf = bands_rf[0].rangelow;
982*4882a593Smuzhiyun s->pixelformat = formats[0].pixelformat;
983*4882a593Smuzhiyun s->buffersize = formats[0].buffersize;
984*4882a593Smuzhiyun
985*4882a593Smuzhiyun /* Detect device */
986*4882a593Smuzhiyun ret = airspy_ctrl_msg(s, CMD_BOARD_ID_READ, 0, 0, &u8tmp, 1);
987*4882a593Smuzhiyun if (ret == 0)
988*4882a593Smuzhiyun ret = airspy_ctrl_msg(s, CMD_VERSION_STRING_READ, 0, 0,
989*4882a593Smuzhiyun buf, BUF_SIZE);
990*4882a593Smuzhiyun if (ret) {
991*4882a593Smuzhiyun dev_err(s->dev, "Could not detect board\n");
992*4882a593Smuzhiyun goto err_free_mem;
993*4882a593Smuzhiyun }
994*4882a593Smuzhiyun
995*4882a593Smuzhiyun buf[BUF_SIZE - 1] = '\0';
996*4882a593Smuzhiyun
997*4882a593Smuzhiyun dev_info(s->dev, "Board ID: %02x\n", u8tmp);
998*4882a593Smuzhiyun dev_info(s->dev, "Firmware version: %s\n", buf);
999*4882a593Smuzhiyun
1000*4882a593Smuzhiyun /* Init videobuf2 queue structure */
1001*4882a593Smuzhiyun s->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
1002*4882a593Smuzhiyun s->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
1003*4882a593Smuzhiyun s->vb_queue.drv_priv = s;
1004*4882a593Smuzhiyun s->vb_queue.buf_struct_size = sizeof(struct airspy_frame_buf);
1005*4882a593Smuzhiyun s->vb_queue.ops = &airspy_vb2_ops;
1006*4882a593Smuzhiyun s->vb_queue.mem_ops = &vb2_vmalloc_memops;
1007*4882a593Smuzhiyun s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1008*4882a593Smuzhiyun ret = vb2_queue_init(&s->vb_queue);
1009*4882a593Smuzhiyun if (ret) {
1010*4882a593Smuzhiyun dev_err(s->dev, "Could not initialize vb2 queue\n");
1011*4882a593Smuzhiyun goto err_free_mem;
1012*4882a593Smuzhiyun }
1013*4882a593Smuzhiyun
1014*4882a593Smuzhiyun /* Init video_device structure */
1015*4882a593Smuzhiyun s->vdev = airspy_template;
1016*4882a593Smuzhiyun s->vdev.queue = &s->vb_queue;
1017*4882a593Smuzhiyun s->vdev.queue->lock = &s->vb_queue_lock;
1018*4882a593Smuzhiyun video_set_drvdata(&s->vdev, s);
1019*4882a593Smuzhiyun
1020*4882a593Smuzhiyun /* Register the v4l2_device structure */
1021*4882a593Smuzhiyun s->v4l2_dev.release = airspy_video_release;
1022*4882a593Smuzhiyun ret = v4l2_device_register(&intf->dev, &s->v4l2_dev);
1023*4882a593Smuzhiyun if (ret) {
1024*4882a593Smuzhiyun dev_err(s->dev, "Failed to register v4l2-device (%d)\n", ret);
1025*4882a593Smuzhiyun goto err_free_mem;
1026*4882a593Smuzhiyun }
1027*4882a593Smuzhiyun
1028*4882a593Smuzhiyun /* Register controls */
1029*4882a593Smuzhiyun v4l2_ctrl_handler_init(&s->hdl, 5);
1030*4882a593Smuzhiyun s->lna_gain_auto = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
1031*4882a593Smuzhiyun V4L2_CID_RF_TUNER_LNA_GAIN_AUTO, 0, 1, 1, 0);
1032*4882a593Smuzhiyun s->lna_gain = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
1033*4882a593Smuzhiyun V4L2_CID_RF_TUNER_LNA_GAIN, 0, 14, 1, 8);
1034*4882a593Smuzhiyun v4l2_ctrl_auto_cluster(2, &s->lna_gain_auto, 0, false);
1035*4882a593Smuzhiyun s->mixer_gain_auto = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
1036*4882a593Smuzhiyun V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO, 0, 1, 1, 0);
1037*4882a593Smuzhiyun s->mixer_gain = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
1038*4882a593Smuzhiyun V4L2_CID_RF_TUNER_MIXER_GAIN, 0, 15, 1, 8);
1039*4882a593Smuzhiyun v4l2_ctrl_auto_cluster(2, &s->mixer_gain_auto, 0, false);
1040*4882a593Smuzhiyun s->if_gain = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
1041*4882a593Smuzhiyun V4L2_CID_RF_TUNER_IF_GAIN, 0, 15, 1, 0);
1042*4882a593Smuzhiyun if (s->hdl.error) {
1043*4882a593Smuzhiyun ret = s->hdl.error;
1044*4882a593Smuzhiyun dev_err(s->dev, "Could not initialize controls\n");
1045*4882a593Smuzhiyun goto err_free_controls;
1046*4882a593Smuzhiyun }
1047*4882a593Smuzhiyun
1048*4882a593Smuzhiyun v4l2_ctrl_handler_setup(&s->hdl);
1049*4882a593Smuzhiyun
1050*4882a593Smuzhiyun s->v4l2_dev.ctrl_handler = &s->hdl;
1051*4882a593Smuzhiyun s->vdev.v4l2_dev = &s->v4l2_dev;
1052*4882a593Smuzhiyun s->vdev.lock = &s->v4l2_lock;
1053*4882a593Smuzhiyun s->vdev.device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING |
1054*4882a593Smuzhiyun V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
1055*4882a593Smuzhiyun
1056*4882a593Smuzhiyun ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1);
1057*4882a593Smuzhiyun if (ret) {
1058*4882a593Smuzhiyun dev_err(s->dev, "Failed to register as video device (%d)\n",
1059*4882a593Smuzhiyun ret);
1060*4882a593Smuzhiyun goto err_free_controls;
1061*4882a593Smuzhiyun }
1062*4882a593Smuzhiyun dev_info(s->dev, "Registered as %s\n",
1063*4882a593Smuzhiyun video_device_node_name(&s->vdev));
1064*4882a593Smuzhiyun dev_notice(s->dev, "SDR API is still slightly experimental and functionality changes may follow\n");
1065*4882a593Smuzhiyun return 0;
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun err_free_controls:
1068*4882a593Smuzhiyun v4l2_ctrl_handler_free(&s->hdl);
1069*4882a593Smuzhiyun v4l2_device_unregister(&s->v4l2_dev);
1070*4882a593Smuzhiyun err_free_mem:
1071*4882a593Smuzhiyun kfree(s);
1072*4882a593Smuzhiyun return ret;
1073*4882a593Smuzhiyun }
1074*4882a593Smuzhiyun
1075*4882a593Smuzhiyun /* USB device ID list */
1076*4882a593Smuzhiyun static const struct usb_device_id airspy_id_table[] = {
1077*4882a593Smuzhiyun { USB_DEVICE(0x1d50, 0x60a1) }, /* AirSpy */
1078*4882a593Smuzhiyun { }
1079*4882a593Smuzhiyun };
1080*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, airspy_id_table);
1081*4882a593Smuzhiyun
1082*4882a593Smuzhiyun /* USB subsystem interface */
1083*4882a593Smuzhiyun static struct usb_driver airspy_driver = {
1084*4882a593Smuzhiyun .name = KBUILD_MODNAME,
1085*4882a593Smuzhiyun .probe = airspy_probe,
1086*4882a593Smuzhiyun .disconnect = airspy_disconnect,
1087*4882a593Smuzhiyun .id_table = airspy_id_table,
1088*4882a593Smuzhiyun };
1089*4882a593Smuzhiyun
1090*4882a593Smuzhiyun module_usb_driver(airspy_driver);
1091*4882a593Smuzhiyun
1092*4882a593Smuzhiyun MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
1093*4882a593Smuzhiyun MODULE_DESCRIPTION("AirSpy SDR");
1094*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1095