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; }
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); }
/* 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; }
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; }
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); }
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; }
/* 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; }
/** * 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; }
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; }
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; }
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; }
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; }
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; }