📄 zd_usb.c
字号:
cmd[3] = 0x43; /* bulk command signature */ cmd[14] = 6; /* command length */ cmd[15] = 0x1b; /* SCSI command: START STOP UNIT */ cmd[19] = 0x2; /* eject disc */ dev_info(&udev->dev, "Ejecting virtual installer media...\n"); r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, bulk_out_ep), cmd, 31, NULL, 2000); kfree(cmd); if (r) return r; /* At this point, the device disconnects and reconnects with the real * ID numbers. */ usb_set_intfdata(intf, NULL); return 0;}int zd_usb_init_hw(struct zd_usb *usb){ int r; struct zd_mac *mac = zd_usb_to_mac(usb); dev_dbg_f(zd_usb_dev(usb), "\n"); r = upload_firmware(usb); if (r) { dev_err(zd_usb_dev(usb), "couldn't load firmware. Error number %d\n", r); return r; } r = usb_reset_configuration(zd_usb_to_usbdev(usb)); if (r) { dev_dbg_f(zd_usb_dev(usb), "couldn't reset configuration. Error number %d\n", r); return r; } r = zd_mac_init_hw(mac); if (r) { dev_dbg_f(zd_usb_dev(usb), "couldn't initialize mac. Error number %d\n", r); return r; } usb->initialized = 1; return 0;}static int probe(struct usb_interface *intf, const struct usb_device_id *id){ int r; struct zd_usb *usb; struct usb_device *udev = interface_to_usbdev(intf); struct net_device *netdev = NULL; print_id(udev); if (id->driver_info & DEVICE_INSTALLER) return eject_installer(intf); 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; } usb_reset_device(interface_to_usbdev(intf)); netdev = zd_netdev_alloc(intf); if (netdev == NULL) { r = -ENOMEM; goto error; } usb = &zd_netdev_mac(netdev)->chip.usb; usb->is_zd1211b = (id->driver_info == DEVICE_ZD1211B) != 0; r = zd_mac_preinit_hw(zd_netdev_mac(netdev)); 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; struct zd_usb *usb; /* Either something really bad happened, or we're just dealing with * a DEVICE_INSTALLER. */ if (netdev == NULL) return; mac = zd_netdev_mac(netdev); 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)); 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,};struct workqueue_struct *zd_workqueue;static int __init usb_init(void){ int r; pr_debug("%s usb_init()\n", driver.name); zd_workqueue = create_singlethread_workqueue(driver.name); if (zd_workqueue == NULL) { printk(KERN_ERR "%s couldn't create workqueue\n", driver.name); return -ENOMEM; } r = usb_register(&driver); if (r) { destroy_workqueue(zd_workqueue); printk(KERN_ERR "%s usb_register() failed. Error number %d\n", driver.name, r); return r; } pr_debug("%s initialized\n", driver.name); return 0;}static void __exit usb_exit(void){ pr_debug("%s usb_exit()\n", driver.name); usb_deregister(&driver); destroy_workqueue(zd_workqueue);}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_irq(&intr->lock); intr->read_regs_enabled = 1; INIT_COMPLETION(intr->read_regs.completion); spin_unlock_irq(&intr->lock);}static void disable_read_regs_int(struct zd_usb *usb){ struct zd_usb_interrupt *intr = &usb->intr; spin_lock_irq(&intr->lock); intr->read_regs_enabled = 0; spin_unlock_irq(&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_irq(&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_irq(&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_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;}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;}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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -