diff --git a/usbutils.c b/usbutils.c index af35d4e3..0a289256 100644 --- a/usbutils.c +++ b/usbutils.c @@ -1379,7 +1379,8 @@ static struct cg_usb_device *free_cgusb(struct cg_usb_device *cgusb) if (cgusb->prod_string && cgusb->prod_string != BLANK) free(cgusb->prod_string); - free(cgusb->descriptor); + if (cgusb->descriptor) + free(cgusb->descriptor); free(cgusb->found); @@ -1391,7 +1392,7 @@ static struct cg_usb_device *free_cgusb(struct cg_usb_device *cgusb) return NULL; } -void _usb_uninit(struct cgpu_info *cgpu) +static void _usb_uninit(struct cgpu_info *cgpu) { applog(LOG_DEBUG, "USB uninit %s%i", cgpu->drv->name, cgpu->device_id); @@ -1400,18 +1401,12 @@ void _usb_uninit(struct cgpu_info *cgpu) // if release_cgpu() was called due to a USB NODEV(err) if (!cgpu->usbdev) return; + if (cgpu->usbdev->handle) { - int ifinfo = 0; - while (cgpu->usbdev->claimed > 0) { - libusb_release_interface(cgpu->usbdev->handle, - cgpu->usbdev->found->intinfos[ifinfo].interface); - ifinfo++; - cgpu->usbdev->claimed--; - } + libusb_release_interface(cgpu->usbdev->handle, USBIF(cgpu->usbdev)); cg_wlock(&cgusb_fd_lock); libusb_close(cgpu->usbdev->handle); cgpu->usbdev->handle = NULL; - cgpu->usbdev->claimed = 0; cg_wunlock(&cgusb_fd_lock); } cgpu->usbdev = free_cgusb(cgpu->usbdev); @@ -1474,11 +1469,16 @@ static void release_cgpu(struct cgpu_info *cgpu) cgminer_usb_unlock_bd(cgpu->drv, cgpu->usbinfo.bus_number, cgpu->usbinfo.device_address); } -// Currently only used by MMQ +// Used by MMQ - use the same usbdev thus locking is across all 4 related devices +// since they must use the same USB handle since they use the same interface struct cgpu_info *usb_copy_cgpu(struct cgpu_info *orig) { - struct cgpu_info *copy = calloc(1, sizeof(*copy)); + struct cgpu_info *copy; + int pstate; + DEVLOCK(orig, pstate); + + copy = calloc(1, sizeof(*copy)); if (unlikely(!copy)) quit(1, "Failed to calloc cgpu for %s in usb_copy_cgpu", orig->drv->dname); @@ -1495,6 +1495,70 @@ struct cgpu_info *usb_copy_cgpu(struct cgpu_info *orig) copy->usbinfo.devlock = orig->usbinfo.devlock; + DEVUNLOCK(orig, pstate); + + return copy; +} + +// Used by CMR - use a different usbdev - since they must use a different +// USB handle due to using different interfaces (libusb requirement) +static struct cgpu_info *usb_dup_cgpu(struct cgpu_info *orig, int intinfo) +{ + struct cgpu_info *copy; + + copy = calloc(1, sizeof(*copy)); + if (unlikely(!copy)) + quit(1, "Failed to calloc cgpu for %s in usb_dup_cgpu", orig->drv->dname); + + copy->name = orig->name; + copy->drv = copy_drv(orig->drv); + copy->deven = orig->deven; + copy->threads = orig->threads; + + if (orig->usbdev) { + copy->usbdev = calloc(1, sizeof(*(copy->usbdev))); + if (unlikely(!copy->usbdev)) + quit(1, "Failed to calloc usbdev for %s in usb_dup_cgpu", orig->drv->dname); + + copy->usbdev->found = malloc(sizeof(*(copy->usbdev->found))); + if (unlikely(!copy->usbdev->found)) + quit(1, "Failed to malloc found for %s in usb_dup_cgpu", orig->drv->dname); + memcpy(copy->usbdev->found, orig->usbdev->found, sizeof(*(copy->usbdev->found))); + + copy->usbdev->found->which_intinfo = intinfo; + + copy->usbdev->descriptor = NULL; // don't need it + copy->usbdev->usb_type = orig->usbdev->usb_type; + copy->usbdev->ident = orig->usbdev->ident; + copy->usbdev->usbver = orig->usbdev->usbver; + copy->usbdev->cps = orig->usbdev->cps; + copy->usbdev->usecps = orig->usbdev->usecps; + if (orig->usbdev->prod_string == BLANK) + copy->usbdev->prod_string = (char *)BLANK; + else + copy->usbdev->prod_string = strdup(orig->usbdev->prod_string); + if (orig->usbdev->manuf_string == BLANK) + copy->usbdev->manuf_string = (char *)BLANK; + else + copy->usbdev->manuf_string = strdup(orig->usbdev->manuf_string); + if (orig->usbdev->serial_string == BLANK) + copy->usbdev->serial_string = (char *)BLANK; + else + copy->usbdev->serial_string = strdup(orig->usbdev->serial_string); + copy->usbdev->fwVersion = orig->usbdev->fwVersion; + copy->usbdev->interfaceVersion = orig->usbdev->interfaceVersion; + } + + memcpy(&(copy->usbinfo), &(orig->usbinfo), sizeof(copy->usbinfo)); + + copy->usbinfo.nodev = (copy->usbdev == NULL); + + copy->usbinfo.devlock = calloc(1, sizeof(*(copy->usbinfo.devlock))); + if (unlikely(!copy->usbinfo.devlock)) + quit(1, "Failed to calloc devlock for %s in usb_dup_cgpu", orig->drv->dname); + + rwlock_init(copy->usbinfo.devlock); + return copy; } @@ -1616,22 +1680,18 @@ static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct u } #ifndef WIN32 - for (ifinfo = 0; ifinfo < found->intinfo_count; ifinfo++) { - int interface = found->intinfos[ifinfo].interface; - - if (libusb_kernel_driver_active(cgusb->handle, interface) == 1) { - applog(LOG_DEBUG, "USB init, kernel attached ... %s", devstr); - err = libusb_detach_kernel_driver(cgusb->handle, interface); - if (err == 0) { - applog(LOG_DEBUG, - "USB init, kernel detached interface %d successfully %s", - interface, devstr); - } else { - applog(LOG_WARNING, - "USB init, kernel detach interface %d failed, err %d in use? %s", - interface, err, devstr); - goto cldame; - } + if (libusb_kernel_driver_active(cgusb->handle, FOUNDIF(found)) == 1) { + applog(LOG_DEBUG, "USB init, kernel attached ... %s", devstr); + err = libusb_detach_kernel_driver(cgusb->handle, FOUNDIF(found)); + if (err == 0) { + applog(LOG_DEBUG, + "USB init, kernel detached interface %d successfully %s", + FOUNDIF(found), devstr); + } else { + applog(LOG_WARNING, + "USB init, kernel detach interface %d failed, err %d in use? %s", + FOUNDIF(found), err, devstr); + goto cldame; } } #endif @@ -1754,25 +1814,20 @@ static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct u goto cldame; } - cgusb->claimed = 0; - for (ifinfo = 0; ifinfo < found->intinfo_count; ifinfo++) { - int interface = found->intinfos[ifinfo].interface; - err = libusb_claim_interface(cgusb->handle, interface); - if (err) { - switch(err) { - case LIBUSB_ERROR_BUSY: - applog(LOG_WARNING, - "USB init, claim interface %d in use %s", - interface, devstr); - break; - default: - applog(LOG_DEBUG, - "USB init, claim interface %d failed, err %d %s", - interface, err, devstr); - } - goto reldame; + err = libusb_claim_interface(cgusb->handle, FOUNDIF(found)); + if (err) { + switch(err) { + case LIBUSB_ERROR_BUSY: + applog(LOG_WARNING, + "USB init, claim interface %d in use %s", + FOUNDIF(found), devstr); + break; + default: + applog(LOG_DEBUG, + "USB init, claim interface %d failed, err %d %s", + FOUNDIF(found), err, devstr); } - cgusb->claimed++; + goto reldame; } cfg = -1; @@ -1839,19 +1894,13 @@ static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct u reldame: - ifinfo = 0; - while (cgusb->claimed > 0) { - libusb_release_interface(cgusb->handle, found->intinfos[ifinfo].interface); - ifinfo++; - cgusb->claimed--; - } + libusb_release_interface(cgusb->handle, FOUNDIF(found)); cldame: cg_wlock(&cgusb_fd_lock); libusb_close(cgusb->handle); cgusb->handle = NULL; - cgusb->claimed = 0; cg_wunlock(&cgusb_fd_lock); dame: @@ -1867,6 +1916,144 @@ out_unlock: return bad; } +// To get the extra interfaces on a multi interface device +struct cgpu_info *usb_init_intinfo(struct cgpu_info *orig, int intinfo) +{ + struct usb_find_devices *found; + struct libusb_device *dev; + struct cgpu_info *copy = NULL; + char msgstr[STRBUFLEN+1]; + char devstr[STRBUFLEN+1]; + char devpath[32]; + int err, pstate; + + DEVLOCK(orig, pstate); + + snprintf(msgstr, sizeof(msgstr), "USB %s init_intinfo (%d:%d:ii%d)", + orig->drv->dname, + (int)(orig->usbinfo.bus_number), + (int)(orig->usbinfo.device_address), + orig->usbdev->found->which_intinfo); + + if (orig->usbinfo.nodev) { + applog(LOG_ERR, "%s cgpu has nodev", msgstr); + goto Hitagi; + } + + if (orig->usbdev->found->which_intinfo != 0) { + applog(LOG_ERR, "%s incorrect cgpu (must be ii0)", msgstr); + goto Hitagi; + } + + if (orig->usbdev->found->intinfo_count < 2) { + applog(LOG_ERR, "%s cgpu only has 1 interface", msgstr); + goto Hitagi; + } + + if (intinfo < 1 || intinfo >= orig->usbdev->found->intinfo_count) { + applog(LOG_ERR, "%s invalid intinfo (%d) must be > 0 && < %d", + msgstr, intinfo, orig->usbdev->found->intinfo_count); + goto Hitagi; + } + + dev = libusb_get_device(orig->usbdev->handle); + + copy = usb_dup_cgpu(orig, intinfo); + if (!copy) + goto Hitagi; + + found = copy->usbdev->found; + + snprintf(devpath, sizeof(devpath), "%d:%d:%d", + (int)(copy->usbinfo.bus_number), + (int)(copy->usbinfo.device_address), + intinfo); + + copy->device_path = strdup(devpath); + + snprintf(devstr, sizeof(devstr), "- %s device %s", found->name, devpath); + + cg_wlock(&cgusb_fd_lock); + err = libusb_open(dev, &(copy->usbdev->handle)); + cg_wunlock(&cgusb_fd_lock); + if (err) { + switch (err) { + case LIBUSB_ERROR_ACCESS: + applog(LOG_ERR, + "USB init_intinfo, open device failed, err %d, " + "you don't have privilege to access %s", + err, devstr); + break; +#ifdef WIN32 + // Windows specific message + case LIBUSB_ERROR_NOT_SUPPORTED: + applog(LOG_ERR, + "USB init_intinfo, open device failed, err %d, " + "you need to install a WinUSB driver for %s", + err, devstr); + break; +#endif + default: + applog(LOG_DEBUG, + "USB init_intinfo, open failed, err %d %s", + err, devstr); + } + goto Hitagi; + } + +#ifndef WIN32 + if (libusb_kernel_driver_active(copy->usbdev->handle, FOUNDIF(found)) == 1) { + applog(LOG_DEBUG, "USB init_intinfo, kernel attached ... %s", devstr); + err = libusb_detach_kernel_driver(copy->usbdev->handle, FOUNDIF(found)); + if (err == 0) { + applog(LOG_DEBUG, + "USB init_intinfo, kernel detached interface %d successfully %s", + FOUNDIF(found), devstr); + } else { + applog(LOG_WARNING, + "USB init_intinfo, kernel detach interface %d failed, err %d in use? %s", + FOUNDIF(found), err, devstr); + goto HitagiClose; + } + } +#endif + + err = libusb_claim_interface(copy->usbdev->handle, FOUNDIF(found)); + if (err) { + switch(err) { + case LIBUSB_ERROR_BUSY: + applog(LOG_WARNING, + "USB init_intinfo, claim interface %d in use %s", + FOUNDIF(found), devstr); + break; + default: + applog(LOG_DEBUG, + "USB init_intinfo, claim interface %d failed, err %d %s", + FOUNDIF(found), err, devstr); + } + goto HitagiClose; + } + + goto Hitagi; + +HitagiClose: + + cg_wlock(&cgusb_fd_lock); + libusb_close(copy->usbdev->handle); + copy->usbdev->handle = NULL; + cg_wunlock(&cgusb_fd_lock); + + copy->usbdev = free_cgusb(copy->usbdev); + + copy = usb_free_cgpu(copy); + +Hitagi: + + DEVUNLOCK(orig, pstate); + + return copy; +} + bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found_match) { struct usb_find_devices *found_use = NULL; diff --git a/usbutils.h b/usbutils.h index a68f899c..0abb05d7 100644 --- a/usbutils.h +++ b/usbutils.h @@ -177,7 +177,6 @@ enum usb_types { struct cg_usb_device { struct usb_find_devices *found; libusb_device_handle *handle; - int claimed; pthread_mutex_t *mutex; struct libusb_device_descriptor *descriptor; enum usb_types usb_type; @@ -336,6 +335,7 @@ struct cgpu_info *usb_alloc_cgpu(struct device_drv *drv, int threads); struct cgpu_info *usb_free_cgpu_devlock(struct cgpu_info *cgpu, bool free_devlock); #define usb_free_cgpu(cgpu) usb_free_cgpu_devlock(cgpu, true) void usb_uninit(struct cgpu_info *cgpu); +struct cgpu_info *usb_init_intinfo(struct cgpu_info *orig, int intinfo); bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found); void usb_detect(struct device_drv *drv, bool (*device_detect)(struct libusb_device *, struct usb_find_devices *)); struct api_data *api_usb_stats(int *count);