From 79908e1109e6de0e8703629a95041cc504aa2a6d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 3 Jun 2018 16:23:41 +0200 Subject: libusb-1.0.22 deprecated libusb_set_debug() with libusb_set_option() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids the following compiler warnings when using more recent versions of libusb: src/libosmo-fl2k.c:384:2: warning: ‘libusb_set_debug’ is deprecated: Use libusb_set_option instead [-Wdeprecated-declarations] libusb_set_debug(dev->ctx, 3); ^~~~~~~~~~~~~~~~ Details can be found at https://github.com/libusb/libusb/commit/539f22e2fd916558d11ab9a66f10f461c5593168 --- src/libosmo-fl2k.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/libosmo-fl2k.c') diff --git a/src/libosmo-fl2k.c b/src/libosmo-fl2k.c index 0285f9a..9116aff 100644 --- a/src/libosmo-fl2k.c +++ b/src/libosmo-fl2k.c @@ -381,7 +381,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; -- cgit v1.2.3 From 7ae9754ede8806df16977be28a4811fcf5eacdd0 Mon Sep 17 00:00:00 2001 From: Steve Markgraf Date: Sun, 17 Jun 2018 02:38:15 +0200 Subject: fix sleep durations on Windows Signed-off-by: Steve Markgraf --- src/fl2k_file.c | 11 ++++------- src/fl2k_tcp.c | 18 ++++++------------ src/fl2k_test.c | 14 +++++--------- src/libosmo-fl2k.c | 20 +++++++++----------- 4 files changed, 24 insertions(+), 39 deletions(-) (limited to 'src/libosmo-fl2k.c') diff --git a/src/fl2k_file.c b/src/fl2k_file.c index 05db28e..cff5178 100644 --- a/src/fl2k_file.c +++ b/src/fl2k_file.c @@ -28,11 +28,13 @@ #ifndef _WIN32 #include +#define sleep_ms(ms) usleep(ms*1000) #else #include #include #include #include "getopt/getopt.h" +#define sleep_ms(ms) Sleep(ms) #endif #include "osmo-fl2k.h" @@ -191,13 +193,8 @@ int main(int argc, char **argv) SetConsoleCtrlHandler( (PHANDLER_ROUTINE) sighandler, TRUE ); #endif - while (!do_exit) { -#ifndef _WIN32 - usleep(500000); -#else - Sleep(0.5); -#endif - } + while (!do_exit) + sleep_ms(500); fl2k_close(dev); diff --git a/src/fl2k_tcp.c b/src/fl2k_tcp.c index ad0aa18..bd01758 100644 --- a/src/fl2k_tcp.c +++ b/src/fl2k_tcp.c @@ -36,9 +36,12 @@ #include #include /* for TCP_NODELAY */ #include +#define sleep_ms(ms) usleep(ms*1000) #else +#include #include #include "getopt/getopt.h" +#define sleep_ms(ms) Sleep(ms) #endif #include "osmo-fl2k.h" @@ -217,11 +220,7 @@ int main(int argc, char **argv) fprintf(stderr, "Connecting to %s:%d...\n", addr, port); while (connect(sock, (struct sockaddr *)&remote, sizeof(remote)) != 0) { -#ifndef _WIN32 - usleep(500000); -#else - Sleep(0.5); -#endif + sleep_ms(500); if (do_exit) goto out; } @@ -230,13 +229,8 @@ int main(int argc, char **argv) fprintf(stderr, "Connected\n"); connected = 1; - while (!do_exit) { -#ifndef _WIN32 - usleep(500000); -#else - Sleep(0.5); -#endif - } + while (!do_exit) + sleep_ms(500); out: free(txbuf); diff --git a/src/fl2k_test.c b/src/fl2k_test.c index c9a6048..6d82922 100644 --- a/src/fl2k_test.c +++ b/src/fl2k_test.c @@ -41,9 +41,11 @@ #ifndef _WIN32 #include +#define sleep_ms(ms) usleep(ms*1000) #else #include #include "getopt/getopt.h" +#define sleep_ms(ms) Sleep(ms) #endif #include "osmo-fl2k.h" @@ -290,17 +292,11 @@ int main(int argc, char **argv) fprintf(stderr, "Reporting PPM error measurement every %u seconds...\n", ppm_duration); fprintf(stderr, "Press ^C after a few minutes.\n"); - while (!do_exit) { -#ifndef _WIN32 - usleep(500000); -#else - Sleep(0.5); -#endif - } + while (!do_exit) + sleep_ms(500); - if (do_exit) { + if (do_exit) fprintf(stderr, "\nUser cancel, exiting...\n"); - } exit: fl2k_close(dev); diff --git a/src/libosmo-fl2k.c b/src/libosmo-fl2k.c index 9116aff..34b854e 100644 --- a/src/libosmo-fl2k.c +++ b/src/libosmo-fl2k.c @@ -25,15 +25,18 @@ #include #include #include +#include +#include +#include #ifndef _WIN32 #include +#define sleep_ms(ms) usleep(ms*1000) +#else +#include +#define sleep_ms(ms) Sleep(ms) #endif -#include -#include -#include - /* * 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. @@ -476,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); } -- cgit v1.2.3 From 0fb884942679d1246ae41d018764814401fd8c57 Mon Sep 17 00:00:00 2001 From: Steve Markgraf Date: Sun, 17 Jun 2018 03:09:43 +0200 Subject: lib: add I2C support Note that the FL2000 only supports I2C transfers with a fixed length of 4 bytes. Signed-off-by: Steve Markgraf --- include/osmo-fl2k.h | 35 ++++++++++++++++++ src/libosmo-fl2k.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+) (limited to 'src/libosmo-fl2k.c') diff --git a/include/osmo-fl2k.h b/include/osmo-fl2k.h index 8d3cc3b..02ad4ad 100644 --- a/include/osmo-fl2k.h +++ b/include/osmo-fl2k.h @@ -37,6 +37,7 @@ enum fl2k_error { FL2K_ERROR_NO_DEVICE = -2, FL2K_ERROR_NOT_FOUND = -5, FL2K_ERROR_BUSY = -6, + FL2K_ERROR_TIMEOUT = -7, FL2K_ERROR_NO_MEM = -11, }; @@ -121,6 +122,40 @@ FL2K_API int fl2k_start_tx(fl2k_dev_t *dev, fl2k_tx_cb_t cb, */ FL2K_API int fl2k_stop_tx(fl2k_dev_t *dev); +/*! + * Read 4 bytes via the FL2K I2C bus + * + * \param dev the device handle given by fl2k_open() + * \param i2c_addr address of the I2C device + * \param reg_addr start address of the 4 bytes to be read + * \param data pointer to byte array of size 4 + * \return 0 on success + * \note A read operation will look like this on the bus: + * START, I2C_ADDR(W), REG_ADDR, REP_START, I2C_ADDR(R), DATA[0], STOP + * START, I2C_ADDR(W), REG_ADDR+1, REP_START, I2C_ADDR(R), DATA[1], STOP + * START, I2C_ADDR(W), REG_ADDR+2, REP_START, I2C_ADDR(R), DATA[2], STOP + * START, I2C_ADDR(W), REG_ADDR+3, REP_START, I2C_ADDR(R), DATA[3], STOP + */ +FL2K_API int fl2k_i2c_read(fl2k_dev_t *dev, uint8_t i2c_addr, + uint8_t reg_addr, uint8_t *data); + +/*! + * Write 4 bytes via the FL2K I2C bus + * + * \param dev the device handle given by fl2k_open() + * \param i2c_addr address of the I2C device + * \param reg_addr start address of the 4 bytes to be written + * \param data pointer to byte array of size 4 + * \return 0 on success + * \note A write operation will look like this on the bus: + * START, I2C_ADDR(W), REG_ADDR, DATA[0], STOP + * START, I2C_ADDR(W), REG_ADDR+1, DATA[1], STOP + * START, I2C_ADDR(W), REG_ADDR+2, DATA[2], STOP + * START, I2C_ADDR(W), REG_ADDR+3, DATA[3], STOP + */ +FL2K_API int fl2k_i2c_write(fl2k_dev_t *dev, uint8_t i2c_addr, + uint8_t reg_addr, uint8_t *data); + #ifdef __cplusplus } #endif diff --git a/src/libosmo-fl2k.c b/src/libosmo-fl2k.c index 34b854e..1112539 100644 --- a/src/libosmo-fl2k.c +++ b/src/libosmo-fl2k.c @@ -985,3 +985,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, ®); + 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, ®); + 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, ®); + 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, ®); + 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; +} -- cgit v1.2.3 From df33203db5007218384e6724748be52a1d4fdb25 Mon Sep 17 00:00:00 2001 From: Steve Markgraf Date: Sun, 7 Oct 2018 01:44:23 +0200 Subject: lib: Add workaround for Linux usbfs mmap() bug The Linux Kernel has a bug on ARM/ARM64 systems where the USB CMA memory is incorrectly mapped to userspace, breaking zerocopy. When the Kernel allocates the memory, it clears it with memset(). If the mapping worked correctly, we should have zeroed out buffers, if it doesn't, we get random Kernel memory. We now check for this, and fall back to buffers in userspace if that's the case. Signed-off-by: Steve Markgraf --- src/libosmo-fl2k.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'src/libosmo-fl2k.c') diff --git a/src/libosmo-fl2k.c b/src/libosmo-fl2k.c index 1112539..7748238 100644 --- a/src/libosmo-fl2k.c +++ b/src/libosmo-fl2k.c @@ -591,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; } -- cgit v1.2.3