Loading drivers/usb/storage/uas.c +117 −40 Original line number Diff line number Diff line Loading @@ -98,6 +98,8 @@ struct uas_dev_info { unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe; unsigned use_streams:1; unsigned uas_sense_old:1; struct scsi_cmnd *cmnd; struct urb *status_urb; /* used only if stream support is available */ }; enum { Loading @@ -116,6 +118,7 @@ struct uas_cmd_info { unsigned int state; unsigned int stream; struct urb *cmd_urb; /* status_urb is used only if stream support isn't available */ struct urb *status_urb; struct urb *data_in_urb; struct urb *data_out_urb; Loading @@ -125,28 +128,37 @@ struct uas_cmd_info { /* I hate forward declarations, but I actually have a loop */ static int uas_submit_urbs(struct scsi_cmnd *cmnd, struct uas_dev_info *devinfo, gfp_t gfp); static void uas_do_work(struct work_struct *work); static DECLARE_WORK(uas_work, uas_do_work); static DEFINE_SPINLOCK(uas_work_lock); static LIST_HEAD(uas_work_list); static void uas_do_work(struct work_struct *work) { struct uas_cmd_info *cmdinfo; struct uas_cmd_info *temp; struct list_head list; int err; spin_lock_irq(&uas_work_lock); list_replace_init(&uas_work_list, &list); spin_unlock_irq(&uas_work_lock); list_for_each_entry(cmdinfo, &list, list) { list_for_each_entry_safe(cmdinfo, temp, &list, list) { struct scsi_pointer *scp = (void *)cmdinfo; struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, SCp); uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO); err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO); if (err) { list_del(&cmdinfo->list); spin_lock_irq(&uas_work_lock); list_add_tail(&cmdinfo->list, &uas_work_list); spin_unlock_irq(&uas_work_lock); schedule_work(&uas_work); } } } static DECLARE_WORK(uas_work, uas_do_work); static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd) { Loading @@ -169,10 +181,7 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd) } cmnd->result = sense_iu->status; if (sdev->current_cmnd) sdev->current_cmnd = NULL; cmnd->scsi_done(cmnd); usb_free_urb(urb); } static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd) Loading @@ -196,10 +205,7 @@ static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd) } cmnd->result = sense_iu->status; if (sdev->current_cmnd) sdev->current_cmnd = NULL; cmnd->scsi_done(cmnd); usb_free_urb(urb); } static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd, Loading @@ -208,7 +214,7 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd, struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; int err; cmdinfo->state = direction | SUBMIT_STATUS_URB; cmdinfo->state = direction; err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC); if (err) { spin_lock(&uas_work_lock); Loading @@ -221,27 +227,40 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd, static void uas_stat_cmplt(struct urb *urb) { struct iu *iu = urb->transfer_buffer; struct scsi_device *sdev = urb->context; struct uas_dev_info *devinfo = sdev->hostdata; struct Scsi_Host *shost = urb->context; struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; struct scsi_cmnd *cmnd; u16 tag; int ret; if (urb->status) { dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status); if (devinfo->use_streams) usb_free_urb(urb); return; } tag = be16_to_cpup(&iu->tag) - 1; if (sdev->current_cmnd) cmnd = sdev->current_cmnd; if (tag == 0) cmnd = devinfo->cmnd; else cmnd = scsi_find_tag(sdev, tag); if (!cmnd) cmnd = scsi_host_find_tag(shost, tag - 1); if (!cmnd) { if (devinfo->use_streams) { usb_free_urb(urb); return; } ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret) dev_err(&urb->dev->dev, "failed submit status urb\n"); return; } switch (iu->iu_id) { case IU_ID_STATUS: if (devinfo->cmnd == cmnd) devinfo->cmnd = NULL; if (urb->actual_length < 16) devinfo->uas_sense_old = 1; if (devinfo->uas_sense_old) Loading @@ -259,6 +278,15 @@ static void uas_stat_cmplt(struct urb *urb) scmd_printk(KERN_ERR, cmnd, "Bogus IU (%d) received on status pipe\n", iu->iu_id); } if (devinfo->use_streams) { usb_free_urb(urb); return; } ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret) dev_err(&urb->dev->dev, "failed submit status urb\n"); } static void uas_data_cmplt(struct urb *urb) Loading Loading @@ -289,7 +317,7 @@ static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp, } static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp, struct scsi_cmnd *cmnd, u16 stream_id) struct Scsi_Host *shost, u16 stream_id) { struct usb_device *udev = devinfo->udev; struct urb *urb = usb_alloc_urb(0, gfp); Loading @@ -303,7 +331,7 @@ static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp, goto free; usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu), uas_stat_cmplt, cmnd->device); uas_stat_cmplt, shost); urb->stream_id = stream_id; urb->transfer_flags |= URB_FREE_BUFFER; out: Loading Loading @@ -334,7 +362,10 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp, goto free; iu->iu_id = IU_ID_COMMAND; iu->tag = cpu_to_be16(stream_id); if (blk_rq_tagged(cmnd->request)) iu->tag = cpu_to_be16(cmnd->request->tag + 2); else iu->tag = cpu_to_be16(1); iu->prio_attr = UAS_SIMPLE_TAG; iu->len = len; int_to_scsilun(sdev->lun, &iu->lun); Loading Loading @@ -362,8 +393,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd, struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; if (cmdinfo->state & ALLOC_STATUS_URB) { cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp, cmnd, cmdinfo->stream); cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp, cmnd->device->host, cmdinfo->stream); if (!cmdinfo->status_urb) return SCSI_MLQUEUE_DEVICE_BUSY; cmdinfo->state &= ~ALLOC_STATUS_URB; Loading Loading @@ -444,13 +475,13 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer)); if (!cmdinfo->status_urb && sdev->current_cmnd) if (devinfo->cmnd) return SCSI_MLQUEUE_DEVICE_BUSY; if (blk_rq_tagged(cmnd->request)) { cmdinfo->stream = cmnd->request->tag + 1; cmdinfo->stream = cmnd->request->tag + 2; } else { sdev->current_cmnd = cmnd; devinfo->cmnd = cmnd; cmdinfo->stream = 1; } Loading @@ -472,7 +503,8 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, } if (!devinfo->use_streams) { cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB); cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB | ALLOC_STATUS_URB | SUBMIT_STATUS_URB); cmdinfo->stream = 0; } Loading Loading @@ -551,7 +583,7 @@ static int uas_slave_configure(struct scsi_device *sdev) { struct uas_dev_info *devinfo = sdev->hostdata; scsi_set_tag_type(sdev, MSG_ORDERED_TAG); scsi_activate_tcq(sdev, devinfo->qdepth - 1); scsi_activate_tcq(sdev, devinfo->qdepth - 2); return 0; } Loading Loading @@ -619,6 +651,7 @@ static void uas_configure_endpoints(struct uas_dev_info *devinfo) unsigned i, n_endpoints = intf->cur_altsetting->desc.bNumEndpoints; devinfo->uas_sense_old = 0; devinfo->cmnd = NULL; for (i = 0; i < n_endpoints; i++) { unsigned char *extra = endpoint[i].extra; Loading Loading @@ -670,6 +703,40 @@ static void uas_configure_endpoints(struct uas_dev_info *devinfo) } } static int uas_alloc_status_urb(struct uas_dev_info *devinfo, struct Scsi_Host *shost) { if (devinfo->use_streams) { devinfo->status_urb = NULL; return 0; } devinfo->status_urb = uas_alloc_sense_urb(devinfo, GFP_KERNEL, shost, 0); if (!devinfo->status_urb) goto err_s_urb; if (usb_submit_urb(devinfo->status_urb, GFP_KERNEL)) goto err_submit_urb; return 0; err_submit_urb: usb_free_urb(devinfo->status_urb); err_s_urb: return -ENOMEM; } static void uas_free_streams(struct uas_dev_info *devinfo) { struct usb_device *udev = devinfo->udev; struct usb_host_endpoint *eps[3]; eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe); eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe); eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe); usb_free_streams(devinfo->intf, eps, 3, GFP_KERNEL); } /* * XXX: What I'd like to do here is register a SCSI host for each USB host in * the system. Follow usb-storage's design of registering a SCSI host for Loading Loading @@ -699,18 +766,33 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id) shost->max_id = 1; shost->sg_tablesize = udev->bus->sg_tablesize; result = scsi_add_host(shost, &intf->dev); devinfo->intf = intf; devinfo->udev = udev; uas_configure_endpoints(devinfo); result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2); if (result) goto free; result = scsi_add_host(shost, &intf->dev); if (result) goto deconfig_eps; shost->hostdata[0] = (unsigned long)devinfo; devinfo->intf = intf; devinfo->udev = udev; uas_configure_endpoints(devinfo); result = uas_alloc_status_urb(devinfo, shost); if (result) goto err_alloc_status; scsi_scan_host(shost); usb_set_intfdata(intf, shost); return result; err_alloc_status: scsi_remove_host(shost); shost = NULL; deconfig_eps: uas_free_streams(devinfo); free: kfree(devinfo); if (shost) Loading @@ -732,18 +814,13 @@ static int uas_post_reset(struct usb_interface *intf) static void uas_disconnect(struct usb_interface *intf) { struct usb_device *udev = interface_to_usbdev(intf); struct usb_host_endpoint *eps[3]; struct Scsi_Host *shost = usb_get_intfdata(intf); struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; scsi_remove_host(shost); eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe); eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe); eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe); usb_free_streams(intf, eps, 3, GFP_KERNEL); usb_kill_urb(devinfo->status_urb); usb_free_urb(devinfo->status_urb); uas_free_streams(devinfo); kfree(devinfo); } Loading Loading
drivers/usb/storage/uas.c +117 −40 Original line number Diff line number Diff line Loading @@ -98,6 +98,8 @@ struct uas_dev_info { unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe; unsigned use_streams:1; unsigned uas_sense_old:1; struct scsi_cmnd *cmnd; struct urb *status_urb; /* used only if stream support is available */ }; enum { Loading @@ -116,6 +118,7 @@ struct uas_cmd_info { unsigned int state; unsigned int stream; struct urb *cmd_urb; /* status_urb is used only if stream support isn't available */ struct urb *status_urb; struct urb *data_in_urb; struct urb *data_out_urb; Loading @@ -125,28 +128,37 @@ struct uas_cmd_info { /* I hate forward declarations, but I actually have a loop */ static int uas_submit_urbs(struct scsi_cmnd *cmnd, struct uas_dev_info *devinfo, gfp_t gfp); static void uas_do_work(struct work_struct *work); static DECLARE_WORK(uas_work, uas_do_work); static DEFINE_SPINLOCK(uas_work_lock); static LIST_HEAD(uas_work_list); static void uas_do_work(struct work_struct *work) { struct uas_cmd_info *cmdinfo; struct uas_cmd_info *temp; struct list_head list; int err; spin_lock_irq(&uas_work_lock); list_replace_init(&uas_work_list, &list); spin_unlock_irq(&uas_work_lock); list_for_each_entry(cmdinfo, &list, list) { list_for_each_entry_safe(cmdinfo, temp, &list, list) { struct scsi_pointer *scp = (void *)cmdinfo; struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, SCp); uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO); err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO); if (err) { list_del(&cmdinfo->list); spin_lock_irq(&uas_work_lock); list_add_tail(&cmdinfo->list, &uas_work_list); spin_unlock_irq(&uas_work_lock); schedule_work(&uas_work); } } } static DECLARE_WORK(uas_work, uas_do_work); static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd) { Loading @@ -169,10 +181,7 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd) } cmnd->result = sense_iu->status; if (sdev->current_cmnd) sdev->current_cmnd = NULL; cmnd->scsi_done(cmnd); usb_free_urb(urb); } static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd) Loading @@ -196,10 +205,7 @@ static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd) } cmnd->result = sense_iu->status; if (sdev->current_cmnd) sdev->current_cmnd = NULL; cmnd->scsi_done(cmnd); usb_free_urb(urb); } static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd, Loading @@ -208,7 +214,7 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd, struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; int err; cmdinfo->state = direction | SUBMIT_STATUS_URB; cmdinfo->state = direction; err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC); if (err) { spin_lock(&uas_work_lock); Loading @@ -221,27 +227,40 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd, static void uas_stat_cmplt(struct urb *urb) { struct iu *iu = urb->transfer_buffer; struct scsi_device *sdev = urb->context; struct uas_dev_info *devinfo = sdev->hostdata; struct Scsi_Host *shost = urb->context; struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; struct scsi_cmnd *cmnd; u16 tag; int ret; if (urb->status) { dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status); if (devinfo->use_streams) usb_free_urb(urb); return; } tag = be16_to_cpup(&iu->tag) - 1; if (sdev->current_cmnd) cmnd = sdev->current_cmnd; if (tag == 0) cmnd = devinfo->cmnd; else cmnd = scsi_find_tag(sdev, tag); if (!cmnd) cmnd = scsi_host_find_tag(shost, tag - 1); if (!cmnd) { if (devinfo->use_streams) { usb_free_urb(urb); return; } ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret) dev_err(&urb->dev->dev, "failed submit status urb\n"); return; } switch (iu->iu_id) { case IU_ID_STATUS: if (devinfo->cmnd == cmnd) devinfo->cmnd = NULL; if (urb->actual_length < 16) devinfo->uas_sense_old = 1; if (devinfo->uas_sense_old) Loading @@ -259,6 +278,15 @@ static void uas_stat_cmplt(struct urb *urb) scmd_printk(KERN_ERR, cmnd, "Bogus IU (%d) received on status pipe\n", iu->iu_id); } if (devinfo->use_streams) { usb_free_urb(urb); return; } ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret) dev_err(&urb->dev->dev, "failed submit status urb\n"); } static void uas_data_cmplt(struct urb *urb) Loading Loading @@ -289,7 +317,7 @@ static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp, } static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp, struct scsi_cmnd *cmnd, u16 stream_id) struct Scsi_Host *shost, u16 stream_id) { struct usb_device *udev = devinfo->udev; struct urb *urb = usb_alloc_urb(0, gfp); Loading @@ -303,7 +331,7 @@ static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp, goto free; usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu), uas_stat_cmplt, cmnd->device); uas_stat_cmplt, shost); urb->stream_id = stream_id; urb->transfer_flags |= URB_FREE_BUFFER; out: Loading Loading @@ -334,7 +362,10 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp, goto free; iu->iu_id = IU_ID_COMMAND; iu->tag = cpu_to_be16(stream_id); if (blk_rq_tagged(cmnd->request)) iu->tag = cpu_to_be16(cmnd->request->tag + 2); else iu->tag = cpu_to_be16(1); iu->prio_attr = UAS_SIMPLE_TAG; iu->len = len; int_to_scsilun(sdev->lun, &iu->lun); Loading Loading @@ -362,8 +393,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd, struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; if (cmdinfo->state & ALLOC_STATUS_URB) { cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp, cmnd, cmdinfo->stream); cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp, cmnd->device->host, cmdinfo->stream); if (!cmdinfo->status_urb) return SCSI_MLQUEUE_DEVICE_BUSY; cmdinfo->state &= ~ALLOC_STATUS_URB; Loading Loading @@ -444,13 +475,13 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer)); if (!cmdinfo->status_urb && sdev->current_cmnd) if (devinfo->cmnd) return SCSI_MLQUEUE_DEVICE_BUSY; if (blk_rq_tagged(cmnd->request)) { cmdinfo->stream = cmnd->request->tag + 1; cmdinfo->stream = cmnd->request->tag + 2; } else { sdev->current_cmnd = cmnd; devinfo->cmnd = cmnd; cmdinfo->stream = 1; } Loading @@ -472,7 +503,8 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd, } if (!devinfo->use_streams) { cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB); cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB | ALLOC_STATUS_URB | SUBMIT_STATUS_URB); cmdinfo->stream = 0; } Loading Loading @@ -551,7 +583,7 @@ static int uas_slave_configure(struct scsi_device *sdev) { struct uas_dev_info *devinfo = sdev->hostdata; scsi_set_tag_type(sdev, MSG_ORDERED_TAG); scsi_activate_tcq(sdev, devinfo->qdepth - 1); scsi_activate_tcq(sdev, devinfo->qdepth - 2); return 0; } Loading Loading @@ -619,6 +651,7 @@ static void uas_configure_endpoints(struct uas_dev_info *devinfo) unsigned i, n_endpoints = intf->cur_altsetting->desc.bNumEndpoints; devinfo->uas_sense_old = 0; devinfo->cmnd = NULL; for (i = 0; i < n_endpoints; i++) { unsigned char *extra = endpoint[i].extra; Loading Loading @@ -670,6 +703,40 @@ static void uas_configure_endpoints(struct uas_dev_info *devinfo) } } static int uas_alloc_status_urb(struct uas_dev_info *devinfo, struct Scsi_Host *shost) { if (devinfo->use_streams) { devinfo->status_urb = NULL; return 0; } devinfo->status_urb = uas_alloc_sense_urb(devinfo, GFP_KERNEL, shost, 0); if (!devinfo->status_urb) goto err_s_urb; if (usb_submit_urb(devinfo->status_urb, GFP_KERNEL)) goto err_submit_urb; return 0; err_submit_urb: usb_free_urb(devinfo->status_urb); err_s_urb: return -ENOMEM; } static void uas_free_streams(struct uas_dev_info *devinfo) { struct usb_device *udev = devinfo->udev; struct usb_host_endpoint *eps[3]; eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe); eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe); eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe); usb_free_streams(devinfo->intf, eps, 3, GFP_KERNEL); } /* * XXX: What I'd like to do here is register a SCSI host for each USB host in * the system. Follow usb-storage's design of registering a SCSI host for Loading Loading @@ -699,18 +766,33 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id) shost->max_id = 1; shost->sg_tablesize = udev->bus->sg_tablesize; result = scsi_add_host(shost, &intf->dev); devinfo->intf = intf; devinfo->udev = udev; uas_configure_endpoints(devinfo); result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2); if (result) goto free; result = scsi_add_host(shost, &intf->dev); if (result) goto deconfig_eps; shost->hostdata[0] = (unsigned long)devinfo; devinfo->intf = intf; devinfo->udev = udev; uas_configure_endpoints(devinfo); result = uas_alloc_status_urb(devinfo, shost); if (result) goto err_alloc_status; scsi_scan_host(shost); usb_set_intfdata(intf, shost); return result; err_alloc_status: scsi_remove_host(shost); shost = NULL; deconfig_eps: uas_free_streams(devinfo); free: kfree(devinfo); if (shost) Loading @@ -732,18 +814,13 @@ static int uas_post_reset(struct usb_interface *intf) static void uas_disconnect(struct usb_interface *intf) { struct usb_device *udev = interface_to_usbdev(intf); struct usb_host_endpoint *eps[3]; struct Scsi_Host *shost = usb_get_intfdata(intf); struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; scsi_remove_host(shost); eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe); eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe); eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe); usb_free_streams(intf, eps, 3, GFP_KERNEL); usb_kill_urb(devinfo->status_urb); usb_free_urb(devinfo->status_urb); uas_free_streams(devinfo); kfree(devinfo); } Loading