📄 zd_usb.c
字号:
int zd_usb_enable_rx(struct zd_usb *usb){ int i, r; struct zd_usb_rx *rx = &usb->rx; struct urb **urbs; dev_dbg_f(zd_usb_dev(usb), "\n"); r = -ENOMEM; urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_NOFS); if (!urbs) goto error; for (i = 0; i < URBS_COUNT; i++) { urbs[i] = alloc_urb(usb); if (!urbs[i]) goto error; } ZD_ASSERT(!irqs_disabled()); spin_lock_irq(&rx->lock); if (rx->urbs) { spin_unlock_irq(&rx->lock); r = 0; goto error; } rx->urbs = urbs; rx->urbs_count = URBS_COUNT; spin_unlock_irq(&rx->lock); for (i = 0; i < URBS_COUNT; i++) { r = usb_submit_urb(urbs[i], GFP_NOFS); if (r) goto error_submit; } return 0;error_submit: for (i = 0; i < URBS_COUNT; i++) { usb_kill_urb(urbs[i]); } spin_lock_irq(&rx->lock); rx->urbs = NULL; rx->urbs_count = 0; spin_unlock_irq(&rx->lock);error: if (urbs) { for (i = 0; i < URBS_COUNT; i++) free_urb(urbs[i]); } return r;}void zd_usb_disable_rx(struct zd_usb *usb){ int i; unsigned long flags; struct urb **urbs; unsigned int count; struct zd_usb_rx *rx = &usb->rx; spin_lock_irqsave(&rx->lock, flags); urbs = rx->urbs; count = rx->urbs_count; spin_unlock_irqrestore(&rx->lock, flags); if (!urbs) return; for (i = 0; i < count; i++) { usb_kill_urb(urbs[i]); free_urb(urbs[i]); } kfree(urbs); spin_lock_irqsave(&rx->lock, flags); rx->urbs = NULL; rx->urbs_count = 0; spin_unlock_irqrestore(&rx->lock, flags);}static void tx_urb_complete(struct urb *urb, struct pt_regs *pt_regs){ int r; switch (urb->status) { case 0: break; case -ESHUTDOWN: case -EINVAL: case -ENODEV: case -ENOENT: case -ECONNRESET: case -EPIPE: dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status); break; default: dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status); goto resubmit; }free_urb: usb_buffer_free(urb->dev, urb->transfer_buffer_length, urb->transfer_buffer, urb->transfer_dma); usb_free_urb(urb); return;resubmit: r = usb_submit_urb(urb, GFP_ATOMIC); if (r) { dev_dbg_f(urb_dev(urb), "error resubmit urb %p %d\n", urb, r); goto free_urb; }}/* 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;}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(usb_addr(usb, CR_INTERRUPT));}static inline void init_usb_rx(struct zd_usb *usb){ struct zd_usb_rx *rx = &usb->rx; spin_lock_init(&rx->lock); if (interface_to_usbdev(usb->intf)->speed == USB_SPEED_HIGH) { rx->usb_packet_size = 512; } else { rx->usb_packet_size = 64; } ZD_ASSERT(rx->fragment_length == 0);}static inline void init_usb_tx(struct zd_usb *usb){ /* FIXME: at this point we will allocate a fixed number of urb's for * use in a cyclic scheme */}void zd_usb_init(struct zd_usb *usb, struct net_device *netdev, struct usb_interface *intf){ memset(usb, 0, sizeof(*usb)); usb->intf = usb_get_intf(intf); usb_set_intfdata(usb->intf, netdev); init_usb_interrupt(usb); init_usb_tx(usb); init_usb_rx(usb);}int zd_usb_init_hw(struct zd_usb *usb){ int r; struct zd_chip *chip = zd_usb_to_chip(usb); ZD_ASSERT(mutex_is_locked(&chip->mutex)); r = zd_ioread16_locked(chip, &usb->fw_base_offset, USB_REG((u16)FW_BASE_ADDR_OFFSET)); if (r) return r; dev_dbg_f(zd_usb_dev(usb), "fw_base_offset: %#06hx\n", usb->fw_base_offset); return 0;}void zd_usb_clear(struct zd_usb *usb){ usb_set_intfdata(usb->intf, NULL); usb_put_intf(usb->intf); memset(usb, 0, sizeof(*usb)); /* FIXME: usb_interrupt, usb_tx, usb_rx? */}static const char *speed(enum usb_device_speed speed){ switch (speed) { case USB_SPEED_LOW: return "low"; case USB_SPEED_FULL: return "full"; case USB_SPEED_HIGH: return "high"; default: return "unknown speed"; }}static int scnprint_id(struct usb_device *udev, char *buffer, size_t size){ return scnprintf(buffer, size, "%04hx:%04hx v%04hx %s", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct), get_bcdDevice(udev), speed(udev->speed));}int zd_usb_scnprint_id(struct zd_usb *usb, char *buffer, size_t size){ struct usb_device *udev = interface_to_usbdev(usb->intf); return scnprint_id(udev, buffer, size);}#ifdef DEBUGstatic void print_id(struct usb_device *udev){ char buffer[40]; scnprint_id(udev, buffer, sizeof(buffer)); buffer[sizeof(buffer)-1] = 0; dev_dbg_f(&udev->dev, "%s\n", buffer);}#else#define print_id(udev) do { } while (0)#endifstatic int probe(struct usb_interface *intf, const struct usb_device_id *id){ int r; struct usb_device *udev = interface_to_usbdev(intf); struct net_device *netdev = NULL; print_id(udev); switch (udev->speed) { case USB_SPEED_LOW: case USB_SPEED_FULL: case USB_SPEED_HIGH: break; default: dev_dbg_f(&intf->dev, "Unknown USB speed\n"); r = -ENODEV; goto error; } netdev = zd_netdev_alloc(intf); if (netdev == NULL) { r = -ENOMEM; goto error; } r = upload_firmware(udev, id->driver_info); if (r) { dev_err(&intf->dev, "couldn't load firmware. Error number %d\n", r); goto error; } r = usb_reset_configuration(udev); if (r) { dev_dbg_f(&intf->dev, "couldn't reset configuration. Error number %d\n", r); goto error; } /* At this point the interrupt endpoint is not generally enabled. We * save the USB bandwidth until the network device is opened. But * notify that the initialization of the MAC will require the * interrupts to be temporary enabled. */ r = zd_mac_init_hw(zd_netdev_mac(netdev), id->driver_info); if (r) { dev_dbg_f(&intf->dev, "couldn't initialize mac. Error number %d\n", r); goto error; } r = register_netdev(netdev); if (r) { dev_dbg_f(&intf->dev, "couldn't register netdev. Error number %d\n", r); goto error; } dev_dbg_f(&intf->dev, "successful\n"); dev_info(&intf->dev,"%s\n", netdev->name); return 0;error: usb_reset_device(interface_to_usbdev(intf)); zd_netdev_free(netdev); return r;}static void disconnect(struct usb_interface *intf){ struct net_device *netdev = zd_intf_to_netdev(intf); struct zd_mac *mac = zd_netdev_mac(netdev); struct zd_usb *usb = &mac->chip.usb; dev_dbg_f(zd_usb_dev(usb), "\n"); zd_netdev_disconnect(netdev); /* Just in case something has gone wrong! */ zd_usb_disable_rx(usb); zd_usb_disable_int(usb); /* If the disconnect has been caused by a removal of the * driver module, the reset allows reloading of the driver. If the * reset will not be executed here, the upload of the firmware in the * probe function caused by the reloading of the driver will fail. */ usb_reset_device(interface_to_usbdev(intf)); /* If somebody still waits on this lock now, this is an error. */ zd_netdev_free(netdev); dev_dbg(&intf->dev, "disconnected\n");}static struct usb_driver driver = { .name = "zd1211rw", .id_table = usb_ids, .probe = probe, .disconnect = disconnect,};static int __init usb_init(void){ int r; pr_debug("usb_init()\n"); r = usb_register(&driver); if (r) { printk(KERN_ERR "usb_register() failed. Error number %d\n", r); return r; } pr_debug("zd1211rw initialized\n"); return 0;}static void __exit usb_exit(void){ pr_debug("usb_exit()\n"); usb_deregister(&driver);}module_init(usb_init);module_exit(usb_exit);static int usb_int_regs_length(unsigned int count){ return sizeof(struct usb_int_regs) + count * sizeof(struct reg_data);}static void prepare_read_regs_int(struct zd_usb *usb){ struct zd_usb_interrupt *intr = &usb->intr; spin_lock(&intr->lock); intr->read_regs_enabled = 1; INIT_COMPLETION(intr->read_regs.completion); spin_unlock(&intr->lock);}static int get_results(struct zd_usb *usb, u16 *values, struct usb_req_read_regs *req, unsigned int count){ int r; int i; struct zd_usb_interrupt *intr = &usb->intr; struct read_regs_int *rr = &intr->read_regs; struct usb_int_regs *regs = (struct usb_int_regs *)rr->buffer; spin_lock(&intr->lock); r = -EIO; /* The created block size seems to be larger than expected. * However results appear to be correct. */ if (rr->length < usb_int_regs_length(count)) { dev_dbg_f(zd_usb_dev(usb), "error: actual length %d less than expected %d\n", rr->length, usb_int_regs_length(count)); goto error_unlock; } if (rr->length > sizeof(rr->buffer)) { dev_dbg_f(zd_usb_dev(usb), "error: actual length %d exceeds buffer size %zu\n", rr->length, sizeof(rr->buffer)); goto error_unlock; } for (i = 0; i < count; i++) { struct reg_data *rd = ®s->regs[i]; if (rd->addr != req->addr[i]) { dev_dbg_f(zd_usb_dev(usb), "rd[%d] addr %#06hx expected %#06hx\n", i, le16_to_cpu(rd->addr), le16_to_cpu(req->addr[i])); goto error_unlock; } values[i] = le16_to_cpu(rd->value); } r = 0;error_unlock: spin_unlock(&intr->lock); 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_NOFS); 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(usb_addr(usb, 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;}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_NOFS); 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(usb_addr(usb, 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;}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_NOFS); 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -