Exemplo n.º 1
0
int __bladerf_rcv_one_word(bladerf_device_t *dev, int cmd, void __user *arg) {
    unsigned int buf;
    int retval = -EINVAL;

    if (!arg) {
        retval = -EFAULT;
        goto err_out;
    }

    retval = __bladerf_rcv_cmd(dev, cmd, &buf, sizeof(buf));

    if (retval >= 0) {
        buf = le32_to_cpu(buf);
        if (copy_to_user(arg, &buf, sizeof(buf))) {
            retval = -EFAULT;
        } else {
            retval = 0;
        }
    }

    if (retval >= 0) {
        retval = 0;
    }

err_out:
    return retval;
}
Exemplo n.º 2
0
long bladerf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    bladerf_device_t *dev;
    void __user *data;
    struct bladeRF_version ver;
    int ret;
    int retval = -EINVAL;
    int sz, nread, nwrite;
    struct uart_cmd spi_reg;
    int sectors_to_wipe, sector_idx;
    int pages_to_write, page_idx;
    int pages_to_read;
    int check_idx;
    int count, tries;
    int targetdev;

    /* FIXME this large buffer should be kmalloc'd and kept with the dev, no? */
    unsigned char buf[1024];
    struct bladeRF_firmware brf_fw;
    struct bladeRF_sector brf_sector;
    unsigned char *fw_buf;

    dev = file->private_data;
    data = (void __user *)arg;


    switch (cmd) {
        case BLADE_QUERY_VERSION:
            retval = __bladerf_rcv_cmd(dev, BLADE_USB_CMD_QUERY_VERSION, &ver, sizeof(ver));
            if (retval >= 0) {
                ver.major = le16_to_cpu(ver.major);
                ver.minor = le16_to_cpu(ver.minor);
                if (copy_to_user(data, &ver, sizeof(struct bladeRF_version))) {
                    retval = -EFAULT;
                } else {
                    retval = 0;
                }
            }
            break;

        case BLADE_QUERY_FPGA_STATUS:
            retval = __bladerf_rcv_one_word(dev, BLADE_USB_CMD_QUERY_FPGA_STATUS, data);
            break;

        case BLADE_BEGIN_PROG:
            if (dev->intnum != 0) {
                ret = usb_set_interface(dev->udev, 0,0);
                dev->intnum = 0;
            }

            retval = __bladerf_rcv_one_word(dev, BLADE_USB_CMD_BEGIN_PROG, data);
            break;

        case BLADE_END_PROG:
            // TODO: send another 2 DCLK cycles to ensure compliance with C4's boot procedure
            retval = __bladerf_rcv_one_word(dev, BLADE_USB_CMD_QUERY_FPGA_STATUS, data);

            if (!retval) {
                ret = usb_set_interface(dev->udev, 0,1);
                dev->intnum = 1;
            }
            break;

        case BLADE_CAL:
            if (dev->intnum != 2) {
                retval = usb_set_interface(dev->udev, 0,2);

                if (retval)
                    break;

                dev->intnum = 2;
            }
            if (copy_from_user(&brf_fw, data, sizeof(struct bladeRF_firmware))) {
                return -EFAULT;
            }

            fw_buf = kzalloc(256, GFP_KERNEL);
            if (!fw_buf)
                return -EINVAL;

            memset(fw_buf, 0xff, 256);

            if (copy_from_user(fw_buf, brf_fw.ptr, brf_fw.len)) {
                retval = -EFAULT;
                break;
            }

            retval = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                    BLADE_USB_CMD_FLASH_ERASE, BLADE_USB_TYPE_IN, 0x0000, 3,
                    &ret, 4, BLADE_USB_TIMEOUT_MS * 100);

            if (!retval) {
                dev_err(&dev->interface->dev, "Could not erase NAND cal sector 3.\n");
                break;
            }

            retval = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                    BLADE_USB_CMD_FLASH_WRITE, BLADE_USB_TYPE_OUT, 0x0000, 768,
                    fw_buf, 256, BLADE_USB_TIMEOUT_MS);

            if (!retval) {
                dev_err(&dev->interface->dev, "Could not write NAND cal sector 768.\n");
                break;
            }

            memset(buf, 0, 256);

            retval = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                    BLADE_USB_CMD_FLASH_READ, BLADE_USB_TYPE_IN, 0x0000, 768,
                    buf, 256, BLADE_USB_TIMEOUT_MS);

            if (!retval) {
                dev_err(&dev->interface->dev, "Could not read NAND cal sector 768.\n");
                break;
            }

            retval = memcmp(fw_buf, buf, 256);
            break;

        case BLADE_FLASH_ERASE:
                retval = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                        BLADE_USB_CMD_FLASH_ERASE, BLADE_USB_TYPE_IN, 0x0000, arg,
                        &ret, 4, BLADE_USB_TIMEOUT_MS * 100);

                if (!retval) {
                    dev_err(&dev->interface->dev, "Could not read NAND cal sector 768.\n");
                    break;
                }

                retval = !ret;
        break;

        case BLADE_OTP:
            if (dev->intnum != 2) {
                retval = usb_set_interface(dev->udev, 0,2);

                if (retval)
                    break;

                dev->intnum = 2;
            }

            if (copy_from_user(&brf_fw, data, sizeof(struct bladeRF_firmware))) {
                return -EFAULT;
            }

            fw_buf = kzalloc(256, GFP_KERNEL);
            if (!fw_buf)
                return -EINVAL;
            memset(fw_buf, 0xff, 256);

            if (copy_from_user(fw_buf, brf_fw.ptr, brf_fw.len)) {
                retval = -EFAULT;
                kfree(fw_buf);
                break;
            }

            memcpy(buf, fw_buf, brf_fw.len);

            retval = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                    BLADE_USB_CMD_WRITE_OTP, BLADE_USB_TYPE_OUT, 0x0000, 0,
                    fw_buf, 256, BLADE_USB_TIMEOUT_MS);

            if (!retval) {
                dev_err(&dev->interface->dev, "Could not write OTP.\n");
                break;
            }

            memset(buf, 0, 256);

            retval = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                    BLADE_USB_CMD_READ_OTP, BLADE_USB_TYPE_IN, 0x0000, 0,
                    buf, 256, BLADE_USB_TIMEOUT_MS);

            if (!retval) {
                dev_err(&dev->interface->dev, "Could not read OTP.\n");
                break;
            }

            retval = memcmp(fw_buf, buf, 256);
            break;

        case BLADE_OTP_READ:
        case BLADE_FLASH_READ:
        case BLADE_FLASH_WRITE:
            if (dev->intnum != 2) {
                retval = usb_set_interface(dev->udev, 0,2);

                if (retval)
                    break;

                dev->intnum = 2;
            }

            if (copy_from_user(&brf_sector, data, sizeof(struct bladeRF_sector))) {
                return -EFAULT;
            }

            if (cmd == BLADE_OTP_READ) {
                if (brf_sector.idx != 0 || brf_sector.len != 0x100)
                    dev_err(&dev->interface->dev, "Invalid OTP settings, expecting idx=0, len=256\n");
            }


            sz = 0;
            if (dev->udev->speed == USB_SPEED_HIGH) {
                sz = 64;
            } else if (dev->udev->speed == USB_SPEED_SUPER) {
                sz = 256;
            }

            count = brf_sector.len + (sz - (brf_sector.len % sz));
            fw_buf = kzalloc(count, GFP_KERNEL);

            if (!fw_buf)
                return -EFAULT;

            memset(fw_buf, 0xff, count);

            if (cmd == BLADE_FLASH_READ || cmd == BLADE_OTP_READ) {
                pages_to_read = (brf_sector.len + 255) / 0x100;
                nread = 0;
                for (page_idx = 0; page_idx < pages_to_read; page_idx++) {
                    do {
                        retval = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                                (cmd == BLADE_FLASH_READ) ? BLADE_USB_CMD_FLASH_READ : BLADE_USB_CMD_READ_OTP,
                                BLADE_USB_TYPE_IN, 0x0000, brf_sector.idx + page_idx,
                                &fw_buf[nread], sz, BLADE_USB_TIMEOUT_MS);
                        printk("%d read %d bytes %x %x %x %x\n", retval, sz, fw_buf[nread], fw_buf[nread+1], fw_buf[nread+2], fw_buf[nread+3]);
                        nread += sz;
                        if (retval != sz) break;
                    } while (nread != 256);
                    if (retval != sz) break;
                }

                if (!retval) {
                    dev_err(&dev->interface->dev, "Could not read NAND cal page idx %d.\n", page_idx);
                    break;
                }
                if (copy_to_user((void __user *)brf_sector.ptr, fw_buf, brf_sector.len)) {
                    retval = -EFAULT;
                    break;
                }
            } else if (cmd == BLADE_FLASH_WRITE) {
                if (copy_from_user(fw_buf, brf_sector.ptr, brf_sector.len)) {
                    retval = -EFAULT;
                    break;
                }

                pages_to_write = (brf_sector.len + 255) / 0x100;
                nwrite = 0;
                for (page_idx = 0; page_idx < pages_to_write; page_idx++) {
                    do {
                        retval = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                                BLADE_USB_CMD_FLASH_WRITE, BLADE_USB_TYPE_OUT, 0x0000, brf_sector.idx + page_idx,
                                &fw_buf[page_idx * 256 + nwrite], sz, BLADE_USB_TIMEOUT_MS);
                        nwrite += sz;
                        if (retval != sz) break;
                    } while (nwrite != 256);
                    if (retval != sz) break;
                }

                if (!retval) {
                    dev_err(&dev->interface->dev, "Could not write NAND cal page idx %d.\n", page_idx);
                    break;
                }
            }

            break;

        case BLADE_UPGRADE_FW:

            if (dev->intnum != 2) {
                retval = usb_set_interface(dev->udev, 0,2);

                if (retval)
                    break;

                dev->intnum = 2;
            }

            if (copy_from_user(&brf_fw, data, sizeof(struct bladeRF_firmware))) {
                return -EFAULT;
            }

            brf_fw.len = ((brf_fw.len + 255) / 256) * 256;

            fw_buf = kzalloc(brf_fw.len, GFP_KERNEL);
            if (!fw_buf)
                goto leave_fw;

            if (copy_from_user(fw_buf, brf_fw.ptr, brf_fw.len)) {
                retval = -EFAULT;
                goto leave_fw;
            }

            retval = -ENODEV;

            sectors_to_wipe = (brf_fw.len + 0xffff) / 0x10000;
            printk("Going to wipe %d sectors\n", sectors_to_wipe);
            for (sector_idx = 0; sector_idx < sectors_to_wipe; sector_idx++) {
                printk("Erasing sector %d... ", sector_idx);
                retval = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                        BLADE_USB_CMD_FLASH_ERASE, BLADE_USB_TYPE_IN, 0x0000, sector_idx,
                        &ret, 4, BLADE_USB_TIMEOUT_MS * 100);
                printk("- erased\n");

                if (retval != 4) {
                    goto leave_fw;
                }
                ret = le32_to_cpu(ret);
                if (ret != 1) {
                    printk("Unable to erase previous sector, quitting\n");
                    goto leave_fw;
                }
            }

            sz = 0;
            if (dev->udev->speed == USB_SPEED_HIGH) {
                sz = 64;
            } else if (dev->udev->speed == USB_SPEED_SUPER) {
                sz = 256;
            }

            pages_to_write = (brf_fw.len + 255) / 0x100;
            for (page_idx = pages_to_write - 1; page_idx >= 0; page_idx--) {
                nwrite = 0;
                do {
                    retval = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                            BLADE_USB_CMD_FLASH_WRITE, BLADE_USB_TYPE_OUT, 0x0000, page_idx,
                            &fw_buf[page_idx * 256 + nwrite], sz, BLADE_USB_TIMEOUT_MS);
                    nwrite += sz;
                } while (nwrite != 256);
            }

            pages_to_read = (brf_fw.len + 255) / 0x100;

            for (page_idx = 0; page_idx < pages_to_read; page_idx++) {
                nread = 0;
                do {
                    retval = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                            BLADE_USB_CMD_FLASH_READ, BLADE_USB_TYPE_IN, 0x0000, page_idx,
                            &buf[nread], sz, BLADE_USB_TIMEOUT_MS);
                    nread += sz;
                } while (nread != 256);

                for (check_idx = 0; check_idx < 256; check_idx++) {
                    if (buf[check_idx] != fw_buf[page_idx * 256 + check_idx]) {
                        printk("ERROR: bladeRF firmware verification detected a mismatch at byte offset 0x%.8x\n", page_idx * 256 + check_idx);
                        printk("ERROR: expected byte 0x%.2X, got 0x%.2X\n", fw_buf[page_idx * 256 + check_idx], buf[check_idx]);
                        retval = -EINVAL;
                        goto leave_fw;
                    }
                }
            }
            retval = 0;
            printk("SUCCESSFULLY VERIFIED\n");

leave_fw:
            kfree(fw_buf);
            break;

        case BLADE_DEVICE_RESET:
            ret = 1;
            retval = __bladerf_snd_cmd(dev, BLADE_USB_CMD_RESET, &ret, sizeof(ret));
            break;


        case BLADE_CHECK_PROG:
            retval = 0;
            printk("ok %d\n", dev->intnum);
            if (dev->intnum == 0) {
                retval = __bladerf_rcv_cmd(dev, BLADE_USB_CMD_QUERY_FPGA_STATUS, &ret, sizeof(ret));
                printk("retval =%d     ret=%d\n", retval, ret);
                if (retval >= 0 && ret) {
                    retval = 0;
                    ret = usb_set_interface(dev->udev, 0,1);
                    dev->intnum = 1;

                    if (copy_to_user((void __user *)arg, &ret, sizeof(ret))){
                        retval = -EFAULT;
                    } else {
                        retval = 0;
                    }
                }
            }
            break;

        case BLADE_RF_RX:
            if (dev->intnum != 1) {
                dev_err(&dev->interface->dev, "Cannot enable RX from config mode\n");
                retval = -1;
                break;
            }

            printk("RF_RX!\n");
            retval = __bladerf_snd_one_word(dev, BLADE_USB_CMD_RF_RX, data);
            break;

        case BLADE_RF_TX:
            if (dev->intnum != 1) {
                dev_err(&dev->interface->dev, "Cannot enable TX from config mode\n");
                retval = -1;
                break;
            }

            printk("RF_TX!\n");
            retval = __bladerf_snd_one_word(dev, BLADE_USB_CMD_RF_TX, data);
            break;

        case BLADE_LMS_WRITE:
        case BLADE_LMS_READ:
        case BLADE_SI5338_WRITE:
        case BLADE_SI5338_READ:
        case BLADE_GPIO_WRITE:
        case BLADE_GPIO_READ:
        case BLADE_VCTCXO_WRITE:

            if (copy_from_user(&spi_reg, (void __user *)arg, sizeof(struct uart_cmd))) {
                retval = -EFAULT;
                break;
            }

            nread = count = 16;
            memset(buf, 0, 20);
            buf[0] = 'N';

            targetdev = UART_PKT_DEV_SI5338;
            if (cmd == BLADE_GPIO_WRITE || cmd == BLADE_GPIO_READ)
                targetdev = UART_PKT_DEV_GPIO;
            if (cmd == BLADE_LMS_WRITE || cmd == BLADE_LMS_READ)
                targetdev = UART_PKT_DEV_LMS;
            if (cmd == BLADE_VCTCXO_WRITE)
                targetdev = UART_PKT_DEV_VCTCXO;

            if (cmd == BLADE_LMS_WRITE || cmd == BLADE_GPIO_WRITE || cmd == BLADE_SI5338_WRITE || cmd == BLADE_VCTCXO_WRITE) {
                buf[1] = UART_PKT_MODE_DIR_WRITE | targetdev | 0x01;
                buf[2] = spi_reg.addr;
                buf[3] = spi_reg.data;
            } else if (cmd == BLADE_LMS_READ || cmd == BLADE_GPIO_READ || cmd == BLADE_SI5338_READ) {
                buf[1] = UART_PKT_MODE_DIR_READ | targetdev | 0x01;
                buf[2] = spi_reg.addr;
                buf[3] = 0xff;
            }

            retval = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), buf, count, &nread, BLADE_USB_TIMEOUT_MS);
            if (!retval) {
                memset(buf, 0, 20);

                tries = 3;
                do {
                    retval = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, 0x82), buf, count, &nread, BLADE_USB_TIMEOUT_MS);
                } while(retval == -ETIMEDOUT && tries--);

                if (!retval) {
                    spi_reg.addr = buf[2];
                    spi_reg.data = buf[3];
                }

                if (copy_to_user((void __user *)arg, &spi_reg, sizeof(struct uart_cmd))) {
                    retval = -EFAULT;
                } else {
                    retval = 0;
                }
            }
            break;

        case BLADE_GET_SPEED:
            ret = dev->udev->speed == USB_SPEED_SUPER;
            if (copy_to_user((void __user *)arg, &ret, sizeof(ret))) {
                retval = -EFAULT;
            } else {
                retval = 0;
            }
            break;

        case BLADE_GET_ADDR:
            ret = dev->udev->devnum;
            if (copy_to_user((void __user *)arg, &ret, sizeof(ret))) {
                retval = -EFAULT;
            } else {
                retval = 0;
            }
            break;

        case BLADE_GET_BUS:
            ret = dev->udev->bus->busnum;
            if (copy_to_user((void __user *)arg, &ret, sizeof(ret))) {
                retval = -EFAULT;
            } else {
                retval = 0;
            }
            break;

    }

    return retval;
}
Exemplo n.º 3
0
long bladerf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    bladerf_device_t *dev;
    void __user *data;
    struct bladeRF_version ver;
    int ret;
    int retval = -EINVAL;
    int sz, nread, nwrite;
    int sectors_to_wipe, sector_idx;
    int pages_to_write, page_idx;
    int pages_to_read;
    int check_idx, check_error;

    unsigned char buf[1024];
    struct bladeRF_firmware brf_fw;
    unsigned char *fw_buf;

    dev = file->private_data;
    data = (void __user *)arg;


    switch (cmd) {
        case BLADE_QUERY_VERSION:
            retval = __bladerf_rcv_cmd(dev, BLADE_USB_CMD_QUERY_VERSION, &ver, sizeof(ver));
            if (retval >= 0) {
                ver.major = le16_to_cpu(ver.major);
                ver.minor = le16_to_cpu(ver.minor);
                retval = copy_to_user(data, &ver, sizeof(struct bladeRF_version));
            }
            break;

        case BLADE_QUERY_FPGA_STATUS:
            retval = __bladerf_rcv_one_word(dev, BLADE_USB_CMD_QUERY_FPGA_STATUS, data);
            break;

        case BLADE_BEGIN_PROG:
            if (dev->intnum != 0) {
                ret = usb_set_interface(dev->udev, 0,0);
                dev->intnum = 0;
            }

            retval = __bladerf_rcv_one_word(dev, BLADE_USB_CMD_BEGIN_PROG, data);
            break;

        case BLADE_END_PROG:
            // TODO: send another 2 DCLK cycles to ensure compliance with C4's boot procedure
            retval = __bladerf_rcv_one_word(dev, BLADE_USB_CMD_QUERY_FPGA_STATUS, data);

            if (!retval) {
                ret = usb_set_interface(dev->udev, 1,0);
                dev->intnum = 1;
            }
            break;

        case BLADE_UPGRADE_FW:

            if (dev->intnum != 2) {
                retval = usb_set_interface(dev->udev, 2,0);

                if (retval)
                    break;

                dev->intnum = 2;
            }

            if (copy_from_user(&brf_fw, data, sizeof(struct bladeRF_firmware))) {
                return -EFAULT;
            }

            brf_fw.len = ((brf_fw.len + 255) / 256) * 256;

            fw_buf = kzalloc(brf_fw.len, GFP_KERNEL);
            if (!fw_buf)
                goto leave_fw;

            if (copy_from_user(fw_buf, brf_fw.ptr, brf_fw.len)) {
                retval = -EFAULT;
                goto leave_fw;
            }

            retval = -ENODEV;

            sectors_to_wipe = (brf_fw.len + 0xffff) / 0x10000;
            printk("Going to wipe %d sectors\n", sectors_to_wipe);
            for (sector_idx = 0; sector_idx < sectors_to_wipe; sector_idx++) {
                printk("Erasing sector %d... ", sector_idx);
                retval = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                        BLADE_USB_CMD_FLASH_ERASE, BLADE_USB_TYPE_IN, 0x0000, sector_idx,
                        &ret, 4, BLADE_USB_TIMEOUT_MS * 100);
                printk("- erased\n");

                if (retval != 4) {
                    goto leave_fw;
                }
                ret = le32_to_cpu(ret);
                if (ret != 1) {
                    printk("Unable to erase previous sector, quitting\n");
                    goto leave_fw;
                }
            }

            if (dev->udev->speed == USB_SPEED_HIGH) {
                sz = 64;
            } else if (dev->udev->speed == USB_SPEED_SUPER) {
                sz = 256;
            }

            pages_to_write = (brf_fw.len + 255) / 0x100;
            for (page_idx = pages_to_write - 1; page_idx >= 0; page_idx--) {
                nwrite = 0;
                do {
                    retval = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                            BLADE_USB_CMD_FLASH_WRITE, BLADE_USB_TYPE_OUT, 0x0000, page_idx,
                            &fw_buf[page_idx * 256 + nwrite], sz, BLADE_USB_TIMEOUT_MS);
                    nwrite += sz;
                } while (nwrite != 256);
            }

            pages_to_read = (brf_fw.len + 255) / 0x100;

            check_error = 0;
            for (page_idx = 0; page_idx < pages_to_read; page_idx++) {
                nread = 0;
                do {
                    retval = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                            BLADE_USB_CMD_FLASH_READ, BLADE_USB_TYPE_IN, 0x0000, page_idx,
                            &buf[nread], sz, BLADE_USB_TIMEOUT_MS);
                    nread += sz;
                } while (nread != 256);

                for (check_idx = 0; check_idx < 256; check_idx++) {
                    if (buf[check_idx] != fw_buf[page_idx * 256 + check_idx]) {
                        printk("ERROR: bladeRF firmware verification detected a mismatch at byte offset 0x%.8x\n", page_idx * 256 + check_idx);
                        printk("ERROR: expected byte 0x%.2X, got 0x%.2X\n", fw_buf[page_idx * 256 + check_idx], buf[check_idx]);
                        check_error = 1;
                        goto leave_fw;
                    }
                }
            }
            retval = 0;
            printk("SUCCESSFULLY VERIFIED\n");

leave_fw:
            kfree(fw_buf);
            break;

        case BLADE_CHECK_PROG:
            retval = 0;
            printk("ok %d\n", dev->intnum);
            if (dev->intnum == 0) {
                retval = __bladerf_rcv_cmd(dev, BLADE_USB_CMD_QUERY_FPGA_STATUS, &ret, sizeof(ret));
                printk("retval =%d     ret=%d\n", retval, ret);
                if (retval >= 0 && ret) {
                    retval = 0;
                    ret = usb_set_interface(dev->udev, 1,0);
                    dev->intnum = 1;
                    retval = copy_to_user((void __user *)arg, &ret, sizeof(ret));
                    printk("ok changed intf\n");
                }
            }
            break;

        case BLADE_RF_RX:
            if (dev->intnum != 1) {
                dev_err(&dev->interface->dev, "Cannot enable RX from config mode\n");
                retval = -1;
                break;
            }

            printk("RF_RX!\n");
            retval = __bladerf_snd_one_word(dev, BLADE_USB_CMD_RF_RX, data);
            break;

        case BLADE_RF_TX:
            if (dev->intnum != 1) {
                dev_err(&dev->interface->dev, "Cannot enable TX from config mode\n");
                retval = -1;
                break;
            }

            printk("RF_TX!\n");
            retval = __bladerf_snd_one_word(dev, BLADE_USB_CMD_RF_TX, data);
            break;
    }

    return retval;
}