diff --git a/API-README b/API-README index 0898da0e..bf6e5208 100644 --- a/API-README +++ b/API-README @@ -277,13 +277,13 @@ The list of requests - a (*) means it requires privileged access - and replies: none There is no reply section just the STATUS section stating the results of the identify request This is only available if PGA mining is enabled - and currently only BFL singles support this - command + and currently only BFL singles and Cairnsmore1's + with the appropriate firmware support this command On a BFL single it will flash the led on the front of the device for appoximately 4s - All other non BFL PGA devices will return a + All other non BFL,ICA PGA devices will return a warning status message stating that they dont - support it + support it. Non-CMR ICAs will ignore the command. This adds a 4s delay to the BFL share being processed so you may get a message stating that procssing took longer than 7000ms if the request @@ -364,6 +364,7 @@ The list of requests - a (*) means it requires privileged access - and replies: The current options are: MMQ opt=clock val=160 to 230 (a multiple of 2) + CMR opt=clock val=100 to 220 zero|Which,true/false (*) none There is no reply section just the STATUS section @@ -433,8 +434,8 @@ The list of requests - a (*) means it requires privileged access - and replies: help message about the options available The current options are: - AVA+BTB opt=freq val=256 to 450 - chip frequency - BTB opt=millivolts val=1000 to 1310 - corevoltage + AVA+BTB opt=freq val=256 to 1024 - chip frequency + BTB opt=millivolts val=1000 to 1400 - corevoltage When you enable, disable or restart a GPU, PGA or ASC, you will also get Thread messages in the cgminer status window diff --git a/cgminer.c b/cgminer.c index 3cdaf02b..79fd2ec0 100644 --- a/cgminer.c +++ b/cgminer.c @@ -6254,7 +6254,8 @@ static void hash_sole_work(struct thr_info *mythr) applog(LOG_ERR, "%s %d failure, disabling!", drv->name, cgpu->device_id); cgpu->deven = DEV_DISABLED; dev_error(cgpu, REASON_THREAD_ZERO_HASH); - mt_disable(mythr, thr_id, drv); + cgpu->shutdown = true; + break; } hashes_done += hashes; diff --git a/driver-bitfury.c b/driver-bitfury.c index c1e3124d..0cb9fef5 100644 --- a/driver-bitfury.c +++ b/driver-bitfury.c @@ -15,6 +15,8 @@ /* Wait longer 1/3 longer than it would take for a full nonce range */ #define BF1WAIT 1600 +#define BF1MSGSIZE 7 +#define BF1INFOSIZE 14 static void bitfury_empty_buffer(struct cgpu_info *bitfury) { @@ -26,18 +28,29 @@ static void bitfury_empty_buffer(struct cgpu_info *bitfury) } while (amount); } -static void bitfury_open(struct cgpu_info *bitfury) +static int bitfury_open(struct cgpu_info *bitfury) { uint32_t buf[2]; + int err; bitfury_empty_buffer(bitfury); /* Magic sequence to reset device only really needed for windows but * harmless on linux. */ buf[0] = 0x80250000; buf[1] = 0x00000800; - usb_transfer(bitfury, 0, 9, 1, 0, C_BF1_RESET); - usb_transfer(bitfury, 0x21, 0x22, 0, 0, C_BF1_OPEN); - usb_transfer_data(bitfury, 0x21, 0x20, 0x0000, 0, buf, 7, C_BF1_INIT); + err = usb_transfer(bitfury, 0, 9, 1, 0, C_BF1_RESET); + if (!err) + err = usb_transfer(bitfury, 0x21, 0x22, 0, 0, C_BF1_OPEN); + if (!err) { + err = usb_transfer_data(bitfury, 0x21, 0x20, 0x0000, 0, buf, + BF1MSGSIZE, C_BF1_INIT); + } + + if (err < 0) { + applog(LOG_INFO, "%s %d: Failed to open with error %s", bitfury->drv->name, + bitfury->device_id, libusb_error_name(err)); + } + return (err == BF1MSGSIZE); } static void bitfury_close(struct cgpu_info *bitfury) @@ -63,15 +76,15 @@ static bool bitfury_getinfo(struct cgpu_info *bitfury, struct bitfury_info *info bitfury->drv->name, bitfury->device_id); return false; } - err = usb_read(bitfury, buf, 14, &amount, C_BF1_GETINFO); + err = usb_read(bitfury, buf, BF1INFOSIZE, &amount, C_BF1_GETINFO); if (err) { applog(LOG_INFO, "%s %d: Failed to read GETINFO", bitfury->drv->name, bitfury->device_id); return false; } - if (amount != 14) { - applog(LOG_INFO, "%s %d: Getinfo received %d bytes instead of 14", - bitfury->drv->name, bitfury->device_id, amount); + if (amount != BF1INFOSIZE) { + applog(LOG_INFO, "%s %d: Getinfo received %d bytes instead of %d", + bitfury->drv->name, bitfury->device_id, amount, BF1INFOSIZE); return false; } info->version = buf[1]; @@ -95,15 +108,16 @@ static bool bitfury_reset(struct cgpu_info *bitfury) bitfury->drv->name, bitfury->device_id); return false; } - err = usb_read_timeout(bitfury, buf, 7, &amount, BF1WAIT, C_BF1_GETRESET); + err = usb_read_timeout(bitfury, buf, BF1MSGSIZE, &amount, BF1WAIT, + C_BF1_GETRESET); if (err) { applog(LOG_INFO, "%s %d: Failed to read GETRESET", bitfury->drv->name, bitfury->device_id); return false; } - if (amount != 7) { - applog(LOG_INFO, "%s %d: Getreset received %d bytes instead of 7", - bitfury->drv->name, bitfury->device_id, amount); + if (amount != BF1MSGSIZE) { + applog(LOG_INFO, "%s %d: Getreset received %d bytes instead of %d", + bitfury->drv->name, bitfury->device_id, amount, BF1MSGSIZE); return false; } applog(LOG_DEBUG, "%s %d: Getreset returned %s", bitfury->drv->name, @@ -128,10 +142,14 @@ static bool bitfury_detect_one(struct libusb_device *dev, struct usb_find_device if (!info) quit(1, "Failed to calloc info in bitfury_detect_one"); bitfury->device_data = info; + /* This does not artificially raise hashrate, it simply allows the + * hashrate to adapt quickly on starting. */ + info->total_nonces = 1; usb_buffer_enable(bitfury); - bitfury_open(bitfury); + if (!bitfury_open(bitfury)) + goto out_close; /* Send getinfo request */ if (!bitfury_getinfo(bitfury, info)) @@ -145,7 +163,7 @@ static bool bitfury_detect_one(struct libusb_device *dev, struct usb_find_device bitfury_empty_buffer(bitfury); if (!add_cgpu(bitfury)) - goto out_close; + quit(1, "Failed to add_cgpu in bitfury_detect_one"); update_usb_stats(bitfury); applog(LOG_INFO, "%s %d: Successfully initialised %s", @@ -208,6 +226,8 @@ static int64_t bitfury_scanhash(struct thr_info *thr, struct work *work, struct cgpu_info *bitfury = thr->cgpu; struct bitfury_info *info = bitfury->device_data; struct timeval tv_now; + double nonce_rate; + int64_t ret = 0; int amount, i; char buf[45]; int ms_diff; @@ -235,7 +255,8 @@ static int64_t bitfury_scanhash(struct thr_info *thr, struct work *work, ms_diff = BF1WAIT - ms_tdiff(&tv_now, &info->tv_start); if (unlikely(ms_diff < 10)) ms_diff = 10; - usb_read_once_timeout(bitfury, info->buf + info->tot, 7, &amount, ms_diff, C_BF1_GETRES); + usb_read_once_timeout(bitfury, info->buf + info->tot, BF1MSGSIZE, + &amount, ms_diff, C_BF1_GETRES); info->tot += amount; while (amount) { usb_read_once_timeout(bitfury, info->buf + info->tot, 512, &amount, 10, C_BF1_GETRES); @@ -249,7 +270,7 @@ static int64_t bitfury_scanhash(struct thr_info *thr, struct work *work, usb_write(bitfury, buf, 45, &amount, C_BF1_REQWORK); cgtime(&info->tv_start); /* Get response acknowledging work */ - usb_read(bitfury, buf, 7, &amount, C_BF1_GETWORK); + usb_read(bitfury, buf, BF1MSGSIZE, &amount, C_BF1_GETWORK); /* Only happens on startup */ if (unlikely(!info->prevwork[BF1ARRAY_SIZE])) @@ -257,7 +278,7 @@ static int64_t bitfury_scanhash(struct thr_info *thr, struct work *work, /* Search for what work the nonce matches in order of likelihood. Last * entry is end of result marker. */ - for (i = 0; i < info->tot - 7; i += 7) { + for (i = 0; i < info->tot - BF1MSGSIZE; i += BF1MSGSIZE) { uint32_t nonce; int j; @@ -279,23 +300,30 @@ cascade: info->prevwork[i] = info->prevwork[i - 1]; info->prevwork[0] = copy_work(work); work->blk.nonce = 0xffffffff; - if (info->nonces) { - info->nonces--; - return (int64_t)0xffffffff; + + info->cycles++; + info->total_nonces += info->nonces; + info->saved_nonces += info->nonces; + info->nonces = 0; + nonce_rate = (double)info->total_nonces / (double)info->cycles; + if (info->saved_nonces >= nonce_rate) { + info->saved_nonces -= nonce_rate; + ret = (double)0xffffffff * nonce_rate; } if (unlikely(bitfury->usbinfo.nodev)) { applog(LOG_WARNING, "%s %d: Device disappeared, disabling thread", bitfury->drv->name, bitfury->device_id); - return -1; + ret = -1; } - return 0; + return ret; } static struct api_data *bitfury_api_stats(struct cgpu_info *cgpu) { struct bitfury_info *info = cgpu->device_data; struct api_data *root = NULL; + double nonce_rate; char serial[16]; int version; @@ -304,6 +332,8 @@ static struct api_data *bitfury_api_stats(struct cgpu_info *cgpu) root = api_add_string(root, "Product", info->product, false); sprintf(serial, "%08x", info->serial); root = api_add_string(root, "Serial", serial, true); + nonce_rate = (double)info->total_nonces / (double)info->cycles; + root = api_add_double(root, "NonceRate", &nonce_rate, true); return root; } diff --git a/driver-bitfury.h b/driver-bitfury.h index 9cbe4200..07e795f5 100644 --- a/driver-bitfury.h +++ b/driver-bitfury.h @@ -24,6 +24,9 @@ struct bitfury_info { char buf[512]; int tot; int nonces; + int total_nonces; + double saved_nonces; + int cycles; struct timeval tv_start; }; diff --git a/driver-icarus.c b/driver-icarus.c index bc56caad..2655c140 100644 --- a/driver-icarus.c +++ b/driver-icarus.c @@ -108,6 +108,8 @@ ASSERT1(sizeof(uint32_t) == 4); #define CAIRNSMORE2_HASH_TIME 0.0000000066600 #define NANOSEC 1000000000.0 +#define CAIRNSMORE2_INTS 4 + // Icarus Rev3 doesn't send a completion message when it finishes // the full nonce range, so to avoid being idle we must abort the // work (by starting a new work item) shortly before it finishes @@ -178,6 +180,7 @@ static const char *MODE_VALUE_STR = "value"; static const char *MODE_UNKNOWN_STR = "unknown"; struct ICARUS_INFO { + enum sub_ident ident; int intinfo; // time to calculate the golden_ob @@ -216,17 +219,43 @@ struct ICARUS_INFO { int fpga_count; uint32_t nonce_mask; - bool initialised; + uint8_t cmr2_speed; + bool speed_next_work; + bool flash_next_work; }; #define ICARUS_MIDSTATE_SIZE 32 -#define ICARUS_UNUSED_SIZE 20 +#define ICARUS_UNUSED_SIZE 16 #define ICARUS_WORK_SIZE 12 #define ICARUS_WORK_DATA_OFFSET 64 +#define ICARUS_CMR2_SPEED_FACTOR 2.5 +#define ICARUS_CMR2_SPEED_MIN_INT 100 +#define ICARUS_CMR2_SPEED_DEF_INT 180 +#define ICARUS_CMR2_SPEED_MAX_INT 220 +#define CMR2_INT_TO_SPEED(_speed) ((uint8_t)((float)_speed / ICARUS_CMR2_SPEED_FACTOR)) +#define ICARUS_CMR2_SPEED_MIN CMR2_INT_TO_SPEED(ICARUS_CMR2_SPEED_MIN_INT) +#define ICARUS_CMR2_SPEED_DEF CMR2_INT_TO_SPEED(ICARUS_CMR2_SPEED_DEF_INT) +#define ICARUS_CMR2_SPEED_MAX CMR2_INT_TO_SPEED(ICARUS_CMR2_SPEED_MAX_INT) +#define ICARUS_CMR2_SPEED_INC 1 +#define ICARUS_CMR2_SPEED_DEC -1 +#define ICARUS_CMR2_SPEED_FAIL -10 + +#define ICARUS_CMR2_PREFIX ((uint8_t)0xB7) +#define ICARUS_CMR2_CMD_SPEED ((uint8_t)0) +#define ICARUS_CMR2_CMD_FLASH ((uint8_t)1) +#define ICARUS_CMR2_DATA_FLASH_OFF ((uint8_t)0) +#define ICARUS_CMR2_DATA_FLASH_ON ((uint8_t)1) +#define ICARUS_CMR2_CHECK ((uint8_t)0x6D) + struct ICARUS_WORK { uint8_t midstate[ICARUS_MIDSTATE_SIZE]; + // These 4 bytes are for CMR2 bitstreams that handle MHz adjustment + uint8_t check; + uint8_t data; + uint8_t cmd; + uint8_t prefix; uint8_t unused[ICARUS_UNUSED_SIZE]; uint8_t work[ICARUS_WORK_SIZE]; }; @@ -423,8 +452,6 @@ static void icarus_initialise(struct cgpu_info *icarus, int baud) quit(1, "icarus_intialise() called with invalid %s cgid %i ident=%d", icarus->drv->name, icarus->cgminer_id, ident); } - - info->initialised = true; } static void rev(unsigned char *s, size_t l) @@ -820,9 +847,10 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices char *nonce_hex; int baud, uninitialised_var(work_division), uninitialised_var(fpga_count); struct cgpu_info *icarus; - int ret, err, amount, tries; - enum sub_ident ident; + int ret, err, amount, tries, i; bool ok; + bool cmr2_ok[CAIRNSMORE2_INTS]; + int cmr2_count; if ((sizeof(workdata) << 1) != (sizeof(golden_ob) - 1)) quithere(1, "Data and golden_ob sizes don't match"); @@ -843,8 +871,8 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices quit(1, "Failed to malloc ICARUS_INFO"); icarus->device_data = (void *)info; - ident = usb_ident(icarus); - switch (ident) { + info->ident = usb_ident(icarus); + switch (info->ident) { case IDENT_ICA: case IDENT_BLT: case IDENT_LLT: @@ -853,19 +881,32 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices info->timeout = ICARUS_WAIT_TIMEOUT; break; case IDENT_CMR2: + if (found->intinfo_count != CAIRNSMORE2_INTS) { + quithere(1, "CMR2 Interface count (%d) isn't expected: %d", + found->intinfo_count, + CAIRNSMORE2_INTS); + } info->timeout = ICARUS_CMR2_TIMEOUT; + cmr2_count = 0; + for (i = 0; i < CAIRNSMORE2_INTS; i++) + cmr2_ok[i] = false; break; default: quit(1, "%s icarus_detect_one() invalid %s ident=%d", - icarus->drv->dname, icarus->drv->dname, ident); + icarus->drv->dname, icarus->drv->dname, info->ident); } +// For CMR2 test each USB Interface + +cmr2_retry: + tries = 2; ok = false; while (!ok && tries-- > 0) { icarus_initialise(icarus, baud); - err = usb_write(icarus, (void *)(&workdata), sizeof(workdata), &amount, C_SENDTESTWORK); + err = usb_write_ii(icarus, info->intinfo, + (char *)(&workdata), sizeof(workdata), &amount, C_SENDWORK); if (err != LIBUSB_SUCCESS || amount != sizeof(workdata)) continue; @@ -879,7 +920,7 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices if (strncmp(nonce_hex, golden_nonce, 8) == 0) ok = true; else { - if (tries < 0) { + if (tries < 0 && info->ident != IDENT_CMR2) { applog(LOG_ERR, "Icarus Detect: " "Test failed at %s: get %s, should: %s", @@ -889,13 +930,50 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices free(nonce_hex); } - if (!ok) - goto unshin; + if (!ok) { + if (info->ident != IDENT_CMR2) + goto unshin; + + if (info->intinfo < CAIRNSMORE2_INTS-1) { + info->intinfo++; + goto cmr2_retry; + } + } else { + if (info->ident == IDENT_CMR2) { + applog(LOG_DEBUG, + "Icarus Detect: " + "Test succeeded at %s i%d: got %s", + icarus->device_path, info->intinfo, golden_nonce); + + cmr2_ok[info->intinfo] = true; + cmr2_count++; + if (info->intinfo < CAIRNSMORE2_INTS-1) { + info->intinfo++; + goto cmr2_retry; + } + } + } - applog(LOG_DEBUG, - "Icarus Detect: " - "Test succeeded at %s: got %s", - icarus->device_path, golden_nonce); + if (info->ident == IDENT_CMR2) { + if (cmr2_count == 0) { + applog(LOG_ERR, + "Icarus Detect: Test failed at %s: for all %d CMR2 Interfaces", + icarus->device_path, CAIRNSMORE2_INTS); + goto unshin; + } + + // set the interface to the first one that succeeded + for (i = 0; i < CAIRNSMORE2_INTS; i++) + if (cmr2_ok[i]) { + info->intinfo = i; + break; + } + } else { + applog(LOG_DEBUG, + "Icarus Detect: " + "Test succeeded at %s: got %s", + icarus->device_path, golden_nonce); + } /* We have a real Icarus! */ if (!add_cgpu(icarus)) @@ -906,6 +984,18 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices applog(LOG_INFO, "%s%d: Found at %s", icarus->drv->name, icarus->device_id, icarus->device_path); + if (info->ident == IDENT_CMR2) { + applog(LOG_INFO, "%s%d: with %d Interface%s", + icarus->drv->name, icarus->device_id, + cmr2_count, cmr2_count > 1 ? "s" : ""); + + // Assume 1 or 2 are running FPGA pairs + if (cmr2_count < 3) { + work_division = fpga_count = 2; + info->Hs /= 2; + } + } + applog(LOG_DEBUG, "%s%d: Init baud=%d work_division=%d fpga_count=%d", icarus->drv->name, icarus->device_id, baud, work_division, fpga_count); @@ -919,12 +1009,15 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices set_timing_mode(this_option_offset, icarus); - if (usb_ident(icarus) == IDENT_CMR2) { + if (info->ident == IDENT_CMR2) { int i; - for (i = 1; i < icarus->usbdev->found->intinfo_count; i++) { + for (i = info->intinfo + 1; i < icarus->usbdev->found->intinfo_count; i++) { struct cgpu_info *cgtmp; struct ICARUS_INFO *intmp; + if (!cmr2_ok[i]) + continue; + cgtmp = usb_copy_cgpu(icarus); if (!cgtmp) { applog(LOG_ERR, "%s%d: Init failed initinfo %d", @@ -984,6 +1077,45 @@ static bool icarus_prepare(__maybe_unused struct thr_info *thr) return true; } +static void cmr2_command(struct cgpu_info *icarus, uint8_t cmd, uint8_t data) +{ + struct ICARUS_INFO *info = (struct ICARUS_INFO *)(icarus->device_data); + struct ICARUS_WORK workdata; + int amount; + + memset((void *)(&workdata), 0, sizeof(workdata)); + + workdata.prefix = ICARUS_CMR2_PREFIX; + workdata.cmd = cmd; + workdata.data = data; + workdata.check = workdata.data ^ workdata.cmd ^ workdata.prefix ^ ICARUS_CMR2_CHECK; + + usb_write_ii(icarus, info->intinfo, (char *)(&workdata), sizeof(workdata), &amount, C_SENDWORK); +} + +static void cmr2_commands(struct cgpu_info *icarus) +{ + struct ICARUS_INFO *info = (struct ICARUS_INFO *)(icarus->device_data); + + if (info->speed_next_work) { + info->speed_next_work = false; + cmr2_command(icarus, ICARUS_CMR2_CMD_SPEED, info->cmr2_speed); + return; + } + + if (info->flash_next_work) { + info->flash_next_work = false; + cmr2_command(icarus, ICARUS_CMR2_CMD_FLASH, ICARUS_CMR2_DATA_FLASH_ON); + cgsleep_ms(250); + cmr2_command(icarus, ICARUS_CMR2_CMD_FLASH, ICARUS_CMR2_DATA_FLASH_OFF); + cgsleep_ms(250); + cmr2_command(icarus, ICARUS_CMR2_CMD_FLASH, ICARUS_CMR2_DATA_FLASH_ON); + cgsleep_ms(250); + cmr2_command(icarus, ICARUS_CMR2_CMD_FLASH, ICARUS_CMR2_DATA_FLASH_OFF); + return; + } +} + static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, __maybe_unused int64_t max_nonce) { @@ -1014,9 +1146,6 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, if (icarus->usbinfo.nodev) return -1; - if (!info->initialised) - icarus_initialise(icarus, info->baud); - elapsed.tv_sec = elapsed.tv_usec = 0; memset((void *)(&workdata), 0, sizeof(workdata)); @@ -1025,6 +1154,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, rev((void *)(&(workdata.midstate)), ICARUS_MIDSTATE_SIZE); rev((void *)(&(workdata.work)), ICARUS_WORK_SIZE); + if (info->speed_next_work || info->flash_next_work) + cmr2_commands(icarus); + // We only want results for the work we are about to send usb_buffer_clear(icarus); @@ -1245,17 +1377,80 @@ static struct api_data *icarus_api_stats(struct cgpu_info *cgpu) return root; } +static void icarus_statline_before(char *buf, size_t bufsiz, struct cgpu_info *cgpu) +{ + struct ICARUS_INFO *info = (struct ICARUS_INFO *)(cgpu->device_data); + + if (info->ident == IDENT_CMR2 && info->cmr2_speed > 0) + tailsprintf(buf, bufsiz, "%5.1fMhz", (float)(info->cmr2_speed) * ICARUS_CMR2_SPEED_FACTOR); + else + tailsprintf(buf, bufsiz, " "); + + tailsprintf(buf, bufsiz, " | "); +} + static void icarus_shutdown(__maybe_unused struct thr_info *thr) { // TODO: ? } +static void icarus_identify(struct cgpu_info *cgpu) +{ + struct ICARUS_INFO *info = (struct ICARUS_INFO *)(cgpu->device_data); + + if (info->ident == IDENT_CMR2) + info->flash_next_work = true; +} + +static char *icarus_set(struct cgpu_info *cgpu, char *option, char *setting, char *replybuf) +{ + struct ICARUS_INFO *info = (struct ICARUS_INFO *)(cgpu->device_data); + int val; + + if (info->ident != IDENT_CMR2) { + strcpy(replybuf, "no set options available"); + return replybuf; + } + + if (strcasecmp(option, "help") == 0) { + sprintf(replybuf, "clock: range %d-%d", + ICARUS_CMR2_SPEED_MIN_INT, ICARUS_CMR2_SPEED_MAX_INT); + return replybuf; + } + + if (strcasecmp(option, "clock") == 0) { + if (!setting || !*setting) { + sprintf(replybuf, "missing clock setting"); + return replybuf; + } + + val = atoi(setting); + if (val < ICARUS_CMR2_SPEED_MIN_INT || val > ICARUS_CMR2_SPEED_MAX_INT) { + sprintf(replybuf, "invalid clock: '%s' valid range %d-%d", + setting, + ICARUS_CMR2_SPEED_MIN_INT, + ICARUS_CMR2_SPEED_MAX_INT); + } + + info->cmr2_speed = CMR2_INT_TO_SPEED(val); + info->speed_next_work = true; + + return NULL; + } + + sprintf(replybuf, "Unknown option: %s", option); + return replybuf; +} + struct device_drv icarus_drv = { .drv_id = DRIVER_icarus, .dname = "Icarus", .name = "ICA", .drv_detect = icarus_detect, .get_api_stats = icarus_api_stats, + .get_statline_before = icarus_statline_before, + .set_device = icarus_set, + .identify_device = icarus_identify, .thread_prepare = icarus_prepare, .scanhash = icarus_scanhash, .thread_shutdown = icarus_shutdown, diff --git a/usbutils.c b/usbutils.c index 41f77d46..163906de 100644 --- a/usbutils.c +++ b/usbutils.c @@ -2598,11 +2598,9 @@ out_noerrmsg: if (NODEV(err)) { cg_ruwlock(&cgpu->usbinfo.devlock); release_cgpu(cgpu); - cg_dwlock(&cgpu->usbinfo.devlock); - } - - DEVRUNLOCK(cgpu, pstate); - + DEVWUNLOCK(cgpu, pstate); + } else + DEVRUNLOCK(cgpu, pstate); return err; } @@ -2700,10 +2698,9 @@ out_noerrmsg: if (NODEV(err)) { cg_ruwlock(&cgpu->usbinfo.devlock); release_cgpu(cgpu); - cg_dwlock(&cgpu->usbinfo.devlock); - } - - DEVRUNLOCK(cgpu, pstate); + DEVWUNLOCK(cgpu, pstate); + } else + DEVRUNLOCK(cgpu, pstate); return err; } @@ -3197,7 +3194,7 @@ void usb_cleanup(void) cgsem_destroy(&usb_resource_sem); } -#define DRIVER_COUNT_FOUND(X) if (strcasecmp(ptr, X##_drv.name) == 0) { \ +#define DRIVER_COUNT_FOUND(X) if (X##_drv.name && strcasecmp(ptr, X##_drv.name) == 0) { \ drv_count[X##_drv.drv_id].limit = lim; \ found = true; \ }