summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librtlsdr.c121
-rw-r--r--src/tuner_fc0013.c4
-rw-r--r--src/tuner_r82xx.c96
3 files changed, 126 insertions, 95 deletions
diff --git a/src/librtlsdr.c b/src/librtlsdr.c
index cdf1ca9..096abae 100644
--- a/src/librtlsdr.c
+++ b/src/librtlsdr.c
@@ -39,12 +39,6 @@
#define LIBUSB_CALL
#endif
-/* libusb < 1.0.9 doesn't have libusb_handle_events_timeout_completed */
-#ifndef HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED
-#define libusb_handle_events_timeout_completed(ctx, tv, c) \
- libusb_handle_events_timeout(ctx, tv)
-#endif
-
/* two raised to the power of n */
#define TWO_POW(n) ((double)(1ULL<<(n)))
@@ -103,6 +97,7 @@ struct rtlsdr_dev {
void *cb_ctx;
enum rtlsdr_async_status async_status;
int async_cancel;
+ int use_zerocopy;
/* rtl demod context */
uint32_t rate; /* Hz */
uint32_t rtl_xtal; /* Hz */
@@ -329,6 +324,7 @@ static rtlsdr_dongle_t known_devices[] = {
{ 0x0ccd, 0x00e0, "Terratec NOXON DAB/DAB+ USB dongle (rev 2)" },
{ 0x1554, 0x5020, "PixelView PV-DT235U(RN)" },
{ 0x15f4, 0x0131, "Astrometa DVB-T/DVB-T2" },
+ { 0x15f4, 0x0133, "HanfTek DAB+FM+DVB-T" },
{ 0x185b, 0x0620, "Compro Videomate U620F"},
{ 0x185b, 0x0650, "Compro Videomate U650F"},
{ 0x185b, 0x0680, "Compro Videomate U680F"},
@@ -569,7 +565,7 @@ void rtlsdr_set_gpio_output(rtlsdr_dev_t *dev, uint8_t gpio)
gpio = 1 << gpio;
r = rtlsdr_read_reg(dev, SYSB, GPD, 1);
- rtlsdr_write_reg(dev, SYSB, GPO, r & ~gpio, 1);
+ rtlsdr_write_reg(dev, SYSB, GPD, r & ~gpio, 1);
r = rtlsdr_read_reg(dev, SYSB, GPOE, 1);
rtlsdr_write_reg(dev, SYSB, GPOE, r | gpio, 1);
}
@@ -1564,11 +1560,11 @@ int rtlsdr_open(rtlsdr_dev_t **out_dev, uint32_t index)
}
/* initialise GPIOs */
- rtlsdr_set_gpio_output(dev, 5);
+ rtlsdr_set_gpio_output(dev, 4);
/* reset tuner before probing */
- rtlsdr_set_gpio_bit(dev, 5, 1);
- rtlsdr_set_gpio_bit(dev, 5, 0);
+ rtlsdr_set_gpio_bit(dev, 4, 1);
+ rtlsdr_set_gpio_bit(dev, 4, 0);
reg = rtlsdr_i2c_read_reg(dev, FC2580_I2C_ADDR, FC2580_CHECK_ADDR);
if ((reg & 0x7f) == FC2580_CHECK_VAL) {
@@ -1593,6 +1589,7 @@ found:
switch (dev->tuner_type) {
case RTLSDR_TUNER_R828D:
dev->tun_xtal = R828D_XTAL_FREQ;
+ /* fall-through */
case RTLSDR_TUNER_R820T:
/* disable Zero-IF mode */
rtlsdr_demod_write_reg(dev, 1, 0xb1, 0x1a, 1);
@@ -1625,6 +1622,9 @@ found:
return 0;
err:
if (dev) {
+ if (dev->devh)
+ libusb_close(dev->devh);
+
if (dev->ctx)
libusb_exit(dev->ctx);
@@ -1739,12 +1739,64 @@ static int _rtlsdr_alloc_async_buffers(rtlsdr_dev_t *dev)
dev->xfer[i] = libusb_alloc_transfer(0);
}
- if (!dev->xfer_buf) {
- dev->xfer_buf = malloc(dev->xfer_buf_num *
- sizeof(unsigned char *));
+ if (dev->xfer_buf)
+ return -2;
- for(i = 0; i < dev->xfer_buf_num; ++i)
+ dev->xfer_buf = malloc(dev->xfer_buf_num * sizeof(unsigned char *));
+ memset(dev->xfer_buf, 0, dev->xfer_buf_num * sizeof(unsigned char *));
+
+#if defined(ENABLE_ZEROCOPY) && defined (__linux__) && LIBUSB_API_VERSION >= 0x01000105
+ fprintf(stderr, "Allocating %d zero-copy buffers\n", dev->xfer_buf_num);
+
+ dev->use_zerocopy = 1;
+ for (i = 0; i < dev->xfer_buf_num; ++i) {
+ dev->xfer_buf[i] = libusb_dev_mem_alloc(dev->devh, dev->xfer_buf_len);
+
+ if (dev->xfer_buf[i]) {
+ /* Check if Kernel usbfs mmap() bug is present: if the
+ * mapping is correct, the buffers point to memory that
+ * was memset to 0 by the Kernel, otherwise, they point
+ * to random memory. We check if the buffers are zeroed
+ * and otherwise fall back to buffers in userspace.
+ */
+ if (dev->xfer_buf[i][0] || memcmp(dev->xfer_buf[i],
+ dev->xfer_buf[i] + 1,
+ dev->xfer_buf_len - 1)) {
+ fprintf(stderr, "Detected Kernel usbfs mmap() "
+ "bug, falling back to buffers "
+ "in userspace\n");
+ dev->use_zerocopy = 0;
+ break;
+ }
+ } else {
+ fprintf(stderr, "Failed to allocate zero-copy "
+ "buffer for transfer %d\nFalling "
+ "back to buffers in userspace\n", i);
+ dev->use_zerocopy = 0;
+ break;
+ }
+ }
+
+ /* zero-copy buffer allocation failed (partially or completely)
+ * we need to free the buffers again if already allocated */
+ if (!dev->use_zerocopy) {
+ for (i = 0; i < dev->xfer_buf_num; ++i) {
+ if (dev->xfer_buf[i])
+ libusb_dev_mem_free(dev->devh,
+ dev->xfer_buf[i],
+ dev->xfer_buf_len);
+ }
+ }
+#endif
+
+ /* no zero-copy available, allocate buffers in userspace */
+ if (!dev->use_zerocopy) {
+ for (i = 0; i < dev->xfer_buf_num; ++i) {
dev->xfer_buf[i] = malloc(dev->xfer_buf_len);
+
+ if (!dev->xfer_buf[i])
+ return -ENOMEM;
+ }
}
return 0;
@@ -1769,9 +1821,18 @@ static int _rtlsdr_free_async_buffers(rtlsdr_dev_t *dev)
}
if (dev->xfer_buf) {
- for(i = 0; i < dev->xfer_buf_num; ++i) {
- if (dev->xfer_buf[i])
- free(dev->xfer_buf[i]);
+ for (i = 0; i < dev->xfer_buf_num; ++i) {
+ if (dev->xfer_buf[i]) {
+ if (dev->use_zerocopy) {
+#if defined (__linux__) && LIBUSB_API_VERSION >= 0x01000105
+ libusb_dev_mem_free(dev->devh,
+ dev->xfer_buf[i],
+ dev->xfer_buf_len);
+#endif
+ } else {
+ free(dev->xfer_buf[i]);
+ }
+ }
}
free(dev->xfer_buf);
@@ -1826,7 +1887,12 @@ int rtlsdr_read_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx,
r = libusb_submit_transfer(dev->xfer[i]);
if (r < 0) {
- fprintf(stderr, "Failed to submit transfer %i!\n", i);
+ fprintf(stderr, "Failed to submit transfer %i\n"
+ "Please increase your allowed "
+ "usbfs buffer size with the "
+ "following command:\n"
+ "echo 0 > /sys/module/usbcore"
+ "/parameters/usbfs_memory_mb\n", i);
dev->async_status = RTLSDR_CANCELING;
break;
}
@@ -1858,6 +1924,9 @@ int rtlsdr_read_async(rtlsdr_dev_t *dev, rtlsdr_read_async_cb_t cb, void *ctx,
/* handle events after canceling
* to allow transfer status to
* propagate */
+#ifdef _WIN32
+ Sleep(1);
+#endif
libusb_handle_events_timeout_completed(dev->ctx,
&zerotv, NULL);
if (r < 0)
@@ -1936,3 +2005,19 @@ int rtlsdr_i2c_read_fn(void *dev, uint8_t addr, uint8_t *buf, int len)
return -1;
}
+
+int rtlsdr_set_bias_tee_gpio(rtlsdr_dev_t *dev, int gpio, int on)
+{
+ if (!dev)
+ return -1;
+
+ rtlsdr_set_gpio_output(dev, gpio);
+ rtlsdr_set_gpio_bit(dev, gpio, on);
+
+ return 0;
+}
+
+int rtlsdr_set_bias_tee(rtlsdr_dev_t *dev, int on)
+{
+ return rtlsdr_set_bias_tee_gpio(dev, 0, on);
+}
diff --git a/src/tuner_fc0013.c b/src/tuner_fc0013.c
index 78b696e..5984dfb 100644
--- a/src/tuner_fc0013.c
+++ b/src/tuner_fc0013.c
@@ -248,11 +248,11 @@ int fc0013_set_params(void *dev, uint32_t freq, uint32_t bandwidth)
if (ret)
goto exit;
- /* disable UHF & enable GPS */
+ /* enable UHF & disable GPS */
ret = fc0013_readreg(dev, 0x14, &tmp);
if (ret)
goto exit;
- ret = fc0013_writereg(dev, 0x14, (tmp & 0x1f) | 0x20);
+ ret = fc0013_writereg(dev, 0x14, (tmp & 0x1f) | 0x40);
if (ret)
goto exit;
}
diff --git a/src/tuner_r82xx.c b/src/tuner_r82xx.c
index f620238..997abd7 100644
--- a/src/tuner_r82xx.c
+++ b/src/tuner_r82xx.c
@@ -330,8 +330,14 @@ static int r82xx_read(struct r82xx_priv *priv, uint8_t reg, uint8_t *val, int le
priv->buf[0] = reg;
rc = rtlsdr_i2c_write_fn(priv->rtl_dev, priv->cfg->i2c_addr, priv->buf, 1);
- if (rc < 1)
- return rc;
+
+ if (rc != 1) {
+ fprintf(stderr, "%s: i2c wr failed=%d reg=%02x len=%d\n",
+ __FUNCTION__, rc, reg, 1);
+ if (rc < 0)
+ return rc;
+ return -1;
+ }
rc = rtlsdr_i2c_read_fn(priv->rtl_dev, priv->cfg->i2c_addr, p, len);
@@ -770,78 +776,18 @@ static int r82xx_set_tv_standard(struct r82xx_priv *priv,
uint8_t lt_att, flt_ext_widest, polyfil_cur;
int need_calibration;
- if (delsys == SYS_ISDBT) {
- if_khz = 4063;
- filt_cal_lo = 59000;
- filt_gain = 0x10; /* +3db, 6mhz on */
- img_r = 0x00; /* image negative */
- filt_q = 0x10; /* r10[4]:low q(1'b1) */
- hp_cor = 0x6a; /* 1.7m disable, +2cap, 1.25mhz */
- ext_enable = 0x40; /* r30[6], ext enable; r30[5]:0 ext at lna max */
- loop_through = 0x00; /* r5[7], lt on */
- lt_att = 0x00; /* r31[7], lt att enable */
- flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
- polyfil_cur = 0x60; /* r25[6:5]:min */
- } else {
- if (bw <= 6) {
- if_khz = 3570;
- filt_cal_lo = 56000; /* 52000->56000 */
- filt_gain = 0x10; /* +3db, 6mhz on */
- img_r = 0x00; /* image negative */
- filt_q = 0x10; /* r10[4]:low q(1'b1) */
- hp_cor = 0x6b; /* 1.7m disable, +2cap, 1.0mhz */
- ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
- loop_through = 0x00; /* r5[7], lt on */
- lt_att = 0x00; /* r31[7], lt att enable */
- flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
- polyfil_cur = 0x60; /* r25[6:5]:min */
- } else if (bw == 7) {
-#if 0
- /*
- * There are two 7 MHz tables defined on the original
- * driver, but just the second one seems to be visible
- * by rtl2832. Keep this one here commented, as it
- * might be needed in the future
- */
-
- if_khz = 4070;
- filt_cal_lo = 60000;
- filt_gain = 0x10; /* +3db, 6mhz on */
- img_r = 0x00; /* image negative */
- filt_q = 0x10; /* r10[4]:low q(1'b1) */
- hp_cor = 0x2b; /* 1.7m disable, +1cap, 1.0mhz */
- ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
- loop_through = 0x00; /* r5[7], lt on */
- lt_att = 0x00; /* r31[7], lt att enable */
- flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
- polyfil_cur = 0x60; /* r25[6:5]:min */
-#endif
- /* 7 MHz, second table */
- if_khz = 4570;
- filt_cal_lo = 63000;
- filt_gain = 0x10; /* +3db, 6mhz on */
- img_r = 0x00; /* image negative */
- filt_q = 0x10; /* r10[4]:low q(1'b1) */
- hp_cor = 0x2a; /* 1.7m disable, +1cap, 1.25mhz */
- ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
- loop_through = 0x00; /* r5[7], lt on */
- lt_att = 0x00; /* r31[7], lt att enable */
- flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
- polyfil_cur = 0x60; /* r25[6:5]:min */
- } else {
- if_khz = 4570;
- filt_cal_lo = 68500;
- filt_gain = 0x10; /* +3db, 6mhz on */
- img_r = 0x00; /* image negative */
- filt_q = 0x10; /* r10[4]:low q(1'b1) */
- hp_cor = 0x0b; /* 1.7m disable, +0cap, 1.0mhz */
- ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
- loop_through = 0x00; /* r5[7], lt on */
- lt_att = 0x00; /* r31[7], lt att enable */
- flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
- polyfil_cur = 0x60; /* r25[6:5]:min */
- }
- }
+ /* BW < 6 MHz */
+ if_khz = 3570;
+ filt_cal_lo = 56000; /* 52000->56000 */
+ filt_gain = 0x10; /* +3db, 6mhz on */
+ img_r = 0x00; /* image negative */
+ filt_q = 0x10; /* r10[4]:low q(1'b1) */
+ hp_cor = 0x6b; /* 1.7m disable, +2cap, 1.0mhz */
+ ext_enable = 0x60; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
+ loop_through = 0x01; /* r5[7], lt off */
+ lt_att = 0x00; /* r31[7], lt att enable */
+ flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
+ polyfil_cur = 0x60; /* r25[6:5]:min */
/* Initialize the shadow registers */
memcpy(priv->regs, r82xx_init_array, sizeof(r82xx_init_array));
@@ -1196,7 +1142,7 @@ int r82xx_standby(struct r82xx_priv *priv)
rc = r82xx_write_reg(priv, 0x06, 0xb1);
if (rc < 0)
return rc;
- rc = r82xx_write_reg(priv, 0x05, 0x03);
+ rc = r82xx_write_reg(priv, 0x05, 0xa0);
if (rc < 0)
return rc;
rc = r82xx_write_reg(priv, 0x07, 0x3a);