/ driver-blockerupter.c
driver-blockerupter.c
1 #include "config.h" 2 #include <limits.h> 3 #include <pthread.h> 4 #include <stdio.h> 5 #include <sys/time.h> 6 #include <sys/types.h> 7 #include <dirent.h> 8 #include <unistd.h> 9 #include <math.h> 10 #ifndef WIN32 11 #include <termios.h> 12 #include <sys/stat.h> 13 #include <fcntl.h> 14 #ifndef O_CLOEXEC 15 #define O_CLOEXEC 0 16 #endif 17 #else 18 #include <io.h> 19 #endif 20 21 #include "elist.h" 22 #include "miner.h" 23 #include "driver-blockerupter.h" 24 #include "usbutils.h" 25 26 static void blockerupter_space_mode(struct cgpu_info *blockerupter) 27 { 28 int interface; 29 unsigned int bits = 0; 30 31 interface = usb_interface(blockerupter); 32 33 bits |= CP210X_BITS_DATA_8; 34 bits |= CP210X_BITS_PARITY_SPACE; 35 36 usb_transfer_data(blockerupter, CP210X_TYPE_OUT, CP210X_SET_LINE_CTL, bits, interface, NULL, 0, C_SETPARITY); 37 } 38 39 static void blockerupter_mark_mode(struct cgpu_info *blockerupter) 40 { 41 int interface; 42 unsigned int bits = 0; 43 44 interface = usb_interface(blockerupter); 45 46 bits |= CP210X_BITS_DATA_8; 47 bits |= CP210X_BITS_PARITY_MARK; 48 49 usb_transfer_data(blockerupter, CP210X_TYPE_OUT, CP210X_SET_LINE_CTL, bits, interface, NULL, 0, C_SETPARITY); 50 51 } 52 53 static void blockerupter_init_com(struct cgpu_info *blockerupter) 54 { 55 uint32_t baudrate; 56 int interface; 57 58 if (blockerupter->usbinfo.nodev) 59 return; 60 61 interface = usb_interface(blockerupter); 62 63 // Enable the UART 64 usb_transfer_data(blockerupter, CP210X_TYPE_OUT, CP210X_REQUEST_IFC_ENABLE, 65 CP210X_VALUE_UART_ENABLE, interface, NULL, 0, C_ENABLE_UART); 66 if (blockerupter->usbinfo.nodev) 67 return; 68 69 // Set data control 70 usb_transfer_data(blockerupter, CP210X_TYPE_OUT, CP210X_REQUEST_DATA, CP210X_VALUE_DATA, 71 interface, NULL, 0, C_SETDATA); 72 73 if (blockerupter->usbinfo.nodev) 74 return; 75 76 // Set the baud 77 baudrate = BET_BAUD; 78 79 usb_transfer_data(blockerupter, CP210X_TYPE_OUT, CP210X_REQUEST_BAUD, 0, 80 interface, &baudrate, sizeof (baudrate), C_SETBAUD); 81 82 // Set space mode 83 blockerupter_space_mode(blockerupter); 84 } 85 86 static int blockerupter_send(struct cgpu_info *blockerupter, char *data, int len) 87 { 88 int err; 89 int bytes_sent; 90 91 if (unlikely(blockerupter->usbinfo.nodev)) 92 return SEND_FAIL; 93 94 err = usb_write(blockerupter, data, len, &bytes_sent, C_BET_WRITE); 95 96 if (err || bytes_sent != len) { 97 applog(LOG_DEBUG, "blockerupter: Send (%d/%d)", bytes_sent, len); 98 return SEND_FAIL; 99 } 100 101 return SEND_OK; 102 } 103 104 static int blockerupter_read(struct cgpu_info *blockerupter, char *data, int len) 105 { 106 int err; 107 int bytes_read; 108 109 if (unlikely(blockerupter->usbinfo.nodev)) 110 return READ_FAIL; 111 112 err = usb_read_timeout(blockerupter, data, len, &bytes_read, 2, C_BET_READ); 113 114 if (err || bytes_read != len) { 115 applog(LOG_DEBUG, "blockerupter: Read (%d/%d)", bytes_read, len); 116 return READ_FAIL; 117 } 118 119 return READ_OK; 120 } 121 122 static void blockerupter_setclock(struct cgpu_info *blockerupter, uint8_t clock) 123 { 124 struct blockerupter_info *info; 125 info = blockerupter->device_data; 126 char command; 127 int err; 128 129 command = C_GCK | clock; 130 info->clock = clock; 131 err = blockerupter_send(blockerupter, &command, 1); 132 if (!err) 133 applog(LOG_DEBUG, "%s%d: Set Clock to %d MHz", blockerupter->drv->name, 134 blockerupter->device_id, (clock + 1) * 10 / 2); 135 } 136 137 static void blockerupter_setdiff(struct cgpu_info *blockerupter, int diff) 138 { 139 struct blockerupter_info *info; 140 info = blockerupter->device_data; 141 char command,bits; 142 int err; 143 int local_diff; 144 145 // min_diff for driver is 64 146 if (diff >= 262144) { 147 bits = 3; 148 local_diff = 262144; 149 } else if (diff >= 4096) { 150 bits = 2; 151 local_diff = 4096; 152 } else { 153 bits = 1; 154 local_diff = 64; 155 } 156 157 if (local_diff == info->diff) 158 return; 159 160 command = C_DIF | bits; 161 err = blockerupter_send(blockerupter, &command, 1); 162 if (!err) { 163 applog(LOG_DEBUG, "%s%d: Set Diff Bits to %d", blockerupter->drv->name, 164 blockerupter->device_id, bits); 165 info->diff = local_diff; 166 } 167 } 168 169 static void blockerupter_setrolling(struct cgpu_info *blockerupter, uint8_t rolling) 170 { 171 struct blockerupter_info *info; 172 info = blockerupter->device_data; 173 char command; 174 int err; 175 176 command = C_LPO | rolling; 177 err = blockerupter_send(blockerupter, &command, 1); 178 179 if (!err) { 180 applog(LOG_DEBUG, "%s%d: Set nTime Rolling to %d seconds", blockerupter->drv->name, 181 blockerupter->device_id, (rolling + 1) * 30); 182 info->rolling = (rolling + 1) * 30; 183 } 184 } 185 186 static void blockerupter_init(struct cgpu_info *blockerupter) 187 { 188 struct blockerupter_info *info; 189 190 info = blockerupter->device_data; 191 // Set Clock 192 if (!opt_bet_clk || opt_bet_clk< 19 || opt_bet_clk > 31) { 193 opt_bet_clk = BET_CLOCK_DEFAULT; 194 } 195 blockerupter_setclock(blockerupter, opt_bet_clk); 196 info->clock = (opt_bet_clk + 1) * 10; 197 info->expected = info->clock * 24 * 32 * info->found / 1000.0; 198 // Set Diff 199 blockerupter_setdiff(blockerupter, BET_DIFF_DEFAULT); 200 info->diff = BET_DIFF_DEFAULT; 201 // Set nTime Rolling 202 blockerupter_setrolling(blockerupter, BET_ROLLING_DEFAULT); 203 info->rolling = (BET_ROLLING_DEFAULT + 1) * 30; 204 cgtime(&info->start_time); 205 } 206 207 static struct cgpu_info *blockerupter_detect_one(struct libusb_device *dev, struct usb_find_devices *found) 208 { 209 struct blockerupter_info *info; 210 struct cgpu_info *blockerupter = usb_alloc_cgpu(&blockerupter_drv, 1); 211 int i, err; 212 char reset = C_RES; 213 214 if (!usb_init(blockerupter, dev, found)) { 215 applog(LOG_ERR, "Blockerupter usb init failed"); 216 blockerupter = usb_free_cgpu(blockerupter); 217 return NULL; 218 } 219 220 blockerupter->device_data = (struct blockerupter_info *) malloc(sizeof(struct blockerupter_info)); 221 info = blockerupter->device_data; 222 memset(info, 0, sizeof(blockerupter_info)); 223 blockerupter_init_com(blockerupter); 224 225 err = blockerupter_send(blockerupter, &reset, 1); 226 if (err) { 227 applog(LOG_ERR, "Blockerupter detect failed"); 228 blockerupter = usb_free_cgpu(blockerupter); 229 return NULL; 230 } 231 cgsleep_ms(5000); 232 233 234 for (i = 0; i < BET_MAXBOARDS; i++) { 235 char detect, answer; 236 237 answer = 0; 238 detect = C_ASK | (uint8_t)i; 239 blockerupter_send(blockerupter, &detect, 1); 240 blockerupter_read(blockerupter, &answer, 1); 241 if (answer == A_WAL) { 242 applog(LOG_DEBUG, "BlockErupter found Board: %d", i); 243 info->boards[i] = 1; 244 info->found++; 245 } else { 246 if (!i) { 247 applog(LOG_DEBUG, "BlockErupter no boards found, likely not BET"); 248 break; 249 } 250 applog(LOG_DEBUG, "BlockErupter missing board: %d, received %02x", 251 i, answer); 252 } 253 } 254 255 if (!info->found) { 256 usb_uninit(blockerupter); 257 blockerupter = usb_free_cgpu(blockerupter); 258 free(info); 259 return NULL; 260 } else { 261 blockerupter->threads = 1; 262 add_cgpu(blockerupter); 263 applog(LOG_DEBUG, "Add BlockErupter with %d/%d Boards", info->found, 264 BET_MAXBOARDS); 265 blockerupter_init(blockerupter); 266 return blockerupter; 267 } 268 } 269 270 static inline void blockerupter_detect(bool __maybe_unused hotplug) 271 { 272 usb_detect(&blockerupter_drv, blockerupter_detect_one); 273 } 274 275 static struct api_data *blockerupter_api_stats(struct cgpu_info *blockerupter) 276 { 277 struct blockerupter_info *info = blockerupter->device_data; 278 struct api_data *root = NULL; 279 struct timeval now, elapsed; 280 char buf[32]; 281 int i; 282 283 cgtime(&now); 284 timersub(&now, &info->start_time, &elapsed); 285 286 info->hashrate = elapsed.tv_sec ? info->hashes * 4.295 / elapsed.tv_sec : 0; 287 info->eff = info->hashrate / info->expected; 288 289 root = api_add_int(root, "Nonces", &info->nonces, false); 290 root = api_add_uint8(root, "Board", &info->found, false); 291 root = api_add_int(root, "Clock", &info->clock, false); 292 root = api_add_int(root,"Accepted", &info->accepted, false); 293 root = api_add_double(root, "HashRate", &info->hashrate , false); 294 root = api_add_double(root, "Expected", &info->expected , false); 295 root = api_add_double(root, "Efficiency", &info->eff, false); 296 for (i = 0; i < BET_MAXBOARDS; i++) { 297 double brd_hashrate; 298 299 if (info->boards[i]) { 300 sprintf(buf, "Board%02d accepted", i); 301 root = api_add_int(root, buf, &info->b_info[i].accepted, false); 302 sprintf(buf, "Board%02d nonces", i); 303 root = api_add_int(root, buf, &info->b_info[i].nonces, false); 304 sprintf(buf, "Board%02d hwerror", i); 305 root = api_add_double(root, buf, &info->b_info[i].hwe, false); 306 sprintf(buf, "Board%02d hashrate", i); 307 brd_hashrate = elapsed.tv_sec ? info->b_info[i].hashes * 4.295 / elapsed.tv_sec : 0; 308 root = api_add_double(root, buf, &brd_hashrate, false); 309 } 310 } 311 312 return root; 313 } 314 315 static bool blockerupter_prepare(struct thr_info *thr) 316 { 317 struct cgpu_info *blockerupter = thr->cgpu; 318 struct blockerupter_info *info = blockerupter->device_data; 319 320 cglock_init(&(info->pool.data_lock)); 321 322 return true; 323 } 324 325 static void blockerupter_sendjob(struct cgpu_info *blockerupter, int board) 326 { 327 struct blockerupter_info *info = blockerupter->device_data; 328 struct thr_info *thr = blockerupter->thr[0]; 329 struct work *work; 330 uint8_t command, answer; 331 int err; 332 333 work = get_work(thr, thr->id); 334 memcpy(&info->works[info->work_idx],work,sizeof(struct work)); 335 336 blockerupter_setdiff(blockerupter,floor(work->work_difficulty)); 337 338 command = C_JOB | (uint8_t)board; 339 blockerupter_send(blockerupter, (char *)&command, 1); 340 blockerupter_mark_mode(blockerupter); 341 cgsleep_ms(1); 342 343 blockerupter_send(blockerupter, (char *)(work->midstate), 32); 344 blockerupter_send(blockerupter, (char *)&(work->data[64]), 12); 345 blockerupter_send(blockerupter, (char *)&work->nonce2, 4); 346 blockerupter_send(blockerupter, (char *)&info->work_idx, 1); 347 348 cgsleep_ms(1); 349 blockerupter_space_mode(blockerupter); 350 351 answer = 0; 352 err = blockerupter_read(blockerupter, (char *)&answer, 1); 353 354 cgtime(&info->last_job); 355 356 if (err || answer != A_GET) { 357 applog(LOG_ERR, "%s%d: Sync Error", blockerupter->drv->name, blockerupter->device_id); 358 } else { 359 info->b_info[board].job_count++; 360 applog(LOG_DEBUG, "%s%d: Sent work %d to board %d", blockerupter->drv->name, 361 blockerupter->device_id, info->work_idx, board); 362 } 363 364 info->work_idx++; 365 if (info->work_idx >= BET_WORK_FIFO) 366 info->work_idx = 0; 367 } 368 369 static uint64_t blockerupter_checknonce(struct cgpu_info *blockerupter, struct blockerupter_response *resp, int board) 370 { 371 uint8_t test; 372 struct blockerupter_info *info; 373 struct thr_info *thr = blockerupter->thr[0]; 374 struct work work; 375 uint32_t nonce; 376 uint64_t hashes=0; 377 int i; 378 struct board_info *cur_brd; 379 struct asic_info *cur_asic; 380 381 info = blockerupter->device_data; 382 work = info->works[resp->work_idx]; 383 384 nonce = *(uint32_t *)resp->nonce; 385 386 applog(LOG_DEBUG, "%s%d: Nonce %08x from board %d, asic %d for work %d", 387 blockerupter->drv->name, blockerupter->device_id, *(uint32_t *) resp->nonce, 388 board, resp->chip, resp->work_idx); 389 390 memcpy(work.data + 4 + 32 + 32, resp->ntime, 4); 391 __bin2hex(work.ntime, resp->ntime, 4); 392 393 info->nonces++; 394 cur_brd = &info->b_info[board]; 395 cur_brd->nonces++; 396 cur_asic = &info->b_info[board].asics[resp->chip]; 397 cur_asic->nonces++; 398 399 for (i = 0; i < BET_NONCE_FIX; i++) { 400 test = test_nonce_diff(&work, nonce + i, (double)info->diff); 401 if (test) { 402 applog(LOG_DEBUG, "%s%d: Nonce Fix Pass @%d", blockerupter->drv->name, 403 blockerupter->device_id, i); 404 info->hashes += info->diff; 405 cur_brd->hashes += info->diff; 406 cur_asic->hashes += info->diff; 407 if (test_nonce_diff(&work, nonce + i, work.work_difficulty)) { 408 if (submit_nonce(thr, &work, nonce + i)) { 409 hashes += floor(work.work_difficulty) * (uint64_t) 0xffffffff; 410 info->accepted++; 411 cur_brd->accepted++; 412 cur_asic->accepted++; 413 } 414 } 415 break; 416 } 417 } 418 419 if (i == BET_NONCE_FIX) { 420 applog(LOG_DEBUG, "%s%d: Nonce Fix Failed", blockerupter->drv->name, 421 blockerupter->device_id); 422 cur_brd->bad++; 423 cur_brd->hwe = cur_brd->nonces ? (double)cur_brd->bad / cur_brd->nonces : 0; 424 cur_asic->bad++; 425 cur_asic->hwe = cur_asic->nonces ? (double)cur_asic->bad / cur_asic->nonces : 0; 426 } 427 return hashes; 428 } 429 430 static uint64_t blockerupter_getresp(struct cgpu_info *blockerupter, int board) 431 { 432 struct blockerupter_response *resp; 433 int err; 434 uint64_t hashes = 0; 435 436 resp = (struct blockerupter_response *) malloc(BET_RESP_SZ); 437 err = blockerupter_read(blockerupter, (char *)resp, BET_RESP_SZ); 438 if (!err) 439 hashes = blockerupter_checknonce(blockerupter, resp, board); 440 free(resp); 441 return hashes; 442 } 443 444 static int64_t blockerupter_scanhash(struct thr_info *thr) 445 { 446 struct cgpu_info *blockerupter = thr->cgpu; 447 struct blockerupter_info *info = blockerupter->device_data; 448 char ask; 449 uint8_t answer; 450 int i; 451 int64_t hashes=0; 452 453 if (unlikely(blockerupter->usbinfo.nodev)) { 454 applog(LOG_ERR, "%s%d: Device disappeared, shutting down thread", 455 blockerupter->drv->name, blockerupter->device_id); 456 return -1; 457 } 458 459 for (i = 0; i < BET_MAXBOARDS; i++) { 460 if (!info->boards[i]) 461 continue; 462 ask = C_ASK | (uint8_t)i; 463 blockerupter_send(blockerupter, &ask, 1); 464 cgsleep_ms(1); 465 answer = 0; 466 blockerupter_read(blockerupter, (char *)&answer, 1); 467 468 switch (answer) { 469 case A_WAL: 470 blockerupter_sendjob(blockerupter, i); 471 break; 472 case A_YES: 473 hashes += blockerupter_getresp(blockerupter, i); 474 break; 475 case A_NO: 476 break; 477 default: 478 applog(LOG_ERR, "%s%d: Unexpected value %02x received", blockerupter->drv->name, 479 blockerupter->device_id, answer); 480 break; 481 } 482 } 483 484 return hashes; 485 } 486 487 static void blockerupter_flush_work(struct cgpu_info *blockerupter) 488 { 489 uint8_t command = C_LPO | BET_ROLLING_DEFAULT; 490 491 blockerupter_send(blockerupter, (char *)&command, 1); 492 } 493 494 struct device_drv blockerupter_drv = { 495 .drv_id = DRIVER_blockerupter, 496 .dname = "blockerupter", 497 .name = "BET", 498 .min_diff = 64, 499 .get_api_stats = blockerupter_api_stats, 500 .drv_detect = blockerupter_detect, 501 .thread_prepare = blockerupter_prepare, 502 .hash_work = hash_driver_work, 503 .flush_work = blockerupter_flush_work, 504 .scanwork = blockerupter_scanhash 505 };