aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSteve Markgraf <steve@steve-m.de>2018-05-01 14:23:37 +0200
committerSteve Markgraf <steve@steve-m.de>2018-05-01 14:23:37 +0200
commita854ae8b48d42e8dad514c75d3a4c6cfb62707da (patch)
tree3b23087e82cd22abfcada4f356c28a7ec3bb9003 /src
parent326b0e3accc21b47e7b4bc118ed4c4b55b914127 (diff)
lib: use USB zero-copy transfers if possible
Decreases CPU load especially for embedded machines. Requires Linux >= 4.6 and libusb >= 1.0.21. If this is not the case or the allocation fails, we will fall back to buffers allocated in userspace. Signed-off-by: Steve Markgraf <steve@steve-m.de>
Diffstat (limited to 'src')
-rw-r--r--src/librtlsdr.c68
1 files changed, 60 insertions, 8 deletions
diff --git a/src/librtlsdr.c b/src/librtlsdr.c
index ae933b0..433ed5b 100644
--- a/src/librtlsdr.c
+++ b/src/librtlsdr.c
@@ -103,6 +103,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 */
@@ -1741,12 +1742,49 @@ 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 (__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]) {
+ 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;
@@ -1771,9 +1809,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);
@@ -1828,7 +1875,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;
}