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