コード例 #1
0
ファイル: zd_usb.c プロジェクト: ARMP/android_kernel_lge_x3
static int handle_version_mismatch(struct zd_usb *usb,
	const struct firmware *ub_fw)
{
	struct usb_device *udev = zd_usb_to_usbdev(usb);
	const struct firmware *ur_fw = NULL;
	int offset;
	int r = 0;
	char fw_name[128];

	r = request_fw_file(&ur_fw,
		get_fw_name(usb, fw_name, sizeof(fw_name), "ur"),
		&udev->dev);
	if (r)
		goto error;

	r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START, REBOOT);
	if (r)
		goto error;

	offset = (E2P_BOOT_CODE_OFFSET * sizeof(u16));
	r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset,
		E2P_START + E2P_BOOT_CODE_OFFSET, REBOOT);

	/* At this point, the vendor driver downloads the whole firmware
	 * image, hacks around with version IDs, and uploads it again,
	 * completely overwriting the boot code. We do not do this here as
	 * it is not required on any tested devices, and it is suspected to
	 * cause problems. */
error:
	release_firmware(ur_fw);
	return r;
}
コード例 #2
0
ファイル: zd_usb.c プロジェクト: ARMP/android_kernel_lge_x3
void zd_usb_disable_int(struct zd_usb *usb)
{
	unsigned long flags;
	struct usb_device *udev = zd_usb_to_usbdev(usb);
	struct zd_usb_interrupt *intr = &usb->intr;
	struct urb *urb;
	void *buffer;
	dma_addr_t buffer_dma;

	spin_lock_irqsave(&intr->lock, flags);
	urb = intr->urb;
	if (!urb) {
		spin_unlock_irqrestore(&intr->lock, flags);
		return;
	}
	intr->urb = NULL;
	buffer = intr->buffer;
	buffer_dma = intr->buffer_dma;
	intr->buffer = NULL;
	spin_unlock_irqrestore(&intr->lock, flags);

	usb_kill_urb(urb);
	dev_dbg_f(zd_usb_dev(usb), "urb %p killed\n", urb);
	usb_free_urb(urb);

	if (buffer)
		usb_free_coherent(udev, USB_MAX_EP_INT_BUFFER,
				  buffer, buffer_dma);
}
コード例 #3
0
ファイル: zd_usb.c プロジェクト: ARMP/android_kernel_lge_x3
/* Read data from device address space using "firmware interface" which does
 * not require firmware to be loaded. */
int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len)
{
	int r;
	struct usb_device *udev = zd_usb_to_usbdev(usb);
	u8 *buf;

	/* Use "DMA-aware" buffer. */
	buf = kmalloc(len, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;
	r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
		USB_REQ_FIRMWARE_READ_DATA, USB_DIR_IN | 0x40, addr, 0,
		buf, len, 5000);
	if (r < 0) {
		dev_err(&udev->dev,
			"read over firmware interface failed: %d\n", r);
		goto exit;
	} else if (r != len) {
		dev_err(&udev->dev,
			"incomplete read over firmware interface: %d/%d\n",
			r, len);
		r = -EIO;
		goto exit;
	}
	r = 0;
	memcpy(data, buf, len);
exit:
	kfree(buf);
	return r;
}
コード例 #4
0
ファイル: zd_usb.c プロジェクト: ARMP/android_kernel_lge_x3
static int upload_firmware(struct zd_usb *usb)
{
	int r;
	u16 fw_bcdDevice;
	u16 bcdDevice;
	struct usb_device *udev = zd_usb_to_usbdev(usb);
	const struct firmware *ub_fw = NULL;
	const struct firmware *uph_fw = NULL;
	char fw_name[128];

	bcdDevice = get_bcdDevice(udev);

	r = request_fw_file(&ub_fw,
		get_fw_name(usb, fw_name, sizeof(fw_name), "ub"),
		&udev->dev);
	if (r)
		goto error;

	fw_bcdDevice = get_word(ub_fw->data, E2P_DATA_OFFSET);

	if (fw_bcdDevice != bcdDevice) {
		dev_info(&udev->dev,
			"firmware version %#06x and device bootcode version "
			"%#06x differ\n", fw_bcdDevice, bcdDevice);
		if (bcdDevice <= 0x4313)
			dev_warn(&udev->dev, "device has old bootcode, please "
				"report success or failure\n");

		r = handle_version_mismatch(usb, ub_fw);
		if (r)
			goto error;
	} else {
		dev_dbg_f(&udev->dev,
			"firmware device id %#06x is equal to the "
			"actual device id\n", fw_bcdDevice);
	}


	r = request_fw_file(&uph_fw,
		get_fw_name(usb, fw_name, sizeof(fw_name), "uphr"),
		&udev->dev);
	if (r)
		goto error;

	r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START, REBOOT);
	if (r) {
		dev_err(&udev->dev,
			"Could not upload firmware code uph. Error number %d\n",
			r);
	}

	/* FALL-THROUGH */
error:
	release_firmware(ub_fw);
	release_firmware(uph_fw);
	return r;
}
コード例 #5
0
ファイル: zd_usb.c プロジェクト: b3rnik/dsl-n55u-bender
static inline void init_usb_interrupt(struct zd_usb *usb)
{
    struct zd_usb_interrupt *intr = &usb->intr;

    spin_lock_init(&intr->lock);
    intr->interval = int_urb_interval(zd_usb_to_usbdev(usb));
    init_completion(&intr->read_regs.completion);
    intr->read_regs.cr_int_addr = cpu_to_le16((u16)CR_INTERRUPT);
}
コード例 #6
0
ファイル: zd_usb.c プロジェクト: b3rnik/dsl-n55u-bender
int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
                      unsigned int count)
{
    int r;
    struct usb_device *udev;
    struct usb_req_write_regs *req = NULL;
    int i, req_len, actual_req_len;

    if (count == 0)
        return 0;
    if (count > USB_MAX_IOWRITE16_COUNT) {
        dev_dbg_f(zd_usb_dev(usb),
                  "error: count %u exceeds possible max %u\n",
                  count, USB_MAX_IOWRITE16_COUNT);
        return -EINVAL;
    }
    if (in_atomic()) {
        dev_dbg_f(zd_usb_dev(usb),
                  "error: io in atomic context not supported\n");
        return -EWOULDBLOCK;
    }

    req_len = sizeof(struct usb_req_write_regs) +
              count * sizeof(struct reg_data);
    req = kmalloc(req_len, GFP_KERNEL);
    if (!req)
        return -ENOMEM;

    req->id = cpu_to_le16(USB_REQ_WRITE_REGS);
    for (i = 0; i < count; i++) {
        struct reg_data *rw  = &req->reg_writes[i];
        rw->addr = cpu_to_le16((u16)ioreqs[i].addr);
        rw->value = cpu_to_le16(ioreqs[i].value);
    }

    udev = zd_usb_to_usbdev(usb);
    r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT),
                     req, req_len, &actual_req_len, 1000 /* ms */);
    if (r) {
        dev_dbg_f(zd_usb_dev(usb),
                  "error in usb_bulk_msg(). Error number %d\n", r);
        goto error;
    }
    if (req_len != actual_req_len) {
        dev_dbg_f(zd_usb_dev(usb),
                  "error in usb_bulk_msg()"
                  " req_len %d != actual_req_len %d\n",
                  req_len, actual_req_len);
        r = -EIO;
        goto error;
    }

    /* FALL-THROUGH with r == 0 */
error:
    kfree(req);
    return r;
}
コード例 #7
0
ファイル: zd_usb.c プロジェクト: b3rnik/dsl-n55u-bender
/* Puts the frame on the USB endpoint. It doesn't wait for
 * completion. The frame must contain the control set.
 */
int zd_usb_tx(struct zd_usb *usb, const u8 *frame, unsigned int length)
{
    int r;
    struct usb_device *udev = zd_usb_to_usbdev(usb);
    struct urb *urb;
    void *buffer;

    urb = usb_alloc_urb(0, GFP_ATOMIC);
    if (!urb) {
        r = -ENOMEM;
        goto out;
    }

    buffer = usb_buffer_alloc(zd_usb_to_usbdev(usb), length, GFP_ATOMIC,
                              &urb->transfer_dma);
    if (!buffer) {
        r = -ENOMEM;
        goto error_free_urb;
    }
    memcpy(buffer, frame, length);

    usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT),
                      buffer, length, tx_urb_complete, NULL);
    urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

    r = usb_submit_urb(urb, GFP_ATOMIC);
    if (r)
        goto error;
    return 0;
error:
    usb_buffer_free(zd_usb_to_usbdev(usb), length, buffer,
                    urb->transfer_dma);
error_free_urb:
    usb_free_urb(urb);
out:
    return r;
}
コード例 #8
0
ファイル: zd_usb.c プロジェクト: ARMP/android_kernel_lge_x3
/**
 * zd_usb_tx: initiates transfer of a frame of the device
 *
 * @usb: the zd1211rw-private USB structure
 * @skb: a &struct sk_buff pointer
 *
 * This function tranmits a frame to the device. It doesn't wait for
 * completion. The frame must contain the control set and have all the
 * control set information available.
 *
 * The function returns 0 if the transfer has been successfully initiated.
 */
int zd_usb_tx(struct zd_usb *usb, struct sk_buff *skb)
{
	int r;
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
	struct usb_device *udev = zd_usb_to_usbdev(usb);
	struct urb *urb;
	struct zd_usb_tx *tx = &usb->tx;

	if (!atomic_read(&tx->enabled)) {
		r = -ENOENT;
		goto out;
	}

	urb = usb_alloc_urb(0, GFP_ATOMIC);
	if (!urb) {
		r = -ENOMEM;
		goto out;
	}

	usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT),
		          skb->data, skb->len, tx_urb_complete, skb);

	info->rate_driver_data[1] = (void *)jiffies;
	skb_queue_tail(&tx->submitted_skbs, skb);
	usb_anchor_urb(urb, &tx->submitted);

	r = usb_submit_urb(urb, GFP_ATOMIC);
	if (r) {
		dev_dbg_f(zd_usb_dev(usb), "error submit urb %p %d\n", urb, r);
		usb_unanchor_urb(urb);
		skb_unlink(skb, &tx->submitted_skbs);
		goto error;
	}
	tx_inc_submitted_urbs(usb);
	return 0;
error:
	usb_free_urb(urb);
out:
	return r;
}
コード例 #9
0
ファイル: zd_usb.c プロジェクト: ARMP/android_kernel_lge_x3
static struct urb *alloc_rx_urb(struct zd_usb *usb)
{
	struct usb_device *udev = zd_usb_to_usbdev(usb);
	struct urb *urb;
	void *buffer;

	urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!urb)
		return NULL;
	buffer = usb_alloc_coherent(udev, USB_MAX_RX_SIZE, GFP_KERNEL,
				    &urb->transfer_dma);
	if (!buffer) {
		usb_free_urb(urb);
		return NULL;
	}

	usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, EP_DATA_IN),
			  buffer, USB_MAX_RX_SIZE,
			  rx_urb_complete, usb);
	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

	return urb;
}
コード例 #10
0
ファイル: zd_usb.c プロジェクト: ARMP/android_kernel_lge_x3
int zd_usb_enable_int(struct zd_usb *usb)
{
	int r;
	struct usb_device *udev = zd_usb_to_usbdev(usb);
	struct zd_usb_interrupt *intr = &usb->intr;
	struct urb *urb;

	dev_dbg_f(zd_usb_dev(usb), "\n");

	urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!urb) {
		r = -ENOMEM;
		goto out;
	}

	ZD_ASSERT(!irqs_disabled());
	spin_lock_irq(&intr->lock);
	if (intr->urb) {
		spin_unlock_irq(&intr->lock);
		r = 0;
		goto error_free_urb;
	}
	intr->urb = urb;
	spin_unlock_irq(&intr->lock);

	r = -ENOMEM;
	intr->buffer = usb_alloc_coherent(udev, USB_MAX_EP_INT_BUFFER,
					  GFP_KERNEL, &intr->buffer_dma);
	if (!intr->buffer) {
		dev_dbg_f(zd_usb_dev(usb),
			"couldn't allocate transfer_buffer\n");
		goto error_set_urb_null;
	}

	usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, EP_INT_IN),
			 intr->buffer, USB_MAX_EP_INT_BUFFER,
			 int_urb_complete, usb,
			 intr->interval);
	urb->transfer_dma = intr->buffer_dma;
	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

	dev_dbg_f(zd_usb_dev(usb), "submit urb %p\n", intr->urb);
	r = usb_submit_urb(urb, GFP_KERNEL);
	if (r) {
		dev_dbg_f(zd_usb_dev(usb),
			 "Couldn't submit urb. Error number %d\n", r);
		goto error;
	}

	return 0;
error:
	usb_free_coherent(udev, USB_MAX_EP_INT_BUFFER,
			  intr->buffer, intr->buffer_dma);
error_set_urb_null:
	spin_lock_irq(&intr->lock);
	intr->urb = NULL;
	spin_unlock_irq(&intr->lock);
error_free_urb:
	usb_free_urb(urb);
out:
	return r;
}
コード例 #11
0
ファイル: zd_usb.c プロジェクト: b3rnik/dsl-n55u-bender
int zd_usb_enable_int(struct zd_usb *usb)
{
    int r;
    struct usb_device *udev;
    struct zd_usb_interrupt *intr = &usb->intr;
    void *transfer_buffer = NULL;
    struct urb *urb;

    dev_dbg_f(zd_usb_dev(usb), "\n");

    urb = usb_alloc_urb(0, GFP_KERNEL);
    if (!urb) {
        r = -ENOMEM;
        goto out;
    }

    ZD_ASSERT(!irqs_disabled());
    spin_lock_irq(&intr->lock);
    if (intr->urb) {
        spin_unlock_irq(&intr->lock);
        r = 0;
        goto error_free_urb;
    }
    intr->urb = urb;
    spin_unlock_irq(&intr->lock);

    /* TODO: make it a DMA buffer */
    r = -ENOMEM;
    transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_KERNEL);
    if (!transfer_buffer) {
        dev_dbg_f(zd_usb_dev(usb),
                  "couldn't allocate transfer_buffer\n");
        goto error_set_urb_null;
    }

    udev = zd_usb_to_usbdev(usb);
    usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, EP_INT_IN),
                     transfer_buffer, USB_MAX_EP_INT_BUFFER,
                     int_urb_complete, usb,
                     intr->interval);

    dev_dbg_f(zd_usb_dev(usb), "submit urb %p\n", intr->urb);
    r = usb_submit_urb(urb, GFP_KERNEL);
    if (r) {
        dev_dbg_f(zd_usb_dev(usb),
                  "Couldn't submit urb. Error number %d\n", r);
        goto error;
    }

    return 0;
error:
    kfree(transfer_buffer);
error_set_urb_null:
    spin_lock_irq(&intr->lock);
    intr->urb = NULL;
    spin_unlock_irq(&intr->lock);
error_free_urb:
    usb_free_urb(urb);
out:
    return r;
}
コード例 #12
0
ファイル: zd_usb.c プロジェクト: b3rnik/dsl-n55u-bender
int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits)
{
    int r;
    struct usb_device *udev;
    struct usb_req_rfwrite *req = NULL;
    int i, req_len, actual_req_len;
    u16 bit_value_template;

    if (in_atomic()) {
        dev_dbg_f(zd_usb_dev(usb),
                  "error: io in atomic context not supported\n");
        return -EWOULDBLOCK;
    }
    if (bits < USB_MIN_RFWRITE_BIT_COUNT) {
        dev_dbg_f(zd_usb_dev(usb),
                  "error: bits %d are smaller than"
                  " USB_MIN_RFWRITE_BIT_COUNT %d\n",
                  bits, USB_MIN_RFWRITE_BIT_COUNT);
        return -EINVAL;
    }
    if (bits > USB_MAX_RFWRITE_BIT_COUNT) {
        dev_dbg_f(zd_usb_dev(usb),
                  "error: bits %d exceed USB_MAX_RFWRITE_BIT_COUNT %d\n",
                  bits, USB_MAX_RFWRITE_BIT_COUNT);
        return -EINVAL;
    }
#ifdef DEBUG
    if (value & (~0UL << bits)) {
        dev_dbg_f(zd_usb_dev(usb),
                  "error: value %#09x has bits >= %d set\n",
                  value, bits);
        return -EINVAL;
    }
#endif /* DEBUG */

    dev_dbg_f(zd_usb_dev(usb), "value %#09x bits %d\n", value, bits);

    r = zd_usb_ioread16(usb, &bit_value_template, CR203);
    if (r) {
        dev_dbg_f(zd_usb_dev(usb),
                  "error %d: Couldn't read CR203\n", r);
        goto out;
    }
    bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA);

    req_len = sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16);
    req = kmalloc(req_len, GFP_KERNEL);
    if (!req)
        return -ENOMEM;

    req->id = cpu_to_le16(USB_REQ_WRITE_RF);
    /* 1: 3683a, but not used in ZYDAS driver */
    req->value = cpu_to_le16(2);
    req->bits = cpu_to_le16(bits);

    for (i = 0; i < bits; i++) {
        u16 bv = bit_value_template;
        if (value & (1 << (bits-1-i)))
            bv |= RF_DATA;
        req->bit_values[i] = cpu_to_le16(bv);
    }

    udev = zd_usb_to_usbdev(usb);
    r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT),
                     req, req_len, &actual_req_len, 1000 /* ms */);
    if (r) {
        dev_dbg_f(zd_usb_dev(usb),
                  "error in usb_bulk_msg(). Error number %d\n", r);
        goto out;
    }
    if (req_len != actual_req_len) {
        dev_dbg_f(zd_usb_dev(usb), "error in usb_bulk_msg()"
                  " req_len %d != actual_req_len %d\n",
                  req_len, actual_req_len);
        r = -EIO;
        goto out;
    }

    /* FALL-THROUGH with r == 0 */
out:
    kfree(req);
    return r;
}
コード例 #13
0
ファイル: zd_usb.c プロジェクト: b3rnik/dsl-n55u-bender
int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
                     const zd_addr_t *addresses, unsigned int count)
{
    int r;
    int i, req_len, actual_req_len;
    struct usb_device *udev;
    struct usb_req_read_regs *req = NULL;
    unsigned long timeout;

    if (count < 1) {
        dev_dbg_f(zd_usb_dev(usb), "error: count is zero\n");
        return -EINVAL;
    }
    if (count > USB_MAX_IOREAD16_COUNT) {
        dev_dbg_f(zd_usb_dev(usb),
                  "error: count %u exceeds possible max %u\n",
                  count, USB_MAX_IOREAD16_COUNT);
        return -EINVAL;
    }
    if (in_atomic()) {
        dev_dbg_f(zd_usb_dev(usb),
                  "error: io in atomic context not supported\n");
        return -EWOULDBLOCK;
    }
    if (!usb_int_enabled(usb)) {
        dev_dbg_f(zd_usb_dev(usb),
                  "error: usb interrupt not enabled\n");
        return -EWOULDBLOCK;
    }

    req_len = sizeof(struct usb_req_read_regs) + count * sizeof(__le16);
    req = kmalloc(req_len, GFP_KERNEL);
    if (!req)
        return -ENOMEM;
    req->id = cpu_to_le16(USB_REQ_READ_REGS);
    for (i = 0; i < count; i++)
        req->addr[i] = cpu_to_le16((u16)addresses[i]);

    udev = zd_usb_to_usbdev(usb);
    prepare_read_regs_int(usb);
    r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT),
                     req, req_len, &actual_req_len, 1000 /* ms */);
    if (r) {
        dev_dbg_f(zd_usb_dev(usb),
                  "error in usb_bulk_msg(). Error number %d\n", r);
        goto error;
    }
    if (req_len != actual_req_len) {
        dev_dbg_f(zd_usb_dev(usb), "error in usb_bulk_msg()\n"
                  " req_len %d != actual_req_len %d\n",
                  req_len, actual_req_len);
        r = -EIO;
        goto error;
    }

    timeout = wait_for_completion_timeout(&usb->intr.read_regs.completion,
                                          msecs_to_jiffies(1000));
    if (!timeout) {
        disable_read_regs_int(usb);
        dev_dbg_f(zd_usb_dev(usb), "read timed out\n");
        r = -ETIMEDOUT;
        goto error;
    }

    r = get_results(usb, values, req, count);
error:
    kfree(req);
    return r;
}