aboutsummaryrefslogtreecommitdiffstats
path: root/src/libosmo-fl2k.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libosmo-fl2k.c')
-rw-r--r--src/libosmo-fl2k.c144
1 files changed, 131 insertions, 13 deletions
diff --git a/src/libosmo-fl2k.c b/src/libosmo-fl2k.c
index 09380b6..c5959c3 100644
--- a/src/libosmo-fl2k.c
+++ b/src/libosmo-fl2k.c
@@ -25,15 +25,18 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
+#include <math.h>
+#include <libusb.h>
+#include <pthread.h>
#ifndef _WIN32
#include <unistd.h>
+#define sleep_ms(ms) usleep(ms*1000)
+#else
+#include <windows.h>
+#define sleep_ms(ms) Sleep(ms)
#endif
-#include <math.h>
-#include <libusb.h>
-#include <pthread.h>
-
/*
* All libusb callback functions should be marked with the LIBUSB_CALL macro
* to ensure that they are compiled with the same calling convention as libusb.
@@ -381,7 +384,11 @@ int fl2k_open(fl2k_dev_t **out_dev, uint32_t index)
return -1;
}
+#if LIBUSB_API_VERSION >= 0x01000106
+ libusb_set_option(dev->ctx, LIBUSB_OPTION_LOG_LEVEL, 3);
+#else
libusb_set_debug(dev->ctx, 3);
+#endif
dev->dev_lost = 1;
@@ -472,13 +479,8 @@ int fl2k_close(fl2k_dev_t *dev)
if(!dev->dev_lost) {
/* block until all async operations have been completed (if any) */
- while (FL2K_INACTIVE != dev->async_status) {
-#ifdef _WIN32
- Sleep(1);
-#else
- usleep(1000);
-#endif
- }
+ while (FL2K_INACTIVE != dev->async_status)
+ sleep_ms(100);
fl2k_deinit_device(dev);
}
@@ -589,11 +591,26 @@ static int fl2k_alloc_submit_transfers(fl2k_dev_t *dev)
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]) {
+ 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;
}
@@ -1020,3 +1037,104 @@ int fl2k_stop_tx(fl2k_dev_t *dev)
return FL2K_ERROR_BUSY;
}
+
+int fl2k_i2c_read(fl2k_dev_t *dev, uint8_t i2c_addr, uint8_t reg_addr, uint8_t *data)
+{
+ int i, r, timeout = 1;
+ uint32_t reg;
+
+ if (!dev)
+ return FL2K_ERROR_INVALID_PARAM;
+
+ r = fl2k_read_reg(dev, 0x8020, &reg);
+ if (r < 0)
+ return r;
+
+ /* apply mask, clearing bit 30 disables periodic repetition of read */
+ reg &= 0x3ffc0000;
+
+ /* set I2C register and address, select I2C read (bit 7) */
+ reg |= (1 << 28) | (reg_addr << 8) | (1 << 7) | (i2c_addr & 0x7f);
+
+ r = fl2k_write_reg(dev, 0x8020, reg);
+ if (r < 0)
+ return r;
+
+ for (i = 0; i < 10; i++) {
+ sleep_ms(10);
+
+ r = fl2k_read_reg(dev, 0x8020, &reg);
+ if (r < 0)
+ return r;
+
+ /* check if operation completed */
+ if (reg & (1 << 31)) {
+ timeout = 0;
+ break;
+ }
+ }
+
+ if (timeout)
+ return FL2K_ERROR_TIMEOUT;
+
+ /* check if slave responded and all data was read */
+ if (reg & (0x0f << 24))
+ return FL2K_ERROR_NOT_FOUND;
+
+ /* read data from register 0x8024 */
+ return libusb_control_transfer(dev->devh, CTRL_IN, 0x40,
+ 0, 0x8024, data, 4, CTRL_TIMEOUT);
+}
+
+int fl2k_i2c_write(fl2k_dev_t *dev, uint8_t i2c_addr, uint8_t reg_addr, uint8_t *data)
+{
+ int i, r, timeout = 1;
+ uint32_t reg;
+
+ if (!dev)
+ return FL2K_ERROR_INVALID_PARAM;
+
+ /* write data to register 0x8028 */
+ r = libusb_control_transfer(dev->devh, CTRL_OUT, 0x41,
+ 0, 0x8028, data, 4, CTRL_TIMEOUT);
+
+ if (r < 0)
+ return r;
+
+ r = fl2k_read_reg(dev, 0x8020, &reg);
+ if (r < 0)
+ return r;
+
+ /* apply mask, clearing bit 30 disables periodic repetition of read */
+ reg &= 0x3ffc0000;
+
+ /* set I2C register and address */
+ reg |= (1 << 28) | (reg_addr << 8) | (i2c_addr & 0x7f);
+
+ r = fl2k_write_reg(dev, 0x8020, reg);
+ if (r < 0)
+ return r;
+
+ for (i = 0; i < 10; i++) {
+ sleep_ms(10);
+
+ r = fl2k_read_reg(dev, 0x8020, &reg);
+ if (r < 0)
+ return r;
+
+ /* check if operation completed */
+ if (reg & (1 << 31)) {
+ timeout = 0;
+ break;
+ }
+ }
+
+ if (timeout)
+ return FL2K_ERROR_TIMEOUT;
+
+ /* check if slave responded and all data was written */
+ if (reg & (0x0f << 24))
+ return FL2K_ERROR_NOT_FOUND;
+
+ return FL2K_SUCCESS;
+}