static bool hfa_get_header(struct cgpu_info *hashfast, struct hf_header *h, uint8_t *computed_crc) { int amount, ret, orig_len, len, ofs = 0; cgtimer_t ts_start; char buf[512]; char *header; orig_len = len = sizeof(*h); /* Read for up to 200ms till we find the first occurrence of HF_PREAMBLE * though it should be the first byte unless we get woefully out of * sync. */ cgtimer_time(&ts_start); do { cgtimer_t ts_now, ts_diff; cgtimer_time(&ts_now); cgtimer_sub(&ts_now, &ts_start, &ts_diff); if (cgtimer_to_ms(&ts_diff) > 200) return false; ret = usb_read(hashfast, buf + ofs, len, &amount, C_HF_GETHEADER); if (unlikely(ret && ret != LIBUSB_ERROR_TIMEOUT)) return false; ofs += amount; header = memchr(buf, HF_PREAMBLE, ofs); if (header) len -= ofs - (header - buf); } while (len); memcpy(h, header, orig_len); *computed_crc = hfa_crc8((uint8_t *)h); return true; }
static bool gridseed_prepare(struct thr_info *thr) { struct cgpu_info *gridseed = thr->cgpu; GRIDSEED_INFO *info = gridseed->device_data; info->thr = thr; mutex_init(&info->lock); mutex_init(&info->qlock); info->queued = 0; info->dev_queue_len = GRIDSEED_MCU_QUEUE_LEN; info->soft_queue_len = 0; info->query_qlen = false; info->needworks = 0; memset(&info->workqueue, 0, sizeof(struct work *)*GRIDSEED_SOFT_QUEUE_LEN); cgtimer_time(&info->query_ts); info->workdone = 0; if (info->sockltc > 0) close(info->sockltc); info->sockltc = -1; if (pthread_create(&info->th_read, NULL, gridseed_get_results, (void*)gridseed)) quit(1, "Failed to create GridSeed read thread"); if (pthread_create(&info->th_send, NULL, gridseed_send_command, (void*)gridseed)) quit(1, "Failed to create GridSeed send thread"); gridseed_create_proxy(gridseed, info); gridseed_request_ltc_task(gridseed, info); applog(LOG_NOTICE, "GridSeed device opened on %s", gridseed->device_path); return true; }
static void gridseed_get_queue_length(struct cgpu_info *gridseed, GRIDSEED_INFO *info, unsigned char *data) { uint32_t qlen; memcpy(&qlen, data+8, 4); qlen = htole32(qlen); mutex_lock(&info->qlock); info->query_qlen = false; info->dev_queue_len = GRIDSEED_MCU_QUEUE_LEN - qlen; info->needworks = qlen; cgtimer_time(&info->query_ts); mutex_unlock(&info->qlock); return; }
static bool gridseed_send_query_cmd(struct cgpu_info *gridseed, GRIDSEED_INFO *info) { unsigned char *cmd = "\x55\xaa\xc0\x00\xa0\xa0\xa0\xa0\x00\x00\x00\x00\x01\x00\x00\x00"; cgtimer_t ts_now, ts_res; bool ret = false; cgtimer_time(&ts_now); mutex_lock(&info->qlock); if (!info->query_qlen) { cgtimer_sub(&ts_now, &info->query_ts, &ts_res); #ifndef WIN32 if (ts_res.tv_sec > 0) { #else if (ts_res.QuadPart > 10000000) { #endif if (gc3355_write_data(gridseed, cmd, 16) == 0) { info->query_qlen = true; ret = true; } } } mutex_unlock(&info->qlock); return ret; } static bool gridseed_send_task(struct cgpu_info *gridseed, GRIDSEED_INFO *info, struct work *work) { unsigned char cmd[52]; memcpy(cmd, "\x55\xaa\x0f\x01", 4); memcpy(cmd+4, work->midstate, 32); memcpy(cmd+36, work->data+64, 12); memcpy(cmd+48, &(work->id), 4); return (gc3355_write_data(gridseed, cmd, sizeof(cmd)) == 0); }
static bool gridseed_check_new_task(struct cgpu_info *gridseed, GRIDSEED_INFO *info) { cgtimer_t ts_now, ts_res; bool ret = false; cgtimer_time(&ts_now); mutex_lock(&info->qlock); cgtimer_sub(&ts_now, &info->query_ts, &ts_res); #ifndef WIN32 if (ts_res.tv_sec > 0 || ts_res.tv_nsec > 350000000) { #else if (ts_res.QuadPart > 3500000) { #endif info->query_qlen = false; info->dev_queue_len = 1; info->needworks = 1; cgtimer_time(&info->query_ts); } mutex_unlock(&info->qlock); } /* * Thread to read response from Miner device */ static void *gridseed_get_results(void *userdata) { struct cgpu_info *gridseed = (struct cgpu_info *)userdata; GRIDSEED_INFO *info = gridseed->device_data; struct thr_info *thr = info->thr; char threadname[24]; unsigned char readbuf[GRIDSEED_READBUF_SIZE]; int offset = 0, ret; snprintf(threadname, sizeof(threadname), "GridSeed_Recv/%d", gridseed->device_id); RenameThread(threadname); applog(LOG_NOTICE, "GridSeed: recv thread running, %s", threadname); while(likely(!gridseed->shutdown)) { unsigned char buf[GRIDSEED_READ_SIZE]; if (offset >= GRIDSEED_READ_SIZE) gridseed_parse_results(gridseed, info, thr, readbuf, &offset); if (unlikely(offset + GRIDSEED_READ_SIZE >= GRIDSEED_READBUF_SIZE)) { applog(LOG_ERR, "Read buffer overflow, resetting %d", gridseed->device_id); offset = 0; } ret = gc3355_get_data(gridseed, buf, sizeof(buf)); if (ret == LIBUSB_ERROR_NO_DEVICE) gridseed->shutdown = true; if (unlikely(ret != 0)) continue; if (opt_debug) { applog(LOG_DEBUG, "GridSeed: get %d bytes", GRIDSEED_READ_SIZE); hexdump((uint8_t *)buf, GRIDSEED_READ_SIZE); } memcpy(readbuf + offset, buf, GRIDSEED_READ_SIZE); offset += GRIDSEED_READ_SIZE; } return NULL; } /* * Thread to send task and queue length query command to device */ static void *gridseed_send_command(void *userdata) { struct cgpu_info *gridseed = (struct cgpu_info *)userdata; GRIDSEED_INFO *info = gridseed->device_data; char threadname[24]; int i; snprintf(threadname, sizeof(threadname), "GridSeed_Send/%d", gridseed->device_id); RenameThread(threadname); applog(LOG_NOTICE, "GridSeed: send thread running, %s", threadname); while(likely(!gridseed->shutdown)) { cgsleep_ms(10); if (info->usefifo == 0) { /* mark the first work in queue as complete after several ms */ if (gridseed_check_new_task(gridseed, info)) continue; } else { /* send query command to device */ if (gridseed_send_query_cmd(gridseed, info)) continue; } /* send task to device */ mutex_lock(&info->qlock); for(i=0; i<info->soft_queue_len; i++) { if (info->workqueue[i] && info->workqueue[i]->devflag == false) { if (gridseed_send_task(gridseed, info, info->workqueue[i])) { info->workqueue[i]->devflag = true; break; } } } mutex_unlock(&info->qlock); /* recv LTC task and send to device */ gridseed_recv_ltc(gridseed, info); } return NULL; } /*========== functions for struct device_drv ===========*/ static void gridseed_detect(bool __maybe_unused hotplug) { usb_detect(&gridseed_drv, gridseed_detect_one); }