diff --git a/01-cgminer.rules b/01-cgminer.rules deleted file mode 100644 index 972468ca..00000000 --- a/01-cgminer.rules +++ /dev/null @@ -1,32 +0,0 @@ -# Butterfly Labs FPGA and ASIC devices -ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", SUBSYSTEMS=="usb", ACTION=="add", MODE="0666", GROUP="plugdev" - -# ModMinerQuad -ATTRS{idVendor}=="1fc9", ATTRS{idProduct}=="0003", SUBSYSTEMS=="usb", ACTION=="add", MODE="0666", GROUP="plugdev" - -# Lancelot and Avalon -ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", SUBSYSTEMS=="usb", ACTION=="add", MODE="0666", GROUP="plugdev" - -# Icarus -ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", SUBSYSTEMS=="usb", ACTION=="add", MODE="0666", GROUP="plugdev" - -# AsicminerUSB -ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", SUBSYSTEMS=="usb", ACTION=="add", MODE="0666", GROUP="plugdev" - -# Cairnsmore1 -ATTRS{idVendor}=="067b", ATTRS{idProduct}=="0230", SUBSYSTEMS=="usb", ACTION=="add", MODE="0666", GROUP="plugdev" - -# Cairnsmore1-2 -ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8350", SUBSYSTEMS=="usb", ACTION=="add", MODE="0666", GROUP="plugdev" - -# Ztex -ATTRS{idVendor}=="221a", ATTRS{idProduct}=="0100", SUBSYSTEMS=="usb", ACTION=="add", MODE="0666", GROUP="plugdev" - -# BF1 -ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204b", SUBSYSTEMS=="usb", ACTION=="add", MODE="0666", GROUP="plugdev" - -#Klondike -ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="f60a", SUBSYSTEMS=="usb", ACTION=="add", MODE="0666", GROUP="plugdev" - -#HashFast -ATTRS{idVendor}=="297c", ATTRS{idProduct}=="0001", SUBSYSTEMS=="usb", ACTION=="add", MODE="0666", GROUP="plugdev", ENV{ID_MM_DEVICE_IGNORE}="1" diff --git a/bitforce-firmware-flash.c b/bitforce-firmware-flash.c deleted file mode 100644 index b4f6aca4..00000000 --- a/bitforce-firmware-flash.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2012 Luke Dashjr - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. See COPYING for more details. - */ - -#define _BSD_SOURCE -#include -#include -#include - -#include -#include - -#define BFL_FILE_MAGIC "BFLDATA" -#define BFL_UPLOAD_MAGIC "NGH-STREAM" - -#define myassert(expr, n, ...) \ -do { \ - if (!(expr)) { \ - fprintf(stderr, __VA_ARGS__); \ - return n; \ - } \ -} while(0) - -#define ERRRESP(buf) buf, (buf[strlen(buf)-1] == '\n' ? "" : "\n") - -#define WAITFOROK(n, msg) \ -do { \ - myassert(fgets(buf, sizeof(buf), BFL), n, "Error reading response from " msg "\n"); \ - myassert(!strcmp(buf, "OK\n"), n, "Invalid response from " msg ": %s%s", ERRRESP(buf)); \ -} while(0) - -int main(int argc, char**argv) -{ - myassert(argc == 3, 1, "Usage: %s \n", argv[0]); - setbuf(stdout, NULL); - - // Check filename - char *FWname = basename(strdup(argv[2])); - size_t FWnameLen = strlen(FWname); - myassert(FWnameLen <= 255, 0x0f, "Firmware filename '%s' is too long\n", FWname); - uint8_t n8 = FWnameLen; - - // Open and check firmware file - FILE *FW = fopen(argv[2], "r"); - myassert(FW, 0x10, "Failed to open '%s' for reading\n", argv[2]); - char buf[0x20]; - myassert(1 == fread(buf, 7, 1, FW), 0x10, "Failed to read from '%s'\n", argv[2]); - myassert(!memcmp(buf, BFL_FILE_MAGIC, sizeof(BFL_FILE_MAGIC)-1), 0x11, "'%s' doesn't look like a BFL firmware\n", argv[2]); - myassert(!fseek(FW, 0, SEEK_END), 0x12, "Failed to find end of '%s'\n", argv[2]); - long FWlen = ftell(FW); - myassert(FWlen > 0, 0x12, "Couldn't get size of '%s'\n", argv[2]); - myassert(!fseek(FW, 7, SEEK_SET), 0x12, "Failed to rewind firmware file after getting size\n"); - FWlen -= 7; - printf("Firmware file looks OK :)\n"); - - // Open device - FILE *BFL = fopen(argv[1], "r+"); - myassert(BFL, 0x20, "Failed to open '%s' for read/write\n", argv[1]); - myassert(!setvbuf(BFL, NULL, _IOFBF, 1032), 0x21, "Failed to setup buffer for device"); - - // ZAX: Start firmware upload - printf("Starting firmware upload... "); - myassert(1 == fwrite("ZAX", 3, 1, BFL), 0x22, "Failed to issue ZAX command\n"); - WAITFOROK(0x22, "ZAX"); - - // Firmware upload header - myassert(1 == fwrite(BFL_UPLOAD_MAGIC, sizeof(BFL_UPLOAD_MAGIC)-1, 1, BFL), 0x23, "Failed to send firmware upload header (magic)\n"); - uint32_t n32 = htonl(FWlen - FWlen / 6); - myassert(1 == fwrite(&n32, sizeof(n32), 1, BFL), 0x23, "Failed to send firmware upload header (size)\n"); - myassert(1 == fwrite("\0\0", 2 , 1, BFL), 0x23, "Failed to send firmware upload header (padding 1)\n"); - myassert(1 == fwrite(&n8, sizeof(n8) , 1, BFL), 0x23, "Failed to send firmware upload header (filename length)\n"); - myassert(1 == fwrite(FWname, n8 , 1, BFL), 0x23, "Failed to send firmware upload header (filename)\n"); - myassert(1 == fwrite("\0>>>>>>>>", 9 , 1, BFL), 0x23, "Failed to send firmware upload header (padding 2)\n"); - WAITFOROK(0x23, "firmware upload header"); - printf("OK, sending...\n"); - - // Actual firmware upload - long i, j; - for (i = 0, j = 0; i < FWlen; ++i) { - myassert(1 == fread(&n8, sizeof(n8), 1, FW), 0x30, "Error reading data from firmware file\n"); - if (5 == i % 6) - continue; - n8 ^= 0x2f; - myassert(1 == fwrite(&n8, sizeof(n8), 1, BFL), 0x31, "Error sending data to device\n"); - if (!(++j % 0x400)) { - myassert(1 == fwrite(">>>>>>>>", 8, 1, BFL), 0x32, "Error sending block-finish to device\n"); - printf("\r%5.2f%% complete", (double)i * 100. / (double)FWlen); - WAITFOROK(0x32, "block-finish"); - } - } - printf("\r100%% complete :)\n"); - myassert(1 == fwrite(">>>>>>>>", 8, 1, BFL), 0x3f, "Error sending upload-finished to device\n"); - myassert(fgets(buf, sizeof(buf), BFL), 0x3f, "Error reading response from upload-finished\n"); - myassert(!strcmp(buf, "DONE\n"), 0x3f, "Invalid response from upload-finished: %s%s", ERRRESP(buf)); - - // ZBX: Finish programming - printf("Waiting for device... "); - myassert(1 == fwrite("ZBX", 3, 1, BFL), 0x40, "Failed to issue ZBX command\n"); - WAITFOROK(0x40, "ZBX"); - printf("All done! Try mining to test the flash succeeded.\n"); - - return 0; -} diff --git a/bitstreams/COPYING_fpgaminer b/bitstreams/COPYING_fpgaminer deleted file mode 100644 index 9db2c5fd..00000000 --- a/bitstreams/COPYING_fpgaminer +++ /dev/null @@ -1,23 +0,0 @@ -All the bitstream files included in this directory that follow the name pattern fpgaminer_*.ncd are: - ----- - -Copyright (c) 2011-2012 fpgaminer@bitcoin-mining.com - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . - ----- - -You can find the original sources at the Open Source FPGA Bitcoin Miner project GitHub repository: -https://github.com/progranism/Open-Source-FPGA-Bitcoin-Miner/tree/master/projects/X6000_ztex_comm4/hdl diff --git a/bitstreams/fpgaminer_top_fixed7_197MHz.ncd b/bitstreams/fpgaminer_top_fixed7_197MHz.ncd deleted file mode 100644 index 1df4e1d0..00000000 Binary files a/bitstreams/fpgaminer_top_fixed7_197MHz.ncd and /dev/null differ diff --git a/diablo130302.cl b/diablo130302.cl deleted file mode 100644 index a7218031..00000000 --- a/diablo130302.cl +++ /dev/null @@ -1,1361 +0,0 @@ -/* - * DiabloMiner - OpenCL miner for BitCoin - * Copyright (C) 2012, 2013 Con Kolivas - * Copyright (C) 2010, 2011, 2012 Patrick McFarland - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more detail). - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifdef VECTORS4 - typedef uint4 z; -#elif defined(VECTORS2) - typedef uint2 z; -#else - typedef uint z; -#endif - -#ifdef BITALIGN -#pragma OPENCL EXTENSION cl_amd_media_ops : enable -#define Zrotr(a, b) amd_bitalign((z)a, (z)a, (z)(32 - b)) -#else -#define Zrotr(a, b) rotate((z)a, (z)b) -#endif - -#ifdef BFI_INT -#define ZCh(a, b, c) amd_bytealign(a, b, c) -#define ZMa(a, b, c) amd_bytealign((c ^ a), (b), (a)) -#else -#define ZCh(a, b, c) bitselect((z)c, (z)b, (z)a) -#define ZMa(a, b, c) bitselect((z)a, (z)b, (z)c ^ (z)a) -#endif - -/* These constants are not the classic SHA256 constants but the order that - * constants are used in this kernel. - */ -__constant uint K[] = { - 0xd807aa98U, - 0x12835b01U, - 0x243185beU, - 0x550c7dc3U, - 0x72be5d74U, - 0x80deb1feU, - 0x9bdc06a7U, - 0xc19bf3f4U, - 0x0fc19dc6U, - 0x240ca1ccU, - 0x80000000U, // 10 - 0x2de92c6fU, - 0x4a7484aaU, - 0x00000280U, - 0x5cb0a9dcU, - 0x76f988daU, - 0x983e5152U, - 0xa831c66dU, - 0xb00327c8U, - 0xbf597fc7U, - 0xc6e00bf3U, // 20 - 0x00A00055U, - 0xd5a79147U, - 0x06ca6351U, - 0x14292967U, - 0x27b70a85U, - 0x2e1b2138U, - 0x4d2c6dfcU, - 0x53380d13U, - 0x650a7354U, - 0x766a0abbU, // 30 - 0x81c2c92eU, - 0x92722c85U, - 0xa2bfe8a1U, - 0xa81a664bU, - 0xc24b8b70U, - 0xc76c51a3U, - 0xd192e819U, - 0xd6990624U, - 0xf40e3585U, - 0x106aa070U, // 40 - 0x19a4c116U, - 0x1e376c08U, - 0x2748774cU, - 0x34b0bcb5U, - 0x391c0cb3U, - 0x4ed8aa4aU, - 0x5b9cca4fU, - 0x682e6ff3U, - 0x748f82eeU, - 0x78a5636fU, // 50 - 0x84c87814U, - 0x8cc70208U, - 0x90befffaU, - 0xa4506cebU, - 0xbef9a3f7U, - 0xc67178f2U, - 0x98c7e2a2U, - 0x90bb1e3cU, - 0x510e527fU, - 0x9b05688cU, // 60 - 0xfc08884dU, - 0x3c6ef372U, - 0x50c6645bU, - 0x6a09e667U, - 0xbb67ae85U, - 0x3ac42e24U, - 0xd21ea4fdU, - 0x59f111f1U, - 0x923f82a4U, - 0xab1c5ed5U, // 70 - 0x5807aa98U, - 0xc19bf274U, - 0xe49b69c1U, - 0x00a00000U, - 0xefbe4786U, - 0x00000100U, - 0x11002000U, - 0x00400022U, - 0x136032EDU -}; - -#define ZR25(n) ((Zrotr((n), 25) ^ Zrotr((n), 14) ^ ((n) >> 3U))) -#define ZR15(n) ((Zrotr((n), 15) ^ Zrotr((n), 13) ^ ((n) >> 10U))) -#define ZR26(n) ((Zrotr((n), 26) ^ Zrotr((n), 21) ^ Zrotr((n), 7))) -#define ZR30(n) ((Zrotr((n), 30) ^ Zrotr((n), 19) ^ Zrotr((n), 10))) - -__kernel -__attribute__((vec_type_hint(z))) -__attribute__((reqd_work_group_size(WORKSIZE, 1, 1))) -void search( -#ifndef GOFFSET - const z base, -#endif - const uint PreVal4_state0, const uint PreVal4_state0_k7, - const uint PreVal4_T1, - const uint W18, const uint W19, - const uint W16, const uint W17, - const uint W16_plus_K16, const uint W17_plus_K17, - const uint W31, const uint W32, - const uint d1, const uint b1, const uint c1, - const uint h1, const uint f1, const uint g1, - const uint c1_plus_k5, const uint b1_plus_k6, - const uint state0, const uint state1, const uint state2, const uint state3, - const uint state4, const uint state5, const uint state6, const uint state7, - volatile __global uint * output) -{ - - z ZA[930]; - -#ifdef GOFFSET - const z Znonce = (uint)(get_global_id(0)); -#else - const z Znonce = base + (uint)(get_global_id(0)); -#endif - - ZA[15] = Znonce + PreVal4_state0; - - ZA[16] = (ZCh(ZA[15], b1, c1) + d1) + ZR26(ZA[15]); - ZA[26] = Znonce + PreVal4_T1; - - ZA[27] = ZMa(f1, g1, ZA[26]) + ZR30(ZA[26]); - ZA[17] = ZA[16] + h1; - - ZA[19] = (ZCh(ZA[17], ZA[15], b1) + c1_plus_k5) + ZR26(ZA[17]); - ZA[28] = ZA[27] + ZA[16]; - - ZA[548] = ZMa(ZA[26], f1, ZA[28]) + ZR30(ZA[28]); - ZA[20] = ZA[19] + g1; - - ZA[22] = (ZCh(ZA[20], ZA[17], ZA[15]) + b1_plus_k6) + ZR26(ZA[20]); - ZA[29] = ZA[548] + ZA[19]; - - ZA[549] = ZMa(ZA[28], ZA[26], ZA[29]) + ZR30(ZA[29]); - ZA[23] = ZA[22] + f1; - - ZA[24] = ZCh(ZA[23], ZA[20], ZA[17]) + ZR26(ZA[23]); - ZA[180] = Znonce + PreVal4_state0_k7; - ZA[30] = ZA[549] + ZA[22]; - - ZA[31] = ZMa(ZA[29], ZA[28], ZA[30]) + ZR30(ZA[30]); - ZA[181] = ZA[180] + ZA[24]; - - ZA[182] = ZA[181] + ZA[26]; - ZA[183] = ZA[181] + ZA[31]; - ZA[18] = ZA[17] + K[0]; - - ZA[186] = (ZCh(ZA[182], ZA[23], ZA[20]) + ZA[18]) + ZR26(ZA[182]); - ZA[184] = ZMa(ZA[30], ZA[29], ZA[183]) + ZR30(ZA[183]); - - ZA[187] = ZA[186] + ZA[28]; - ZA[188] = ZA[186] + ZA[184]; - ZA[21] = ZA[20] + K[1]; - - ZA[191] = (ZCh(ZA[187], ZA[182], ZA[23]) + ZA[21]) + ZR26(ZA[187]); - ZA[189] = ZMa(ZA[183], ZA[30], ZA[188]) + ZR30(ZA[188]); - - ZA[192] = ZA[191] + ZA[29]; - ZA[193] = ZA[191] + ZA[189]; - ZA[25] = ZA[23] + K[2]; - - ZA[196] = (ZCh(ZA[192], ZA[187], ZA[182]) + ZA[25]) + ZR26(ZA[192]); - ZA[194] = ZMa(ZA[188], ZA[183], ZA[193]) + ZR30(ZA[193]); - - ZA[197] = ZA[196] + ZA[30]; - ZA[198] = ZA[196] + ZA[194]; - ZA[185] = ZA[182] + K[3]; - - ZA[201] = (ZCh(ZA[197], ZA[192], ZA[187]) + ZA[185]) + ZR26(ZA[197]); - ZA[199] = ZMa(ZA[193], ZA[188], ZA[198]) + ZR30(ZA[198]); - - ZA[202] = ZA[201] + ZA[183]; - ZA[203] = ZA[201] + ZA[199]; - ZA[190] = ZA[187] + K[4]; - - ZA[206] = (ZCh(ZA[202], ZA[197], ZA[192]) + ZA[190]) + ZR26(ZA[202]); - ZA[204] = ZMa(ZA[198], ZA[193], ZA[203]) + ZR30(ZA[203]); - - ZA[207] = ZA[206] + ZA[188]; - ZA[208] = ZA[206] + ZA[204]; - ZA[195] = ZA[192] + K[5]; - - ZA[211] = (ZCh(ZA[207], ZA[202], ZA[197]) + ZA[195]) + ZR26(ZA[207]); - ZA[209] = ZMa(ZA[203], ZA[198], ZA[208]) + ZR30(ZA[208]); - - ZA[212] = ZA[193] + ZA[211]; - ZA[213] = ZA[211] + ZA[209]; - ZA[200] = ZA[197] + K[6]; - - ZA[216] = (ZCh(ZA[212], ZA[207], ZA[202]) + ZA[200]) + ZR26(ZA[212]); - ZA[214] = ZMa(ZA[208], ZA[203], ZA[213]) + ZR30(ZA[213]); - - ZA[217] = ZA[198] + ZA[216]; - ZA[218] = ZA[216] + ZA[214]; - ZA[205] = ZA[202] + K[7]; - - ZA[220] = (ZCh(ZA[217], ZA[212], ZA[207]) + ZA[205]) + ZR26(ZA[217]); - ZA[219] = ZMa(ZA[213], ZA[208], ZA[218]) + ZR30(ZA[218]); - - ZA[222] = ZA[203] + ZA[220]; - ZA[223] = ZA[220] + ZA[219]; - ZA[210] = ZA[207] + W16_plus_K16; - - ZA[226] = (ZCh(ZA[222], ZA[217], ZA[212]) + ZA[210]) + ZR26(ZA[222]); - ZA[225] = ZMa(ZA[218], ZA[213], ZA[223]) + ZR30(ZA[223]); - - ZA[0] = ZR25(Znonce) + W18; - ZA[228] = ZA[226] + ZA[225]; - ZA[227] = ZA[208] + ZA[226]; - ZA[215] = ZA[212] + W17_plus_K17; - - ZA[231] = (ZCh(ZA[227], ZA[222], ZA[217]) + ZA[215]) + ZR26(ZA[227]); - ZA[229] = ZMa(ZA[223], ZA[218], ZA[228]) + ZR30(ZA[228]); - ZA[1] = ZA[0] + K[8]; - - ZA[232] = ZA[213] + ZA[231]; - ZA[233] = ZA[231] + ZA[229]; - ZA[221] = ZA[217] + ZA[1]; - ZA[32] = Znonce + W19; - - ZA[236] = (ZCh(ZA[232], ZA[227], ZA[222]) + ZA[221]) + ZR26(ZA[232]); - ZA[234] = ZMa(ZA[228], ZA[223], ZA[233]) + ZR30(ZA[233]); - ZA[33] = ZA[32] + K[9]; - - ZA[3] = ZR15(ZA[0]) + K[10]; - ZA[238] = ZA[236] + ZA[234]; - ZA[237] = ZA[218] + ZA[236]; - ZA[224] = ZA[222] + ZA[33]; - - ZA[241] = (ZCh(ZA[237], ZA[232], ZA[227]) + ZA[224]) + ZR26(ZA[237]); - ZA[239] = ZMa(ZA[233], ZA[228], ZA[238]) + ZR30(ZA[238]); - ZA[4] = ZA[3] + K[11]; - - ZA[35] = ZR15(ZA[32]); - ZA[243] = ZA[241] + ZA[239]; - ZA[242] = ZA[223] + ZA[241]; - ZA[230] = ZA[227] + ZA[4]; - - ZA[246] = (ZCh(ZA[242], ZA[237], ZA[232]) + ZA[230]) + ZR26(ZA[242]); - ZA[244] = ZMa(ZA[238], ZA[233], ZA[243]) + ZR30(ZA[243]); - ZA[36] = ZA[35] + K[12]; - - ZA[7] = ZR15(ZA[3]) + K[13]; - ZA[248] = ZA[246] + ZA[244]; - ZA[247] = ZA[228] + ZA[246]; - ZA[235] = ZA[232] + ZA[36]; - - ZA[251] = (ZCh(ZA[247], ZA[242], ZA[237]) + ZA[235]) + ZR26(ZA[247]); - ZA[249] = ZMa(ZA[243], ZA[238], ZA[248]) + ZR30(ZA[248]); - ZA[8] = ZA[7] + K[14]; - - ZA[38] = ZR15(ZA[35]) + W16; - ZA[253] = ZA[251] + ZA[249]; - ZA[252] = ZA[233] + ZA[251]; - ZA[240] = ZA[237] + ZA[8]; - - ZA[256] = (ZCh(ZA[252], ZA[247], ZA[242]) + ZA[240]) + ZR26(ZA[252]); - ZA[254] = ZMa(ZA[248], ZA[243], ZA[253]) + ZR30(ZA[253]); - ZA[40] = ZA[38] + K[15]; - - ZA[10] = ZR15(ZA[7]) + W17; - ZA[258] = ZA[256] + ZA[254]; - ZA[257] = ZA[238] + ZA[256]; - ZA[245] = ZA[242] + ZA[40]; - - ZA[261] = (ZCh(ZA[257], ZA[252], ZA[247]) + ZA[245]) + ZR26(ZA[257]); - ZA[259] = ZMa(ZA[253], ZA[248], ZA[258]) + ZR30(ZA[258]); - ZA[13] = ZA[10] + K[16]; - - ZA[43] = ZR15(ZA[38]) + ZA[0]; - ZA[263] = ZA[261] + ZA[259]; - ZA[262] = ZA[243] + ZA[261]; - ZA[250] = ZA[247] + ZA[13]; - - ZA[266] = (ZCh(ZA[262], ZA[257], ZA[252]) + ZA[250]) + ZR26(ZA[262]); - ZA[264] = ZMa(ZA[258], ZA[253], ZA[263]) + ZR30(ZA[263]); - ZA[11] = ZR15(ZA[10]); - ZA[45] = ZA[43] + K[17]; - - ZA[52] = ZA[11] + ZA[32]; - ZA[267] = ZA[248] + ZA[266]; - ZA[255] = ZA[252] + ZA[45]; - ZA[268] = ZA[266] + ZA[264]; - - ZA[271] = (ZCh(ZA[267], ZA[262], ZA[257]) + ZA[255]) + ZR26(ZA[267]); - ZA[269] = ZMa(ZA[263], ZA[258], ZA[268]) + ZR30(ZA[268]); - ZA[54] = ZA[52] + K[18]; - - ZA[48] = ZR15(ZA[43]) + ZA[3]; - ZA[273] = ZA[271] + ZA[269]; - ZA[272] = ZA[253] + ZA[271]; - ZA[260] = ZA[257] + ZA[54]; - - ZA[276] = (ZCh(ZA[272], ZA[267], ZA[262]) + ZA[260]) + ZR26(ZA[272]); - ZA[274] = ZMa(ZA[268], ZA[263], ZA[273]) + ZR30(ZA[273]); - ZA[49] = ZA[48] + K[19]; - - ZA[61] = ZR15(ZA[52]) + ZA[35]; - ZA[278] = ZA[276] + ZA[274]; - ZA[277] = ZA[258] + ZA[276]; - ZA[265] = ZA[262] + ZA[49]; - - ZA[281] = (ZCh(ZA[277], ZA[272], ZA[267]) + ZA[265]) + ZR26(ZA[277]); - ZA[279] = ZMa(ZA[273], ZA[268], ZA[278]) + ZR30(ZA[278]); - ZA[62] = ZA[61] + K[20]; - - ZA[53] = ZR15(ZA[48]) + ZA[7]; - ZA[283] = ZA[281] + ZA[279]; - ZA[282] = ZA[263] + ZA[281]; - ZA[270] = ZA[267] + ZA[62]; - - ZA[286] = (ZCh(ZA[282], ZA[277], ZA[272]) + ZA[270]) + ZR26(ZA[282]); - ZA[284] = ZMa(ZA[278], ZA[273], ZA[283]) + ZR30(ZA[283]); - ZA[39] = ZA[38] + K[21]; - ZA[55] = ZA[53] + K[22]; - - ZA[66] = ZR15(ZA[61]) + ZA[39]; - ZA[288] = ZA[286] + ZA[284]; - ZA[287] = ZA[268] + ZA[286]; - ZA[275] = ZA[272] + ZA[55]; - - ZA[291] = (ZCh(ZA[287], ZA[282], ZA[277]) + ZA[275]) + ZR26(ZA[287]); - ZA[289] = ZMa(ZA[283], ZA[278], ZA[288]) + ZR30(ZA[288]); - ZA[12] = ZA[10] + W31; - ZA[68] = ZA[66] + K[23]; - - ZA[67] = ZR15(ZA[53]) + ZA[12]; - ZA[293] = ZA[291] + ZA[289]; - ZA[292] = ZA[273] + ZA[291]; - ZA[280] = ZA[277] + ZA[68]; - - ZA[296] = (ZCh(ZA[292], ZA[287], ZA[282]) + ZA[280]) + ZR26(ZA[292]); - ZA[294] = ZMa(ZA[288], ZA[283], ZA[293]) + ZR30(ZA[293]); - ZA[2] = ZR25(ZA[0]); - ZA[69] = ZA[67] + K[24]; - ZA[44] = ZA[43] + W32; - - ZA[75] = ZR15(ZA[66]) + ZA[44]; - ZA[298] = ZA[296] + ZA[294]; - ZA[297] = ZA[278] + ZA[296]; - ZA[285] = ZA[282] + ZA[69]; - ZA[5] = ZA[2] + W17; - - ZA[301] = (ZCh(ZA[297], ZA[292], ZA[287]) + ZA[285]) + ZR26(ZA[297]); - ZA[299] = ZMa(ZA[293], ZA[288], ZA[298]) + ZR30(ZA[298]); - ZA[56] = ZA[52] + ZA[5]; - ZA[76] = ZA[75] + K[25]; - - ZA[34] = ZR25(ZA[32]) + ZA[0]; - ZA[70] = ZR15(ZA[67]) + ZA[56]; - ZA[302] = ZA[283] + ZA[301]; - ZA[303] = ZA[301] + ZA[299]; - ZA[290] = ZA[287] + ZA[76]; - - ZA[306] = (ZCh(ZA[302], ZA[297], ZA[292]) + ZA[290]) + ZR26(ZA[302]); - ZA[304] = ZMa(ZA[298], ZA[293], ZA[303]) + ZR30(ZA[303]); - ZA[6] = ZR25(ZA[3]); - ZA[77] = ZA[70] + K[26]; - ZA[50] = ZA[34] + ZA[48]; - - ZA[78] = ZR15(ZA[75]) + ZA[50]; - ZA[308] = ZA[306] + ZA[304]; - ZA[307] = ZA[288] + ZA[306]; - ZA[295] = ZA[292] + ZA[77]; - ZA[41] = ZA[32] + ZA[6]; - - ZA[311] = (ZCh(ZA[307], ZA[302], ZA[297]) + ZA[295]) + ZR26(ZA[307]); - ZA[309] = ZMa(ZA[303], ZA[298], ZA[308]) + ZR30(ZA[308]); - ZA[63] = ZA[41] + ZA[61]; - ZA[85] = ZA[78] + K[27]; - - ZA[37] = ZR25(ZA[35]) + ZA[3]; - ZA[79] = ZR15(ZA[70]) + ZA[63]; - ZA[312] = ZA[293] + ZA[311]; - ZA[313] = ZA[311] + ZA[309]; - ZA[300] = ZA[297] + ZA[85]; - - ZA[316] = (ZCh(ZA[312], ZA[307], ZA[302]) + ZA[300]) + ZR26(ZA[312]); - ZA[314] = ZMa(ZA[308], ZA[303], ZA[313]) + ZR30(ZA[313]); - ZA[9] = ZR25(ZA[7]); - ZA[86] = ZA[79] + K[28]; - ZA[57] = ZA[37] + ZA[53]; - - ZA[87] = ZR15(ZA[78]) + ZA[57]; - ZA[318] = ZA[316] + ZA[314]; - ZA[317] = ZA[298] + ZA[316]; - ZA[305] = ZA[302] + ZA[86]; - ZA[46] = ZA[35] + ZA[9]; - - ZA[321] = (ZCh(ZA[317], ZA[312], ZA[307]) + ZA[305]) + ZR26(ZA[317]); - ZA[319] = ZMa(ZA[313], ZA[308], ZA[318]) + ZR30(ZA[318]); - ZA[71] = ZA[46] + ZA[66]; - ZA[92] = ZA[87] + K[29]; - - ZA[42] = ZR25(ZA[38]) + ZA[7]; - ZA[88] = ZR15(ZA[79]) + ZA[71]; - ZA[322] = ZA[303] + ZA[321]; - ZA[323] = ZA[321] + ZA[319]; - ZA[310] = ZA[307] + ZA[92]; - - ZA[326] = (ZCh(ZA[322], ZA[317], ZA[312]) + ZA[310]) + ZR26(ZA[322]); - ZA[324] = ZMa(ZA[318], ZA[313], ZA[323]) + ZR30(ZA[323]); - ZA[14] = ZR25(ZA[10]); - ZA[93] = ZA[88] + K[30]; - ZA[72] = ZA[42] + ZA[67]; - - ZA[94] = ZR15(ZA[87]) + ZA[72]; - ZA[328] = ZA[326] + ZA[324]; - ZA[327] = ZA[308] + ZA[326]; - ZA[315] = ZA[312] + ZA[93]; - ZA[51] = ZA[38] + ZA[14]; - - ZA[331] = (ZCh(ZA[327], ZA[322], ZA[317]) + ZA[315]) + ZR26(ZA[327]); - ZA[329] = ZMa(ZA[323], ZA[318], ZA[328]) + ZR30(ZA[328]); - ZA[80] = ZA[51] + ZA[75]; - ZA[100] = ZA[94] + K[31]; - - ZA[47] = ZR25(ZA[43]) + ZA[10]; - ZA[95] = ZR15(ZA[88]) + ZA[80]; - ZA[332] = ZA[313] + ZA[331]; - ZA[333] = ZA[331] + ZA[329]; - ZA[320] = ZA[317] + ZA[100]; - - ZA[336] = (ZCh(ZA[332], ZA[327], ZA[322]) + ZA[320]) + ZR26(ZA[332]); - ZA[334] = ZMa(ZA[328], ZA[323], ZA[333]) + ZR30(ZA[333]); - ZA[81] = ZA[47] + ZA[70]; - ZA[101] = ZA[95] + K[32]; - - ZA[58] = ZR25(ZA[52]) + ZA[43]; - ZA[102] = ZR15(ZA[94]) + ZA[81]; - ZA[337] = ZA[318] + ZA[336]; - ZA[338] = ZA[336] + ZA[334]; - ZA[325] = ZA[322] + ZA[101]; - - ZA[341] = (ZCh(ZA[337], ZA[332], ZA[327]) + ZA[325]) + ZR26(ZA[337]); - ZA[339] = ZMa(ZA[333], ZA[328], ZA[338]) + ZR30(ZA[338]); - ZA[89] = ZA[58] + ZA[78]; - ZA[108] = ZA[102] + K[33]; - - ZA[59] = ZR25(ZA[48]) + ZA[52]; - ZA[103] = ZR15(ZA[95]) + ZA[89]; - ZA[342] = ZA[323] + ZA[341]; - ZA[343] = ZA[341] + ZA[339]; - ZA[330] = ZA[327] + ZA[108]; - - ZA[346] = (ZCh(ZA[342], ZA[337], ZA[332]) + ZA[330]) + ZR26(ZA[342]); - ZA[344] = ZMa(ZA[338], ZA[333], ZA[343]) + ZR30(ZA[343]); - ZA[90] = ZA[59] + ZA[79]; - ZA[109] = ZA[103] + K[34]; - - ZA[64] = ZR25(ZA[61]) + ZA[48]; - ZA[110] = ZR15(ZA[102]) + ZA[90]; - ZA[347] = ZA[328] + ZA[346]; - ZA[348] = ZA[346] + ZA[344]; - ZA[335] = ZA[332] + ZA[109]; - - ZA[351] = (ZCh(ZA[347], ZA[342], ZA[337]) + ZA[335]) + ZR26(ZA[347]); - ZA[349] = ZMa(ZA[343], ZA[338], ZA[348]) + ZR30(ZA[348]); - ZA[60] = ZR25(ZA[53]); - ZA[116] = ZA[110] + K[35]; - ZA[96] = ZA[87] + ZA[64]; - - ZA[111] = ZR15(ZA[103]) + ZA[96]; - ZA[353] = ZA[351] + ZA[349]; - ZA[352] = ZA[333] + ZA[351]; - ZA[340] = ZA[337] + ZA[116]; - ZA[65] = ZA[60] + ZA[61]; - - ZA[356] = (ZCh(ZA[352], ZA[347], ZA[342]) + ZA[340]) + ZR26(ZA[352]); - ZA[354] = ZMa(ZA[348], ZA[343], ZA[353]) + ZR30(ZA[353]); - ZA[97] = ZA[88] + ZA[65]; - ZA[117] = ZA[111] + K[36]; - - ZA[73] = ZR25(ZA[66]) + ZA[53]; - ZA[118] = ZR15(ZA[110]) + ZA[97]; - ZA[357] = ZA[338] + ZA[356]; - ZA[358] = ZA[356] + ZA[354]; - ZA[345] = ZA[342] + ZA[117]; - - ZA[361] = (ZCh(ZA[357], ZA[352], ZA[347]) + ZA[345]) + ZR26(ZA[357]); - ZA[359] = ZMa(ZA[353], ZA[348], ZA[358]) + ZR30(ZA[358]); - ZA[104] = ZA[73] + ZA[94]; - ZA[124] = ZA[118] + K[37]; - - ZA[74] = ZR25(ZA[67]) + ZA[66]; - ZA[119] = ZR15(ZA[111]) + ZA[104]; - ZA[362] = ZA[343] + ZA[361]; - ZA[363] = ZA[361] + ZA[359]; - ZA[350] = ZA[347] + ZA[124]; - - ZA[366] = (ZCh(ZA[362], ZA[357], ZA[352]) + ZA[350]) + ZR26(ZA[362]); - ZA[364] = ZMa(ZA[358], ZA[353], ZA[363]) + ZR30(ZA[363]); - ZA[105] = ZA[74] + ZA[95]; - ZA[125] = ZA[119] + K[38]; - - ZA[82] = ZR25(ZA[75]) + ZA[67]; - ZA[126] = ZR15(ZA[118]) + ZA[105]; - ZA[367] = ZA[348] + ZA[366]; - ZA[368] = ZA[366] + ZA[364]; - ZA[355] = ZA[352] + ZA[125]; - - ZA[371] = (ZCh(ZA[367], ZA[362], ZA[357]) + ZA[355]) + ZR26(ZA[367]); - ZA[369] = ZMa(ZA[363], ZA[358], ZA[368]) + ZR30(ZA[368]); - ZA[112] = ZA[102] + ZA[82]; - ZA[132] = ZA[126] + K[39]; - - ZA[83] = ZR25(ZA[70]) + ZA[75]; - ZA[127] = ZR15(ZA[119]) + ZA[112]; - ZA[372] = ZA[353] + ZA[371]; - ZA[373] = ZA[371] + ZA[369]; - ZA[360] = ZA[357] + ZA[132]; - - ZA[376] = (ZCh(ZA[372], ZA[367], ZA[362]) + ZA[360]) + ZR26(ZA[372]); - ZA[374] = ZMa(ZA[368], ZA[363], ZA[373]) + ZR30(ZA[373]); - ZA[113] = ZA[103] + ZA[83]; - ZA[133] = ZA[127] + K[40]; - - ZA[84] = ZR25(ZA[78]) + ZA[70]; - ZA[134] = ZR15(ZA[126]) + ZA[113]; - ZA[377] = ZA[358] + ZA[376]; - ZA[378] = ZA[376] + ZA[374]; - ZA[365] = ZA[362] + ZA[133]; - - ZA[381] = (ZCh(ZA[377], ZA[372], ZA[367]) + ZA[365]) + ZR26(ZA[377]); - ZA[379] = ZMa(ZA[373], ZA[368], ZA[378]) + ZR30(ZA[378]); - ZA[120] = ZA[110] + ZA[84]; - ZA[140] = ZA[134] + K[41]; - - ZA[91] = ZR25(ZA[79]) + ZA[78]; - ZA[135] = ZR15(ZA[127]) + ZA[120]; - ZA[382] = ZA[363] + ZA[381]; - ZA[383] = ZA[381] + ZA[379]; - ZA[370] = ZA[367] + ZA[140]; - - ZA[386] = (ZCh(ZA[382], ZA[377], ZA[372]) + ZA[370]) + ZR26(ZA[382]); - ZA[384] = ZMa(ZA[378], ZA[373], ZA[383]) + ZR30(ZA[383]); - ZA[121] = ZA[111] + ZA[91]; - ZA[141] = ZA[135] + K[42]; - - ZA[98] = ZR25(ZA[87]) + ZA[79]; - ZA[142] = ZR15(ZA[134]) + ZA[121]; - ZA[387] = ZA[368] + ZA[386]; - ZA[388] = ZA[386] + ZA[384]; - ZA[375] = ZA[372] + ZA[141]; - - ZA[391] = (ZCh(ZA[387], ZA[382], ZA[377]) + ZA[375]) + ZR26(ZA[387]); - ZA[389] = ZMa(ZA[383], ZA[378], ZA[388]) + ZR30(ZA[388]); - ZA[128] = ZA[118] + ZA[98]; - ZA[147] = ZA[142] + K[43]; - - ZA[99] = ZR25(ZA[88]) + ZA[87]; - ZA[143] = ZR15(ZA[135]) + ZA[128]; - ZA[392] = ZA[373] + ZA[391]; - ZA[393] = ZA[391] + ZA[389]; - ZA[380] = ZA[377] + ZA[147]; - - ZA[396] = (ZCh(ZA[392], ZA[387], ZA[382]) + ZA[380]) + ZR26(ZA[392]); - ZA[394] = ZMa(ZA[388], ZA[383], ZA[393]) + ZR30(ZA[393]); - ZA[129] = ZA[119] + ZA[99]; - ZA[148] = ZA[143] + K[44]; - - ZA[106] = ZR25(ZA[94]) + ZA[88]; - ZA[149] = ZR15(ZA[142]) + ZA[129]; - ZA[397] = ZA[378] + ZA[396]; - ZA[398] = ZA[396] + ZA[394]; - ZA[385] = ZA[382] + ZA[148]; - - ZA[401] = (ZCh(ZA[397], ZA[392], ZA[387]) + ZA[385]) + ZR26(ZA[397]); - ZA[399] = ZMa(ZA[393], ZA[388], ZA[398]) + ZR30(ZA[398]); - ZA[136] = ZA[126] + ZA[106]; - ZA[153] = ZA[149] + K[45]; - - ZA[107] = ZR25(ZA[95]) + ZA[94]; - ZA[150] = ZR15(ZA[143]) + ZA[136]; - ZA[402] = ZA[383] + ZA[401]; - ZA[403] = ZA[401] + ZA[399]; - ZA[390] = ZA[387] + ZA[153]; - - ZA[406] = (ZCh(ZA[402], ZA[397], ZA[392]) + ZA[390]) + ZR26(ZA[402]); - ZA[404] = ZMa(ZA[398], ZA[393], ZA[403]) + ZR30(ZA[403]); - ZA[137] = ZA[127] + ZA[107]; - ZA[154] = ZA[150] + K[46]; - - ZA[114] = ZR25(ZA[102]) + ZA[95]; - ZA[155] = ZR15(ZA[149]) + ZA[137]; - ZA[407] = ZA[388] + ZA[406]; - ZA[408] = ZA[406] + ZA[404]; - ZA[395] = ZA[392] + ZA[154]; - - ZA[411] = (ZCh(ZA[407], ZA[402], ZA[397]) + ZA[395]) + ZR26(ZA[407]); - ZA[409] = ZMa(ZA[403], ZA[398], ZA[408]) + ZR30(ZA[408]); - ZA[144] = ZA[134] + ZA[114]; - ZA[159] = ZA[155] + K[47]; - - ZA[115] = ZR25(ZA[103]) + ZA[102]; - ZA[156] = ZR15(ZA[150]) + ZA[144]; - ZA[412] = ZA[393] + ZA[411]; - ZA[413] = ZA[411] + ZA[409]; - ZA[400] = ZA[397] + ZA[159]; - - ZA[416] = (ZCh(ZA[412], ZA[407], ZA[402]) + ZA[400]) + ZR26(ZA[412]); - ZA[414] = ZMa(ZA[408], ZA[403], ZA[413]) + ZR30(ZA[413]); - ZA[145] = ZA[135] + ZA[115]; - ZA[160] = ZA[156] + K[48]; - - ZA[122] = ZR25(ZA[110]) + ZA[103]; - ZA[161] = ZR15(ZA[155]) + ZA[145]; - ZA[417] = ZA[398] + ZA[416]; - ZA[418] = ZA[416] + ZA[414]; - ZA[405] = ZA[402] + ZA[160]; - - ZA[421] = (ZCh(ZA[417], ZA[412], ZA[407]) + ZA[405]) + ZR26(ZA[417]); - ZA[419] = ZMa(ZA[413], ZA[408], ZA[418]) + ZR30(ZA[418]); - ZA[151] = ZA[142] + ZA[122]; - ZA[165] = ZA[161] + K[49]; - - ZA[123] = ZR25(ZA[111]) + ZA[110]; - ZA[162] = ZR15(ZA[156]) + ZA[151]; - ZA[422] = ZA[403] + ZA[421]; - ZA[423] = ZA[421] + ZA[419]; - ZA[410] = ZA[407] + ZA[165]; - - ZA[426] = (ZCh(ZA[422], ZA[417], ZA[412]) + ZA[410]) + ZR26(ZA[422]); - ZA[424] = ZMa(ZA[418], ZA[413], ZA[423]) + ZR30(ZA[423]); - ZA[152] = ZA[143] + ZA[123]; - ZA[166] = ZA[162] + K[50]; - - ZA[130] = ZR25(ZA[118]) + ZA[111]; - ZA[167] = ZR15(ZA[161]) + ZA[152]; - ZA[427] = ZA[408] + ZA[426]; - ZA[428] = ZA[426] + ZA[424]; - ZA[415] = ZA[412] + ZA[166]; - - ZA[431] = (ZCh(ZA[427], ZA[422], ZA[417]) + ZA[415]) + ZR26(ZA[427]); - ZA[429] = ZMa(ZA[423], ZA[418], ZA[428]) + ZR30(ZA[428]); - ZA[157] = ZA[149] + ZA[130]; - ZA[170] = ZA[167] + K[51]; - - ZA[131] = ZR25(ZA[119]) + ZA[118]; - ZA[168] = ZR15(ZA[162]) + ZA[157]; - ZA[432] = ZA[413] + ZA[431]; - ZA[433] = ZA[431] + ZA[429]; - ZA[420] = ZA[417] + ZA[170]; - - ZA[436] = (ZCh(ZA[432], ZA[427], ZA[422]) + ZA[420]) + ZR26(ZA[432]); - ZA[434] = ZMa(ZA[428], ZA[423], ZA[433]) + ZR30(ZA[433]); - ZA[158] = ZA[150] + ZA[131]; - ZA[171] = ZA[168] + K[52]; - - ZA[138] = ZR25(ZA[126]) + ZA[119]; - ZA[172] = ZR15(ZA[167]) + ZA[158]; - ZA[437] = ZA[418] + ZA[436]; - ZA[438] = ZA[436] + ZA[434]; - ZA[425] = ZA[422] + ZA[171]; - - ZA[441] = (ZCh(ZA[437], ZA[432], ZA[427]) + ZA[425]) + ZR26(ZA[437]); - ZA[439] = ZMa(ZA[433], ZA[428], ZA[438]) + ZR30(ZA[438]); - ZA[163] = ZA[155] + ZA[138]; - ZA[174] = ZA[172] + K[53]; - - ZA[139] = ZR25(ZA[127]) + ZA[126]; - ZA[173] = ZR15(ZA[168]) + ZA[163]; - ZA[442] = ZA[423] + ZA[441]; - ZA[443] = ZA[441] + ZA[439]; - ZA[430] = ZA[427] + ZA[174]; - - ZA[445] = (ZCh(ZA[442], ZA[437], ZA[432]) + ZA[430]) + ZR26(ZA[442]); - ZA[444] = ZMa(ZA[438], ZA[433], ZA[443]) + ZR30(ZA[443]); - ZA[164] = ZA[156] + ZA[139]; - ZA[175] = ZA[173] + K[54]; - - ZA[146] = ZR25(ZA[134]) + ZA[127]; - ZA[176] = ZR15(ZA[172]) + ZA[164]; - ZA[446] = ZA[428] + ZA[445]; - ZA[447] = ZA[445] + ZA[444]; - ZA[435] = ZA[432] + ZA[175]; - - ZA[449] = (ZCh(ZA[446], ZA[442], ZA[437]) + ZA[435]) + ZR26(ZA[446]); - ZA[448] = ZMa(ZA[443], ZA[438], ZA[447]) + ZR30(ZA[447]); - ZA[169] = ZA[161] + ZA[146]; - ZA[178] = ZA[176] + K[55]; - - ZA[177] = ZR15(ZA[173]) + ZA[169]; - ZA[451] = ZA[449] + ZA[448]; - ZA[450] = ZA[433] + ZA[449]; - ZA[440] = ZA[437] + ZA[178]; - - ZA[453] = (ZCh(ZA[450], ZA[446], ZA[442]) + ZA[440]) + ZR26(ZA[450]); - ZA[452] = ZMa(ZA[447], ZA[443], ZA[451]) + ZR30(ZA[451]); - ZA[179] = ZA[177] + K[56]; - - ZA[454] = ZA[438] + ZA[453]; - ZA[494] = ZA[442] + ZA[179]; - ZA[455] = ZA[453] + ZA[452]; - - ZA[457] = (ZCh(ZA[454], ZA[450], ZA[446]) + ZA[494]) + ZR26(ZA[454]); - ZA[456] = ZMa(ZA[451], ZA[447], ZA[455]) + ZR30(ZA[455]); - - ZA[459] = ZA[457] + ZA[456]; - - ZA[461] = ZA[455] + state1; - ZA[460] = ZA[459] + state0; - - ZA[495] = ZA[460] + K[57]; - ZA[469] = ZA[461] + K[58]; - - ZA[498] = (ZCh(ZA[495], K[59], K[60]) + ZA[469]) + ZR26(ZA[495]); - ZA[462] = ZA[451] + state2; - - ZA[496] = ZA[460] + K[61]; - ZA[506] = ZA[498] + K[62]; - ZA[470] = ZA[462] + K[63]; - - ZA[507] = (ZCh(ZA[506], ZA[495], K[59]) + ZA[470]) + ZR26(ZA[506]); - ZA[500] = ZMa(K[64], K[65], ZA[496]) + ZR30(ZA[496]); - ZA[463] = ZA[447] + state3; - - ZA[458] = ZA[443] + ZA[457]; - ZA[499] = ZA[498] + ZA[500]; - ZA[508] = ZA[507] + K[65]; - ZA[473] = ZA[463] + K[66]; - - ZA[510] = (ZCh(ZA[508], ZA[506], ZA[495]) + ZA[473]) + ZR26(ZA[508]); - ZA[928] = ZMa(ZA[496], K[64], ZA[499]) + ZR30(ZA[499]); - ZA[464] = ZA[458] + state4; - - ZA[476] = ZA[464] + ZA[460] + K[67]; - ZA[511] = ZA[510] + K[64]; - ZA[509] = ZA[928] + ZA[507]; - ZA[465] = ZA[454] + state5; - - ZA[514] = (ZCh(ZA[511], ZA[508], ZA[506]) + ZA[476]) + ZR26(ZA[511]); - ZA[512] = ZMa(ZA[499], ZA[496], ZA[509]) + ZR30(ZA[509]); - ZA[478] = ZA[465] + K[68]; - - ZA[519] = ZA[506] + ZA[478]; - ZA[516] = ZA[496] + ZA[514]; - ZA[513] = ZA[510] + ZA[512]; - ZA[466] = ZA[450] + state6; - - ZA[520] = (ZCh(ZA[516], ZA[511], ZA[508]) + ZA[519]) + ZR26(ZA[516]); - ZA[515] = ZMa(ZA[509], ZA[499], ZA[513]) + ZR30(ZA[513]); - ZA[480] = ZA[466] + K[69]; - - ZA[524] = ZA[508] + ZA[480]; - ZA[521] = ZA[499] + ZA[520]; - ZA[517] = ZA[514] + ZA[515]; - ZA[467] = ZA[446] + state7; - - ZA[525] = (ZCh(ZA[521], ZA[516], ZA[511]) + ZA[524]) + ZR26(ZA[521]); - ZA[522] = ZMa(ZA[513], ZA[509], ZA[517]) + ZR30(ZA[517]); - ZA[484] = ZA[467] + K[70]; - - ZA[529] = ZA[511] + ZA[484]; - ZA[526] = ZA[509] + ZA[525]; - ZA[523] = ZA[520] + ZA[522]; - - ZA[530] = (ZCh(ZA[526], ZA[521], ZA[516]) + ZA[529]) + ZR26(ZA[526]); - ZA[550] = ZMa(ZA[517], ZA[513], ZA[523]) + ZR30(ZA[523]); - - ZA[531] = ZA[513] + ZA[530]; - ZA[533] = ZA[516] + K[71]; - ZA[527] = ZA[550] + ZA[525]; - - ZA[534] = (ZCh(ZA[531], ZA[526], ZA[521]) + ZA[533]) + ZR26(ZA[531]); - ZA[551] = ZMa(ZA[523], ZA[517], ZA[527]) + ZR30(ZA[527]); - - ZA[535] = ZA[517] + ZA[534]; - ZA[538] = ZA[521] + K[1]; - ZA[532] = ZA[551] + ZA[530]; - - ZA[539] = (ZCh(ZA[535], ZA[531], ZA[526]) + ZA[538]) + ZR26(ZA[535]); - ZA[552] = ZMa(ZA[527], ZA[523], ZA[532]) + ZR30(ZA[532]); - - ZA[540] = ZA[523] + ZA[539]; - ZA[542] = ZA[526] + K[2]; - ZA[536] = ZA[552] + ZA[534]; - - ZA[543] = (ZCh(ZA[540], ZA[535], ZA[531]) + ZA[542]) + ZR26(ZA[540]); - ZA[553] = ZMa(ZA[532], ZA[527], ZA[536]) + ZR30(ZA[536]); - - ZA[544] = ZA[527] + ZA[543]; - ZA[555] = ZA[531] + K[3]; - ZA[541] = ZA[553] + ZA[539]; - - ZA[558] = (ZCh(ZA[544], ZA[540], ZA[535]) + ZA[555]) + ZR26(ZA[544]); - ZA[547] = ZMa(ZA[536], ZA[532], ZA[541]) + ZR30(ZA[541]); - - ZA[559] = ZA[532] + ZA[558]; - ZA[556] = ZA[535] + K[4]; - ZA[545] = ZA[547] + ZA[543]; - - ZA[562] = (ZCh(ZA[559], ZA[544], ZA[540]) + ZA[556]) + ZR26(ZA[559]); - ZA[561] = ZMa(ZA[541], ZA[536], ZA[545]) + ZR30(ZA[545]); - - ZA[563] = ZA[536] + ZA[562]; - ZA[560] = ZA[561] + ZA[558]; - ZA[557] = ZA[540] + K[5]; - - ZA[568] = (ZCh(ZA[563], ZA[559], ZA[544]) + ZA[557]) + ZR26(ZA[563]); - ZA[564] = ZMa(ZA[545], ZA[541], ZA[560]) + ZR30(ZA[560]); - - ZA[569] = ZA[541] + ZA[568]; - ZA[572] = ZA[544] + K[6]; - ZA[565] = ZA[562] + ZA[564]; - - ZA[574] = (ZCh(ZA[569], ZA[563], ZA[559]) + ZA[572]) + ZR26(ZA[569]); - ZA[570] = ZMa(ZA[560], ZA[545], ZA[565]) + ZR30(ZA[565]); - ZA[468] = ZR25(ZA[461]); - - ZA[497] = ZA[468] + ZA[460]; - ZA[575] = ZA[545] + ZA[574]; - ZA[571] = ZA[568] + ZA[570]; - ZA[573] = ZA[559] + K[72]; - - ZA[578] = (ZCh(ZA[575], ZA[569], ZA[563]) + ZA[573]) + ZR26(ZA[575]); - ZA[576] = ZMa(ZA[565], ZA[560], ZA[571]) + ZR30(ZA[571]); - ZA[929] = ZR25(ZA[462]); - ZA[503] = ZA[497] + 0xe49b69c1U; - - ZA[471] = ZA[929] + ZA[461] + K[74]; - ZA[582] = ZA[563] + ZA[503]; - ZA[579] = ZA[560] + ZA[578]; - ZA[577] = ZA[574] + ZA[576]; - - ZA[583] = (ZCh(ZA[579], ZA[575], ZA[569]) + ZA[582]) + ZR26(ZA[579]); - ZA[580] = ZMa(ZA[571], ZA[565], ZA[577]) + ZR30(ZA[577]); - ZA[488] = ZA[471] + K[75]; - - ZA[472] = ZR25(ZA[463]) + ZA[462]; - ZA[587] = ZA[569] + ZA[488]; - ZA[584] = ZA[565] + ZA[583]; - ZA[581] = ZA[578] + ZA[580]; - - ZA[588] = (ZCh(ZA[584], ZA[579], ZA[575]) + ZA[587]) + ZR26(ZA[584]); - ZA[586] = ZMa(ZA[577], ZA[571], ZA[581]) + ZR30(ZA[581]); - ZA[501] = ZR15(ZA[497]) + ZA[472]; - ZA[475] = ZR15(ZA[471]); - ZA[926] = ZA[575] + K[8]; - - ZA[474] = ZA[475] + ZA[463] + ZR25(ZA[464]); - ZA[927] = ZA[926] + ZA[501]; - ZA[589] = ZA[571] + ZA[588]; - ZA[585] = ZA[583] + ZA[586]; - - ZA[592] = (ZCh(ZA[589], ZA[584], ZA[579]) + ZA[927]) + ZR26(ZA[589]); - ZA[590] = ZMa(ZA[581], ZA[577], ZA[585]) + ZR30(ZA[585]); - ZA[477] = ZR25(ZA[465]) + ZA[464]; - ZA[489] = ZA[474] + K[9]; - - ZA[518] = ZR15(ZA[501]) + ZA[477]; - ZA[479] = ZR25(ZA[466]); - ZA[596] = ZA[579] + ZA[489]; - ZA[593] = ZA[577] + ZA[592]; - ZA[591] = ZA[588] + ZA[590]; - - ZA[597] = (ZCh(ZA[593], ZA[589], ZA[584]) + ZA[596]) + ZR26(ZA[593]); - ZA[594] = ZMa(ZA[585], ZA[581], ZA[591]) + ZR30(ZA[591]); - ZA[481] = ZA[479] + ZA[465]; - ZA[601] = ZA[518] + K[11]; - - ZA[482] = ZR15(ZA[474]) + ZA[481]; - ZA[602] = ZA[584] + ZA[601]; - ZA[598] = ZA[581] + ZA[597]; - ZA[595] = ZA[592] + ZA[594]; - - ZA[632] = (ZCh(ZA[598], ZA[593], ZA[589]) + ZA[602]) + ZR26(ZA[598]); - ZA[599] = ZMa(ZA[591], ZA[585], ZA[595]) + ZR30(ZA[595]); - ZA[483] = ZA[466] + K[76] + ZR25(ZA[467]); - ZA[490] = ZA[482] + K[12]; - - ZA[528] = ZR15(ZA[518]) + ZA[483]; - ZA[736] = ZA[585] + ZA[632]; - ZA[605] = ZA[589] + ZA[490]; - ZA[600] = ZA[597] + ZA[599]; - ZA[485] = ZA[467] + K[77]; - - ZA[738] = (ZCh(ZA[736], ZA[598], ZA[593]) + ZA[605]) + ZR26(ZA[736]); - ZA[744] = ZMa(ZA[595], ZA[591], ZA[600]) + ZR30(ZA[600]); - ZA[487] = ZR15(ZA[482]) + ZA[485]; - ZA[603] = ZA[528] + K[14]; - - ZA[502] = ZA[497] + ZA[487]; - ZA[739] = ZA[591] + ZA[738]; - ZA[604] = ZA[593] + ZA[603]; - ZA[737] = ZA[744] + ZA[632]; - - ZA[741] = (ZCh(ZA[739], ZA[736], ZA[598]) + ZA[604]) + ZR26(ZA[739]); - ZA[745] = ZMa(ZA[600], ZA[595], ZA[737]) + ZR30(ZA[737]); - ZA[486] = ZA[471] + K[10]; - ZA[606] = ZA[502] + K[15]; - - ZA[537] = ZR15(ZA[528]) + ZA[486]; - ZA[742] = ZA[595] + ZA[741]; - ZA[613] = ZA[598] + ZA[606]; - ZA[740] = ZA[745] + ZA[738]; - - ZA[747] = (ZCh(ZA[742], ZA[739], ZA[736]) + ZA[613]) + ZR26(ZA[742]); - ZA[746] = ZMa(ZA[737], ZA[600], ZA[740]) + ZR30(ZA[740]); - ZA[607] = ZA[537] + K[16]; - - ZA[546] = ZR15(ZA[502]) + ZA[501]; - ZA[751] = ZA[736] + ZA[607]; - ZA[748] = ZA[600] + ZA[747]; - ZA[743] = ZA[746] + ZA[741]; - - ZA[752] = (ZCh(ZA[748], ZA[742], ZA[739]) + ZA[751]) + ZR26(ZA[748]); - ZA[749] = ZMa(ZA[740], ZA[737], ZA[743]) + ZR30(ZA[743]); - ZA[608] = ZA[546] + K[17]; - - ZA[554] = ZR15(ZA[537]) + ZA[474]; - ZA[756] = ZA[739] + ZA[608]; - ZA[753] = ZA[737] + ZA[752]; - ZA[750] = ZA[747] + ZA[749]; - - ZA[757] = (ZCh(ZA[753], ZA[748], ZA[742]) + ZA[756]) + ZR26(ZA[753]); - ZA[754] = ZMa(ZA[743], ZA[740], ZA[750]) + ZR30(ZA[750]); - ZA[609] = ZA[554] + K[18]; - - ZA[566] = ZR15(ZA[546]) + ZA[518]; - ZA[761] = ZA[742] + ZA[609]; - ZA[758] = ZA[740] + ZA[757]; - ZA[755] = ZA[752] + ZA[754]; - - ZA[762] = (ZCh(ZA[758], ZA[753], ZA[748]) + ZA[761]) + ZR26(ZA[758]); - ZA[759] = ZMa(ZA[750], ZA[743], ZA[755]) + ZR30(ZA[755]); - ZA[610] = ZA[566] + K[19]; - - ZA[567] = ZR15(ZA[554]) + ZA[482]; - ZA[766] = ZA[748] + ZA[610]; - ZA[763] = ZA[743] + ZA[762]; - ZA[760] = ZA[757] + ZA[759]; - - ZA[767] = (ZCh(ZA[763], ZA[758], ZA[753]) + ZA[766]) + ZR26(ZA[763]); - ZA[764] = ZMa(ZA[755], ZA[750], ZA[760]) + ZR30(ZA[760]); - ZA[611] = ZA[567] + K[20]; - - ZA[614] = ZR15(ZA[566]) + ZA[528]; - ZA[771] = ZA[753] + ZA[611]; - ZA[768] = ZA[750] + ZA[767]; - ZA[765] = ZA[762] + ZA[764]; - - ZA[772] = (ZCh(ZA[768], ZA[763], ZA[758]) + ZA[771]) + ZR26(ZA[768]); - ZA[769] = ZMa(ZA[760], ZA[755], ZA[765]) + ZR30(ZA[765]); - ZA[612] = ZA[502] + K[78]; - ZA[615] = ZA[614] + K[22]; - - ZA[616] = ZR15(ZA[567]) + ZA[612]; - ZA[504] = ZR25(ZA[497]) + K[76]; - ZA[776] = ZA[758] + ZA[615]; - ZA[773] = ZA[755] + ZA[772]; - ZA[770] = ZA[767] + ZA[769]; - - ZA[777] = (ZCh(ZA[773], ZA[768], ZA[763]) + ZA[776]) + ZR26(ZA[773]); - ZA[774] = ZMa(ZA[765], ZA[760], ZA[770]) + ZR30(ZA[770]); - ZA[492] = ZR25(ZA[471]); - ZA[618] = ZA[537] + ZA[504]; - ZA[617] = ZA[616] + K[23]; - - ZA[619] = ZR15(ZA[614]) + ZA[618]; - ZA[781] = ZA[763] + ZA[617]; - ZA[778] = ZA[760] + ZA[777]; - ZA[775] = ZA[772] + ZA[774]; - ZA[505] = ZA[492] + ZA[497]; - - ZA[782] = (ZCh(ZA[778], ZA[773], ZA[768]) + ZA[781]) + ZR26(ZA[778]); - ZA[779] = ZMa(ZA[770], ZA[765], ZA[775]) + ZR30(ZA[775]); - ZA[621] = ZA[505] + ZA[546]; - ZA[620] = ZA[619] + K[24]; - - ZA[622] = ZR15(ZA[616]) + ZA[621]; - ZA[625] = ZR25(ZA[501]); - ZA[786] = ZA[768] + ZA[620]; - ZA[783] = ZA[765] + ZA[782]; - ZA[624] = ZA[554] + ZA[471]; - ZA[780] = ZA[777] + ZA[779]; - - ZA[787] = (ZCh(ZA[783], ZA[778], ZA[773]) + ZA[786]) + ZR26(ZA[783]); - ZA[784] = ZMa(ZA[775], ZA[770], ZA[780]) + ZR30(ZA[780]); - ZA[493] = ZR25(ZA[474]); - ZA[626] = ZA[625] + ZA[624]; - ZA[623] = ZA[622] + K[25]; - - ZA[627] = ZR15(ZA[619]) + ZA[626]; - ZA[791] = ZA[773] + ZA[623]; - ZA[788] = ZA[770] + ZA[787]; - ZA[785] = ZA[782] + ZA[784]; - ZA[629] = ZA[493] + ZA[501]; - - ZA[792] = (ZCh(ZA[788], ZA[783], ZA[778]) + ZA[791]) + ZR26(ZA[788]); - ZA[789] = ZMa(ZA[780], ZA[775], ZA[785]) + ZR30(ZA[785]); - ZA[630] = ZA[566] + ZA[629]; - ZA[628] = ZA[627] + K[26]; - - ZA[634] = ZR25(ZA[518]) + ZA[474]; - ZA[631] = ZR15(ZA[622]) + ZA[630]; - ZA[796] = ZA[778] + ZA[628]; - ZA[793] = ZA[775] + ZA[792]; - ZA[790] = ZA[787] + ZA[789]; - - ZA[797] = (ZCh(ZA[793], ZA[788], ZA[783]) + ZA[796]) + ZR26(ZA[793]); - ZA[794] = ZMa(ZA[785], ZA[780], ZA[790]) + ZR30(ZA[790]); - ZA[491] = ZR25(ZA[482]); - ZA[635] = ZA[567] + ZA[634]; - ZA[633] = ZA[631] + K[27]; - - ZA[636] = ZR15(ZA[627]) + ZA[635]; - ZA[801] = ZA[783] + ZA[633]; - ZA[798] = ZA[780] + ZA[797]; - ZA[795] = ZA[792] + ZA[794]; - ZA[638] = ZA[491] + ZA[518]; - - ZA[802] = (ZCh(ZA[798], ZA[793], ZA[788]) + ZA[801]) + ZR26(ZA[798]); - ZA[799] = ZMa(ZA[790], ZA[785], ZA[795]) + ZR30(ZA[795]); - ZA[639] = ZA[638] + ZA[614]; - ZA[637] = ZA[636] + K[28]; - - ZA[642] = ZR25(ZA[528]) + ZA[482]; - ZA[640] = ZR15(ZA[631]) + ZA[639]; - ZA[806] = ZA[788] + ZA[637]; - ZA[803] = ZA[785] + ZA[802]; - ZA[800] = ZA[797] + ZA[799]; - - ZA[807] = (ZCh(ZA[803], ZA[798], ZA[793]) + ZA[806]) + ZR26(ZA[803]); - ZA[804] = ZMa(ZA[795], ZA[790], ZA[800]) + ZR30(ZA[800]); - ZA[643] = ZA[616] + ZA[642]; - ZA[641] = ZA[640] + K[29]; - - ZA[646] = ZR25(ZA[502]) + ZA[528]; - ZA[644] = ZR15(ZA[636]) + ZA[643]; - ZA[811] = ZA[793] + ZA[641]; - ZA[808] = ZA[790] + ZA[807]; - ZA[805] = ZA[802] + ZA[804]; - - ZA[812] = (ZCh(ZA[808], ZA[803], ZA[798]) + ZA[811]) + ZR26(ZA[808]); - ZA[809] = ZMa(ZA[800], ZA[795], ZA[805]) + ZR30(ZA[805]); - ZA[647] = ZA[619] + ZA[646]; - ZA[645] = ZA[644] + K[30]; - - ZA[650] = ZR25(ZA[537]) + ZA[502]; - ZA[648] = ZR15(ZA[640]) + ZA[647]; - ZA[816] = ZA[798] + ZA[645]; - ZA[813] = ZA[795] + ZA[812]; - ZA[810] = ZA[807] + ZA[809]; - - ZA[817] = (ZCh(ZA[813], ZA[808], ZA[803]) + ZA[816]) + ZR26(ZA[813]); - ZA[814] = ZMa(ZA[805], ZA[800], ZA[810]) + ZR30(ZA[810]); - ZA[925] = ZA[622] + ZA[650]; - ZA[649] = ZA[648] + K[31]; - - ZA[653] = ZR25(ZA[546]) + ZA[537]; - ZA[651] = ZR15(ZA[644]) + ZA[925]; - ZA[821] = ZA[803] + ZA[649]; - ZA[818] = ZA[800] + ZA[817]; - ZA[815] = ZA[812] + ZA[814]; - - ZA[822] = (ZCh(ZA[818], ZA[813], ZA[808]) + ZA[821]) + ZR26(ZA[818]); - ZA[819] = ZMa(ZA[810], ZA[805], ZA[815]) + ZR30(ZA[815]); - ZA[654] = ZA[627] + ZA[653]; - ZA[652] = ZA[651] + K[32]; - - ZA[657] = ZR25(ZA[554]) + ZA[546]; - ZA[655] = ZR15(ZA[648]) + ZA[654]; - ZA[826] = ZA[808] + ZA[652]; - ZA[823] = ZA[805] + ZA[822]; - ZA[820] = ZA[817] + ZA[819]; - - ZA[827] = (ZCh(ZA[823], ZA[818], ZA[813]) + ZA[826]) + ZR26(ZA[823]); - ZA[824] = ZMa(ZA[815], ZA[810], ZA[820]) + ZR30(ZA[820]); - ZA[658] = ZA[631] + ZA[657]; - ZA[656] = ZA[655] + K[33]; - - ZA[661] = ZR25(ZA[566]) + ZA[554]; - ZA[659] = ZR15(ZA[651]) + ZA[658]; - ZA[831] = ZA[813] + ZA[656]; - ZA[828] = ZA[810] + ZA[827]; - ZA[825] = ZA[822] + ZA[824]; - - ZA[832] = (ZCh(ZA[828], ZA[823], ZA[818]) + ZA[831]) + ZR26(ZA[828]); - ZA[829] = ZMa(ZA[820], ZA[815], ZA[825]) + ZR30(ZA[825]); - ZA[662] = ZA[636] + ZA[661]; - ZA[660] = ZA[659] + K[34]; - - ZA[665] = ZR25(ZA[567]) + ZA[566]; - ZA[663] = ZR15(ZA[655]) + ZA[662]; - ZA[836] = ZA[818] + ZA[660]; - ZA[833] = ZA[815] + ZA[832]; - ZA[830] = ZA[827] + ZA[829]; - - ZA[837] = (ZCh(ZA[833], ZA[828], ZA[823]) + ZA[836]) + ZR26(ZA[833]); - ZA[834] = ZMa(ZA[825], ZA[820], ZA[830]) + ZR30(ZA[830]); - ZA[666] = ZA[640] + ZA[665]; - ZA[664] = ZA[663] + K[35]; - - ZA[669] = ZR25(ZA[614]) + ZA[567]; - ZA[667] = ZR15(ZA[659]) + ZA[666]; - ZA[841] = ZA[823] + ZA[664]; - ZA[838] = ZA[820] + ZA[837]; - ZA[835] = ZA[832] + ZA[834]; - - ZA[842] = (ZCh(ZA[838], ZA[833], ZA[828]) + ZA[841]) + ZR26(ZA[838]); - ZA[839] = ZMa(ZA[830], ZA[825], ZA[835]) + ZR30(ZA[835]); - ZA[670] = ZA[644] + ZA[669]; - ZA[668] = ZA[667] + K[36]; - - ZA[677] = ZR25(ZA[616]) + ZA[614]; - ZA[671] = ZR15(ZA[663]) + ZA[670]; - ZA[846] = ZA[828] + ZA[668]; - ZA[843] = ZA[825] + ZA[842]; - ZA[840] = ZA[837] + ZA[839]; - - ZA[847] = (ZCh(ZA[843], ZA[838], ZA[833]) + ZA[846]) + ZR26(ZA[843]); - ZA[844] = ZMa(ZA[835], ZA[830], ZA[840]) + ZR30(ZA[840]); - ZA[678] = ZA[648] + ZA[677]; - ZA[676] = ZA[671] + K[37]; - - ZA[682] = ZR25(ZA[619]) + ZA[616]; - ZA[679] = ZR15(ZA[667]) + ZA[678]; - ZA[851] = ZA[833] + ZA[676]; - ZA[848] = ZA[830] + ZA[847]; - ZA[845] = ZA[842] + ZA[844]; - - ZA[852] = (ZCh(ZA[848], ZA[843], ZA[838]) + ZA[851]) + ZR26(ZA[848]); - ZA[849] = ZMa(ZA[840], ZA[835], ZA[845]) + ZR30(ZA[845]); - ZA[683] = ZA[651] + ZA[682]; - ZA[680] = ZA[679] + K[38]; - - ZA[686] = ZR25(ZA[622]) + ZA[619]; - ZA[684] = ZR15(ZA[671]) + ZA[683]; - ZA[856] = ZA[838] + ZA[680]; - ZA[853] = ZA[835] + ZA[852]; - ZA[850] = ZA[847] + ZA[849]; - - ZA[857] = (ZCh(ZA[853], ZA[848], ZA[843]) + ZA[856]) + ZR26(ZA[853]); - ZA[854] = ZMa(ZA[845], ZA[840], ZA[850]) + ZR30(ZA[850]); - ZA[687] = ZA[655] + ZA[686]; - ZA[685] = ZA[684] + K[39]; - - ZA[690] = ZR25(ZA[627]) + ZA[622]; - ZA[688] = ZR15(ZA[679]) + ZA[687]; - ZA[861] = ZA[843] + ZA[685]; - ZA[858] = ZA[840] + ZA[857]; - ZA[855] = ZA[852] + ZA[854]; - - ZA[862] = (ZCh(ZA[858], ZA[853], ZA[848]) + ZA[861]) + ZR26(ZA[858]); - ZA[859] = ZMa(ZA[850], ZA[845], ZA[855]) + ZR30(ZA[855]); - ZA[691] = ZA[659] + ZA[690]; - ZA[689] = ZA[688] + K[40]; - - ZA[694] = ZR25(ZA[631]) + ZA[627]; - ZA[692] = ZR15(ZA[684]) + ZA[691]; - ZA[866] = ZA[848] + ZA[689]; - ZA[863] = ZA[845] + ZA[862]; - ZA[860] = ZA[857] + ZA[859]; - - ZA[867] = (ZCh(ZA[863], ZA[858], ZA[853]) + ZA[866]) + ZR26(ZA[863]); - ZA[864] = ZMa(ZA[855], ZA[850], ZA[860]) + ZR30(ZA[860]); - ZA[695] = ZA[663] + ZA[694]; - ZA[693] = ZA[692] + K[41]; - - ZA[698] = ZR25(ZA[636]) + ZA[631]; - ZA[696] = ZR15(ZA[688]) + ZA[695]; - ZA[871] = ZA[853] + ZA[693]; - ZA[868] = ZA[850] + ZA[867]; - ZA[865] = ZA[862] + ZA[864]; - - ZA[873] = (ZCh(ZA[868], ZA[863], ZA[858]) + ZA[871]) + ZR26(ZA[868]); - ZA[869] = ZMa(ZA[860], ZA[855], ZA[865]) + ZR30(ZA[865]); - ZA[699] = ZA[667] + ZA[698]; - ZA[697] = ZA[696] + K[42]; - - ZA[702] = ZR25(ZA[640]) + ZA[636]; - ZA[700] = ZR15(ZA[692]) + ZA[699]; - ZA[877] = ZA[858] + ZA[697]; - ZA[874] = ZA[855] + ZA[873]; - ZA[870] = ZA[867] + ZA[869]; - - ZA[878] = (ZCh(ZA[874], ZA[868], ZA[863]) + ZA[877]) + ZR26(ZA[874]); - ZA[875] = ZMa(ZA[865], ZA[860], ZA[870]) + ZR30(ZA[870]); - ZA[703] = ZA[671] + ZA[702]; - ZA[701] = ZA[700] + K[43]; - - ZA[706] = ZR25(ZA[644]) + ZA[640]; - ZA[704] = ZR15(ZA[696]) + ZA[703]; - ZA[882] = ZA[863] + ZA[701]; - ZA[879] = ZA[860] + ZA[878]; - ZA[876] = ZA[873] + ZA[875]; - - ZA[883] = (ZCh(ZA[879], ZA[874], ZA[868]) + ZA[882]) + ZR26(ZA[879]); - ZA[880] = ZMa(ZA[870], ZA[865], ZA[876]) + ZR30(ZA[876]); - ZA[707] = ZA[679] + ZA[706]; - ZA[705] = ZA[704] + K[44]; - - ZA[710] = ZR25(ZA[648]) + ZA[644]; - ZA[708] = ZR15(ZA[700]) + ZA[707]; - ZA[887] = ZA[868] + ZA[705]; - ZA[884] = ZA[865] + ZA[883]; - ZA[881] = ZA[878] + ZA[880]; - - ZA[888] = (ZCh(ZA[884], ZA[879], ZA[874]) + ZA[887]) + ZR26(ZA[884]); - ZA[885] = ZMa(ZA[876], ZA[870], ZA[881]) + ZR30(ZA[881]); - ZA[711] = ZA[684] + ZA[710]; - ZA[709] = ZA[708] + K[45]; - - ZA[714] = ZR25(ZA[651]) + ZA[648]; - ZA[712] = ZR15(ZA[704]) + ZA[711]; - ZA[892] = ZA[874] + ZA[709]; - ZA[889] = ZA[870] + ZA[888]; - ZA[886] = ZA[883] + ZA[885]; - - ZA[893] = (ZCh(ZA[889], ZA[884], ZA[879]) + ZA[892]) + ZR26(ZA[889]); - ZA[890] = ZMa(ZA[881], ZA[876], ZA[886]) + ZR30(ZA[886]); - ZA[715] = ZA[688] + ZA[714]; - ZA[713] = ZA[712] + K[46]; - - ZA[718] = ZR25(ZA[655]) + ZA[651]; - ZA[716] = ZR15(ZA[708]) + ZA[715]; - ZA[897] = ZA[879] + ZA[713]; - ZA[894] = ZA[876] + ZA[893]; - ZA[891] = ZA[888] + ZA[890]; - - ZA[898] = (ZCh(ZA[894], ZA[889], ZA[884]) + ZA[897]) + ZR26(ZA[894]); - ZA[895] = ZMa(ZA[886], ZA[881], ZA[891]) + ZR30(ZA[891]); - ZA[719] = ZA[692] + ZA[718]; - ZA[717] = ZA[716] + K[47]; - - ZA[722] = ZR25(ZA[659]) + ZA[655]; - ZA[720] = ZR15(ZA[712]) + ZA[719]; - ZA[902] = ZA[884] + ZA[717]; - ZA[899] = ZA[881] + ZA[898]; - ZA[896] = ZA[893] + ZA[895]; - - ZA[903] = (ZCh(ZA[899], ZA[894], ZA[889]) + ZA[902]) + ZR26(ZA[899]); - ZA[900] = ZMa(ZA[891], ZA[886], ZA[896]) + ZR30(ZA[896]); - ZA[723] = ZA[696] + ZA[722]; - ZA[721] = ZA[720] + K[48]; - - ZA[672] = ZR25(ZA[663]) + ZA[659]; - ZA[724] = ZR15(ZA[716]) + ZA[723]; - ZA[907] = ZA[889] + ZA[721]; - ZA[904] = ZA[886] + ZA[903]; - ZA[901] = ZA[898] + ZA[900]; - - ZA[908] = (ZCh(ZA[904], ZA[899], ZA[894]) + ZA[907]) + ZR26(ZA[904]); - ZA[905] = ZMa(ZA[896], ZA[891], ZA[901]) + ZR30(ZA[901]); - ZA[673] = ZR25(ZA[667]) + ZA[663]; - ZA[726] = ZA[700] + ZA[672]; - ZA[725] = ZA[724] + K[49]; - - ZA[727] = ZR15(ZA[720]) + ZA[726]; - ZA[912] = ZA[894] + ZA[725]; - ZA[909] = ZA[891] + ZA[908]; - ZA[906] = ZA[903] + ZA[905]; - ZA[675] = ZA[667] + K[52]; - ZA[729] = ZA[704] + ZA[673]; - - ZA[913] = (ZCh(ZA[909], ZA[904], ZA[899]) + ZA[912]) + ZR26(ZA[909]); - ZA[910] = ZMa(ZA[901], ZA[896], ZA[906]) + ZR30(ZA[906]); - ZA[674] = ZR25(ZA[671]) + ZA[675]; - ZA[730] = ZR15(ZA[724]) + ZA[729]; - ZA[728] = ZA[727] + K[50]; - - ZA[681] = ZR25(ZA[679]) + ZA[671]; - ZA[917] = ZA[899] + ZA[901] + ZA[728]; - ZA[914] = ZA[896] + ZA[913]; - ZA[911] = ZA[908] + ZA[910]; - ZA[732] = ZA[708] + ZA[674]; - ZA[731] = ZA[730] + K[51]; - - ZA[918] = (ZCh(ZA[914], ZA[909], ZA[904]) + ZA[917]) + ZR26(ZA[914]); - ZA[915] = ZMa(ZA[906], ZA[901], ZA[911]) + ZR30(ZA[911]); - ZA[733] = ZR15(ZA[727]) + ZA[732]; - ZA[919] = ZA[906] + ZA[904] + ZA[731]; - ZA[734] = ZA[712] + ZA[681]; - - ZA[920] = (ZCh(ZA[918], ZA[914], ZA[909]) + ZA[919]) + ZR26(ZA[918]); - ZA[735] = ZR15(ZA[730]) + ZA[734]; - ZA[921] = ZA[911] + ZA[909] + ZA[733]; - ZA[916] = ZA[913] + ZA[915]; - - ZA[922] = (ZCh(ZA[920], ZA[918], ZA[914]) + ZA[921]) + ZR26(ZA[920]); - ZA[923] = ZA[916] + ZA[914] + ZA[735]; - - ZA[924] = (ZCh(ZA[922], ZA[920], ZA[918]) + ZA[923]) + ZR26(ZA[922]); - -#define FOUND (0x0F) -#define SETFOUND(Xnonce) output[output[FOUND]++] = Xnonce - -#if defined(VECTORS4) - bool result = any(ZA[924] == K[79]); - - if (result) { - if (ZA[924].x == K[79]) - SETFOUND(Znonce.x); - if (ZA[924].y == K[79]) - SETFOUND(Znonce.y); - if (ZA[924].z == K[79]) - SETFOUND(Znonce.z); - if (ZA[924].w == K[79]) - SETFOUND(Znonce.w); - } -#elif defined(VECTORS2) - bool result = any(ZA[924] == K[79]); - - if (result) { - if (ZA[924].x == K[79]) - SETFOUND(Znonce.x); - if (ZA[924].y == K[79]) - SETFOUND(Znonce.y); - } -#else - if (ZA[924] == K[79]) - SETFOUND(Znonce); -#endif -} diff --git a/diakgcn121016.cl b/diakgcn121016.cl deleted file mode 100644 index b87fbde9..00000000 --- a/diakgcn121016.cl +++ /dev/null @@ -1,599 +0,0 @@ -// DiaKGCN 27-04-2012 - OpenCL kernel by Diapolo -// -// Parts and / or ideas for this kernel are based upon the public-domain poclbm project, the phatk kernel by Phateus and the DiabloMiner kernel by DiabloD3. -// The kernel was rewritten by me (Diapolo) and is still public-domain! - -#ifdef VECTORS4 - typedef uint4 u; -#elif defined VECTORS2 - typedef uint2 u; -#else - typedef uint u; -#endif - -#ifdef BITALIGN - #pragma OPENCL EXTENSION cl_amd_media_ops : enable - #ifdef BFI_INT - #define ch(x, y, z) amd_bytealign(x, y, z) - #define ma(x, y, z) amd_bytealign(z ^ x, y, x) - #else - #define ch(x, y, z) bitselect(z, y, x) - #define ma(z, x, y) bitselect(z, y, z ^ x) - #endif -#else - #define ch(x, y, z) (z ^ (x & (y ^ z))) - #define ma(x, y, z) ((x & z) | (y & (x | z))) -#endif - -#define rotr15(n) (rotate(n, 15U) ^ rotate(n, 13U) ^ (n >> 10U)) -#define rotr25(n) (rotate(n, 25U) ^ rotate(n, 14U) ^ (n >> 3U)) -#define rotr26(n) (rotate(n, 26U) ^ rotate(n, 21U) ^ rotate(n, 7U)) -#define rotr30(n) (rotate(n, 30U) ^ rotate(n, 19U) ^ rotate(n, 10U)) - -__kernel - __attribute__((reqd_work_group_size(WORKSIZE, 1, 1))) - void search( -#ifndef GOFFSET - const u base, -#endif - const uint PreVal0, const uint PreVal4, - const uint H1, const uint D1A, const uint B1, const uint C1, - const uint F1, const uint G1, const uint C1addK5, const uint B1addK6, const uint PreVal0addK7, - const uint W16addK16, const uint W17addK17, - const uint PreW18, const uint PreW19, - const uint W16, const uint W17, - const uint PreW31, const uint PreW32, - const uint state0, const uint state1, const uint state2, const uint state3, - const uint state4, const uint state5, const uint state6, const uint state7, - const uint state0A, const uint state0B, - const uint state1A, const uint state2A, const uint state3A, const uint state4A, - const uint state5A, const uint state6A, const uint state7A, - volatile __global uint * output) -{ - u V[8]; - u W[16]; - -#ifdef VECTORS4 - const u nonce = (uint)(get_local_id(0)) * 4U + (uint)(get_group_id(0)) * (uint)(WORKVEC) + base; -#elif defined VECTORS2 - const u nonce = (uint)(get_local_id(0)) * 2U + (uint)(get_group_id(0)) * (uint)(WORKVEC) + base; -#else - #ifdef GOFFSET - const u nonce = (uint)(get_global_id(0)); - #else - const u nonce = (uint)(get_local_id(0)) + (uint)(get_group_id(0)) * (uint)(WORKSIZE) + base; - #endif -#endif - - V[0] = PreVal0 + nonce; - V[1] = B1; - V[2] = C1; - V[3] = D1A; - V[4] = PreVal4 + nonce; - V[5] = F1; - V[6] = G1; - V[7] = H1; - - V[7] += V[3] + ch(V[0], V[1], V[2]) + rotr26(V[0]); - V[3] = V[3] + ch(V[0], V[1], V[2]) + rotr26(V[0]) + rotr30(V[4]) + ma(V[5], V[6], V[4]); - - V[6] += C1addK5 + ch(V[7], V[0], V[1]) + rotr26(V[7]); - V[2] = C1addK5 + ch(V[7], V[0], V[1]) + rotr26(V[7]) + rotr30(V[3]) + ma(V[4], V[5], V[3]); - - V[5] += B1addK6 + ch(V[6], V[7], V[0]) + rotr26(V[6]); - V[1] = B1addK6 + ch(V[6], V[7], V[0]) + rotr26(V[6]) + rotr30(V[2]) + ma(V[3], V[4], V[2]); - - V[4] += PreVal0addK7 + nonce + ch(V[5], V[6], V[7]) + rotr26(V[5]); - V[0] = PreVal0addK7 + nonce + ch(V[5], V[6], V[7]) + rotr26(V[5]) + rotr30(V[1]) + ma(V[2], V[3], V[1]); - - V[3] += 0xd807aa98U + V[7] + ch(V[4], V[5], V[6]) + rotr26(V[4]); - V[7] = 0xd807aa98U + V[7] + ch(V[4], V[5], V[6]) + rotr26(V[4]) + rotr30(V[0]) + ma(V[1], V[2], V[0]); - - V[2] += 0x12835b01U + V[6] + ch(V[3], V[4], V[5]) + rotr26(V[3]); - V[6] = 0x12835b01U + V[6] + ch(V[3], V[4], V[5]) + rotr26(V[3]) + rotr30(V[7]) + ma(V[0], V[1], V[7]); - - V[1] += 0x243185beU + V[5] + ch(V[2], V[3], V[4]) + rotr26(V[2]); - V[5] = 0x243185beU + V[5] + ch(V[2], V[3], V[4]) + rotr26(V[2]) + rotr30(V[6]) + ma(V[7], V[0], V[6]); - - V[0] += 0x550c7dc3U + V[4] + ch(V[1], V[2], V[3]) + rotr26(V[1]); - V[4] = 0x550c7dc3U + V[4] + ch(V[1], V[2], V[3]) + rotr26(V[1]) + rotr30(V[5]) + ma(V[6], V[7], V[5]); - - V[7] += 0x72be5d74U + V[3] + ch(V[0], V[1], V[2]) + rotr26(V[0]); - V[3] = 0x72be5d74U + V[3] + ch(V[0], V[1], V[2]) + rotr26(V[0]) + rotr30(V[4]) + ma(V[5], V[6], V[4]); - - V[6] += 0x80deb1feU + V[2] + ch(V[7], V[0], V[1]) + rotr26(V[7]); - V[2] = 0x80deb1feU + V[2] + ch(V[7], V[0], V[1]) + rotr26(V[7]) + rotr30(V[3]) + ma(V[4], V[5], V[3]); - - V[5] += 0x9bdc06a7U + V[1] + ch(V[6], V[7], V[0]) + rotr26(V[6]); - V[1] = 0x9bdc06a7U + V[1] + ch(V[6], V[7], V[0]) + rotr26(V[6]) + rotr30(V[2]) + ma(V[3], V[4], V[2]); - - V[4] += 0xc19bf3f4U + V[0] + ch(V[5], V[6], V[7]) + rotr26(V[5]); - V[0] = 0xc19bf3f4U + V[0] + ch(V[5], V[6], V[7]) + rotr26(V[5]) + rotr30(V[1]) + ma(V[2], V[3], V[1]); - - V[3] += W16addK16 + V[7] + ch(V[4], V[5], V[6]) + rotr26(V[4]); - V[7] = W16addK16 + V[7] + ch(V[4], V[5], V[6]) + rotr26(V[4]) + rotr30(V[0]) + ma(V[1], V[2], V[0]); - - V[2] += W17addK17 + V[6] + ch(V[3], V[4], V[5]) + rotr26(V[3]); - V[6] = W17addK17 + V[6] + ch(V[3], V[4], V[5]) + rotr26(V[3]) + rotr30(V[7]) + ma(V[0], V[1], V[7]); - -//---------------------------------------------------------------------------------- - -#ifdef VECTORS4 - W[0] = PreW18 + (u)(rotr25(nonce.x), rotr25(nonce.x) ^ 0x2004000U, rotr25(nonce.x) ^ 0x4008000U, rotr25(nonce.x) ^ 0x600c000U); -#elif defined VECTORS2 - W[0] = PreW18 + (u)(rotr25(nonce.x), rotr25(nonce.x) ^ 0x2004000U); -#else - W[0] = PreW18 + rotr25(nonce); -#endif - W[1] = PreW19 + nonce; - W[2] = 0x80000000U + rotr15(W[0]); - W[3] = rotr15(W[1]); - W[4] = 0x00000280U + rotr15(W[2]); - W[5] = W16 + rotr15(W[3]); - W[6] = W17 + rotr15(W[4]); - W[7] = W[0] + rotr15(W[5]); - W[8] = W[1] + rotr15(W[6]); - W[9] = W[2] + rotr15(W[7]); - W[10] = W[3] + rotr15(W[8]); - W[11] = W[4] + rotr15(W[9]); - W[12] = W[5] + 0x00a00055U + rotr15(W[10]); - W[13] = W[6] + PreW31 + rotr15(W[11]); - W[14] = W[7] + PreW32 + rotr15(W[12]); - W[15] = W[8] + W17 + rotr15(W[13]) + rotr25(W[0]); - - V[1] += 0x0fc19dc6U + V[5] + ch(V[2], V[3], V[4]) + rotr26(V[2]) + W[0]; - V[5] = 0x0fc19dc6U + V[5] + ch(V[2], V[3], V[4]) + rotr26(V[2]) + W[0] + rotr30(V[6]) + ma(V[7], V[0], V[6]); - - V[0] += 0x240ca1ccU + V[4] + W[1] + ch(V[1], V[2], V[3]) + rotr26(V[1]); - V[4] = 0x240ca1ccU + V[4] + W[1] + ch(V[1], V[2], V[3]) + rotr26(V[1]) + rotr30(V[5]) + ma(V[6], V[7], V[5]); - - V[7] += 0x2de92c6fU + V[3] + W[2] + ch(V[0], V[1], V[2]) + rotr26(V[0]); - V[3] = 0x2de92c6fU + V[3] + W[2] + ch(V[0], V[1], V[2]) + rotr26(V[0]) + rotr30(V[4]) + ma(V[5], V[6], V[4]); - - V[6] += 0x4a7484aaU + V[2] + W[3] + ch(V[7], V[0], V[1]) + rotr26(V[7]); - V[2] = 0x4a7484aaU + V[2] + W[3] + ch(V[7], V[0], V[1]) + rotr26(V[7]) + rotr30(V[3]) + ma(V[4], V[5], V[3]); - - V[5] += 0x5cb0a9dcU + V[1] + W[4] + ch(V[6], V[7], V[0]) + rotr26(V[6]); - V[1] = 0x5cb0a9dcU + V[1] + W[4] + ch(V[6], V[7], V[0]) + rotr26(V[6]) + rotr30(V[2]) + ma(V[3], V[4], V[2]); - - V[4] += 0x76f988daU + V[0] + W[5] + ch(V[5], V[6], V[7]) + rotr26(V[5]); - V[0] = 0x76f988daU + V[0] + W[5] + ch(V[5], V[6], V[7]) + rotr26(V[5]) + rotr30(V[1]) + ma(V[2], V[3], V[1]); - - V[3] += 0x983e5152U + V[7] + W[6] + ch(V[4], V[5], V[6]) + rotr26(V[4]); - V[7] = 0x983e5152U + V[7] + W[6] + ch(V[4], V[5], V[6]) + rotr26(V[4]) + rotr30(V[0]) + ma(V[1], V[2], V[0]); - - V[2] += 0xa831c66dU + V[6] + W[7] + ch(V[3], V[4], V[5]) + rotr26(V[3]); - V[6] = 0xa831c66dU + V[6] + W[7] + ch(V[3], V[4], V[5]) + rotr26(V[3]) + rotr30(V[7]) + ma(V[0], V[1], V[7]); - - V[1] += 0xb00327c8U + V[5] + W[8] + ch(V[2], V[3], V[4]) + rotr26(V[2]); - V[5] = 0xb00327c8U + V[5] + W[8] + ch(V[2], V[3], V[4]) + rotr26(V[2]) + rotr30(V[6]) + ma(V[7], V[0], V[6]); - - V[0] += 0xbf597fc7U + V[4] + W[9] + ch(V[1], V[2], V[3]) + rotr26(V[1]); - V[4] = 0xbf597fc7U + V[4] + W[9] + ch(V[1], V[2], V[3]) + rotr26(V[1]) + rotr30(V[5]) + ma(V[6], V[7], V[5]); - - V[7] += 0xc6e00bf3U + V[3] + W[10] + ch(V[0], V[1], V[2]) + rotr26(V[0]); - V[3] = 0xc6e00bf3U + V[3] + W[10] + ch(V[0], V[1], V[2]) + rotr26(V[0]) + rotr30(V[4]) + ma(V[5], V[6], V[4]); - - V[6] += 0xd5a79147U + V[2] + W[11] + ch(V[7], V[0], V[1]) + rotr26(V[7]); - V[2] = 0xd5a79147U + V[2] + W[11] + ch(V[7], V[0], V[1]) + rotr26(V[7]) + rotr30(V[3]) + ma(V[4], V[5], V[3]); - - V[5] += 0x06ca6351U + V[1] + W[12] + ch(V[6], V[7], V[0]) + rotr26(V[6]); - V[1] = 0x06ca6351U + V[1] + W[12] + ch(V[6], V[7], V[0]) + rotr26(V[6]) + rotr30(V[2]) + ma(V[3], V[4], V[2]); - - V[4] += 0x14292967U + V[0] + W[13] + ch(V[5], V[6], V[7]) + rotr26(V[5]); - V[0] = 0x14292967U + V[0] + W[13] + ch(V[5], V[6], V[7]) + rotr26(V[5]) + rotr30(V[1]) + ma(V[2], V[3], V[1]); - - V[3] += 0x27b70a85U + V[7] + W[14] + ch(V[4], V[5], V[6]) + rotr26(V[4]); - V[7] = 0x27b70a85U + V[7] + W[14] + ch(V[4], V[5], V[6]) + rotr26(V[4]) + rotr30(V[0]) + ma(V[1], V[2], V[0]); - - V[2] += 0x2e1b2138U + V[6] + W[15] + ch(V[3], V[4], V[5]) + rotr26(V[3]); - V[6] = 0x2e1b2138U + V[6] + W[15] + ch(V[3], V[4], V[5]) + rotr26(V[3]) + rotr30(V[7]) + ma(V[0], V[1], V[7]); - -//---------------------------------------------------------------------------------- - - W[0] = W[0] + W[9] + rotr15(W[14]) + rotr25( W[1]); - W[1] = W[1] + W[10] + rotr15(W[15]) + rotr25( W[2]); - W[2] = W[2] + W[11] + rotr15( W[0]) + rotr25( W[3]); - W[3] = W[3] + W[12] + rotr15( W[1]) + rotr25( W[4]); - W[4] = W[4] + W[13] + rotr15( W[2]) + rotr25( W[5]); - W[5] = W[5] + W[14] + rotr15( W[3]) + rotr25( W[6]); - W[6] = W[6] + W[15] + rotr15( W[4]) + rotr25( W[7]); - W[7] = W[7] + W[0] + rotr15( W[5]) + rotr25( W[8]); - W[8] = W[8] + W[1] + rotr15( W[6]) + rotr25( W[9]); - W[9] = W[9] + W[2] + rotr15( W[7]) + rotr25(W[10]); - W[10] = W[10] + W[3] + rotr15( W[8]) + rotr25(W[11]); - W[11] = W[11] + W[4] + rotr15( W[9]) + rotr25(W[12]); - W[12] = W[12] + W[5] + rotr15(W[10]) + rotr25(W[13]); - W[13] = W[13] + W[6] + rotr15(W[11]) + rotr25(W[14]); - W[14] = W[14] + W[7] + rotr15(W[12]) + rotr25(W[15]); - W[15] = W[15] + W[8] + rotr15(W[13]) + rotr25( W[0]); - - V[1] += 0x4d2c6dfcU + V[5] + W[0] + ch(V[2], V[3], V[4]) + rotr26(V[2]); - V[5] = 0x4d2c6dfcU + V[5] + W[0] + ch(V[2], V[3], V[4]) + rotr26(V[2]) + rotr30(V[6]) + ma(V[7], V[0], V[6]); - - V[0] += 0x53380d13U + V[4] + W[1] + ch(V[1], V[2], V[3]) + rotr26(V[1]); - V[4] = 0x53380d13U + V[4] + W[1] + ch(V[1], V[2], V[3]) + rotr26(V[1]) + rotr30(V[5]) + ma(V[6], V[7], V[5]); - - V[7] += 0x650a7354U + V[3] + W[2] + ch(V[0], V[1], V[2]) + rotr26(V[0]); - V[3] = 0x650a7354U + V[3] + W[2] + ch(V[0], V[1], V[2]) + rotr26(V[0]) + rotr30(V[4]) + ma(V[5], V[6], V[4]); - - V[6] += 0x766a0abbU + V[2] + W[3] + ch(V[7], V[0], V[1]) + rotr26(V[7]); - V[2] = 0x766a0abbU + V[2] + W[3] + ch(V[7], V[0], V[1]) + rotr26(V[7]) + rotr30(V[3]) + ma(V[4], V[5], V[3]); - - V[5] += 0x81c2c92eU + V[1] + W[4] + ch(V[6], V[7], V[0]) + rotr26(V[6]); - V[1] = 0x81c2c92eU + V[1] + W[4] + ch(V[6], V[7], V[0]) + rotr26(V[6]) + rotr30(V[2]) + ma(V[3], V[4], V[2]); - - V[4] += 0x92722c85U + V[0] + W[5] + ch(V[5], V[6], V[7]) + rotr26(V[5]); - V[0] = 0x92722c85U + V[0] + W[5] + ch(V[5], V[6], V[7]) + rotr26(V[5]) + rotr30(V[1]) + ma(V[2], V[3], V[1]); - - V[3] += 0xa2bfe8a1U + V[7] + W[6] + ch(V[4], V[5], V[6]) + rotr26(V[4]); - V[7] = 0xa2bfe8a1U + V[7] + W[6] + ch(V[4], V[5], V[6]) + rotr26(V[4]) + rotr30(V[0]) + ma(V[1], V[2], V[0]); - - V[2] += 0xa81a664bU + V[6] + W[7] + ch(V[3], V[4], V[5]) + rotr26(V[3]); - V[6] = 0xa81a664bU + V[6] + W[7] + ch(V[3], V[4], V[5]) + rotr26(V[3]) + rotr30(V[7]) + ma(V[0], V[1], V[7]); - - V[1] += 0xc24b8b70U + V[5] + W[8] + ch(V[2], V[3], V[4]) + rotr26(V[2]); - V[5] = 0xc24b8b70U + V[5] + W[8] + ch(V[2], V[3], V[4]) + rotr26(V[2]) + rotr30(V[6]) + ma(V[7], V[0], V[6]); - - V[0] += 0xc76c51a3U + V[4] + W[9] + ch(V[1], V[2], V[3]) + rotr26(V[1]); - V[4] = 0xc76c51a3U + V[4] + W[9] + ch(V[1], V[2], V[3]) + rotr26(V[1]) + rotr30(V[5]) + ma(V[6], V[7], V[5]); - - V[7] += 0xd192e819U + V[3] + W[10] + ch(V[0], V[1], V[2]) + rotr26(V[0]); - V[3] = 0xd192e819U + V[3] + W[10] + ch(V[0], V[1], V[2]) + rotr26(V[0]) + rotr30(V[4]) + ma(V[5], V[6], V[4]); - - V[6] += 0xd6990624U + V[2] + W[11] + ch(V[7], V[0], V[1]) + rotr26(V[7]); - V[2] = 0xd6990624U + V[2] + W[11] + ch(V[7], V[0], V[1]) + rotr26(V[7]) + rotr30(V[3]) + ma(V[4], V[5], V[3]); - - V[5] += 0xf40e3585U + V[1] + W[12] + ch(V[6], V[7], V[0]) + rotr26(V[6]); - V[1] = 0xf40e3585U + V[1] + W[12] + ch(V[6], V[7], V[0]) + rotr26(V[6]) + rotr30(V[2]) + ma(V[3], V[4], V[2]); - - V[4] += 0x106aa070U + V[0] + W[13] + ch(V[5], V[6], V[7]) + rotr26(V[5]); - V[0] = 0x106aa070U + V[0] + W[13] + ch(V[5], V[6], V[7]) + rotr26(V[5]) + rotr30(V[1]) + ma(V[2], V[3], V[1]); - - V[3] += 0x19a4c116U + V[7] + W[14] + ch(V[4], V[5], V[6]) + rotr26(V[4]); - V[7] = 0x19a4c116U + V[7] + W[14] + ch(V[4], V[5], V[6]) + rotr26(V[4]) + rotr30(V[0]) + ma(V[1], V[2], V[0]); - - V[2] += 0x1e376c08U + V[6] + W[15] + ch(V[3], V[4], V[5]) + rotr26(V[3]); - V[6] = 0x1e376c08U + V[6] + W[15] + ch(V[3], V[4], V[5]) + rotr26(V[3]) + rotr30(V[7]) + ma(V[0], V[1], V[7]); - -//---------------------------------------------------------------------------------- - - W[0] = W[0] + W[9] + rotr15(W[14]) + rotr25( W[1]); - W[1] = W[1] + W[10] + rotr15(W[15]) + rotr25( W[2]); - W[2] = W[2] + W[11] + rotr15( W[0]) + rotr25( W[3]); - W[3] = W[3] + W[12] + rotr15( W[1]) + rotr25( W[4]); - W[4] = W[4] + W[13] + rotr15( W[2]) + rotr25( W[5]); - W[5] = W[5] + W[14] + rotr15( W[3]) + rotr25( W[6]); - W[6] = W[6] + W[15] + rotr15( W[4]) + rotr25( W[7]); - W[7] = W[7] + W[0] + rotr15( W[5]) + rotr25( W[8]); - W[8] = W[8] + W[1] + rotr15( W[6]) + rotr25( W[9]); - W[9] = W[9] + W[2] + rotr15( W[7]) + rotr25(W[10]); - W[10] = W[10] + W[3] + rotr15( W[8]) + rotr25(W[11]); - W[11] = W[11] + W[4] + rotr15( W[9]) + rotr25(W[12]); - W[12] = W[12] + W[5] + rotr15(W[10]) + rotr25(W[13]); - W[13] = W[13] + W[6] + rotr15(W[11]) + rotr25(W[14]); - - V[1] += 0x2748774cU + V[5] + W[0] + ch(V[2], V[3], V[4]) + rotr26(V[2]); - V[5] = 0x2748774cU + V[5] + W[0] + ch(V[2], V[3], V[4]) + rotr26(V[2]) + rotr30(V[6]) + ma(V[7], V[0], V[6]); - - V[0] += 0x34b0bcb5U + V[4] + W[1] + ch(V[1], V[2], V[3]) + rotr26(V[1]); - V[4] = 0x34b0bcb5U + V[4] + W[1] + ch(V[1], V[2], V[3]) + rotr26(V[1]) + rotr30(V[5]) + ma(V[6], V[7], V[5]); - - V[7] += 0x391c0cb3U + V[3] + W[2] + ch(V[0], V[1], V[2]) + rotr26(V[0]); - V[3] = 0x391c0cb3U + V[3] + W[2] + ch(V[0], V[1], V[2]) + rotr26(V[0]) + rotr30(V[4]) + ma(V[5], V[6], V[4]); - - V[6] += 0x4ed8aa4aU + V[2] + W[3] + ch(V[7], V[0], V[1]) + rotr26(V[7]); - V[2] = 0x4ed8aa4aU + V[2] + W[3] + ch(V[7], V[0], V[1]) + rotr26(V[7]) + rotr30(V[3]) + ma(V[4], V[5], V[3]); - - V[5] += 0x5b9cca4fU + V[1] + W[4] + ch(V[6], V[7], V[0]) + rotr26(V[6]); - V[1] = 0x5b9cca4fU + V[1] + W[4] + ch(V[6], V[7], V[0]) + rotr26(V[6]) + rotr30(V[2]) + ma(V[3], V[4], V[2]); - - V[4] += 0x682e6ff3U + V[0] + W[5] + ch(V[5], V[6], V[7]) + rotr26(V[5]); - V[0] = 0x682e6ff3U + V[0] + W[5] + ch(V[5], V[6], V[7]) + rotr26(V[5]) + rotr30(V[1]) + ma(V[2], V[3], V[1]); - - V[3] += 0x748f82eeU + V[7] + W[6] + ch(V[4], V[5], V[6]) + rotr26(V[4]); - V[7] = 0x748f82eeU + V[7] + W[6] + ch(V[4], V[5], V[6]) + rotr26(V[4]) + rotr30(V[0]) + ma(V[1], V[2], V[0]); - - V[2] += 0x78a5636fU + V[6] + W[7] + ch(V[3], V[4], V[5]) + rotr26(V[3]); - V[6] = 0x78a5636fU + V[6] + W[7] + ch(V[3], V[4], V[5]) + rotr26(V[3]) + rotr30(V[7]) + ma(V[0], V[1], V[7]); - - V[1] += 0x84c87814U + V[5] + W[8] + ch(V[2], V[3], V[4]) + rotr26(V[2]); - V[5] = 0x84c87814U + V[5] + W[8] + ch(V[2], V[3], V[4]) + rotr26(V[2]) + rotr30(V[6]) + ma(V[7], V[0], V[6]); - - V[0] += 0x8cc70208U + V[4] + W[9] + ch(V[1], V[2], V[3]) + rotr26(V[1]); - V[4] = 0x8cc70208U + V[4] + W[9] + ch(V[1], V[2], V[3]) + rotr26(V[1]) + rotr30(V[5]) + ma(V[6], V[7], V[5]); - - V[7] += 0x90befffaU + V[3] + W[10] + ch(V[0], V[1], V[2]) + rotr26(V[0]); - V[3] = 0x90befffaU + V[3] + W[10] + ch(V[0], V[1], V[2]) + rotr26(V[0]) + rotr30(V[4]) + ma(V[5], V[6], V[4]); - - V[6] += 0xa4506cebU + V[2] + W[11] + ch(V[7], V[0], V[1]) + rotr26(V[7]); - V[2] = 0xa4506cebU + V[2] + W[11] + ch(V[7], V[0], V[1]) + rotr26(V[7]) + rotr30(V[3]) + ma(V[4], V[5], V[3]); - - V[5] += 0xbef9a3f7U + V[1] + W[12] + ch(V[6], V[7], V[0]) + rotr26(V[6]); - V[1] = 0xbef9a3f7U + V[1] + W[12] + ch(V[6], V[7], V[0]) + rotr26(V[6]) + rotr30(V[2]) + ma(V[3], V[4], V[2]); - - V[4] += 0xc67178f2U + V[0] + W[13] + ch(V[5], V[6], V[7]) + rotr26(V[5]); - V[0] = 0xc67178f2U + V[0] + W[13] + ch(V[5], V[6], V[7]) + rotr26(V[5]) + rotr30(V[1]) + ma(V[2], V[3], V[1]); - -//---------------------------------------------------------------------------------- - - W[0] = state0 + V[0] + rotr25(state1 + V[1]); - W[1] = state1 + V[1] + 0x00a00000U + rotr25(state2 + V[2]); - W[2] = state2 + V[2] + rotr15(W[0]) + rotr25(state3 + V[3]); - W[3] = state3 + V[3] + rotr15(W[1]) + rotr25(state4 + V[4]); - W[4] = state4 + V[4] + rotr15(W[2]) + rotr25(state5 + V[5]); - W[5] = state5 + V[5] + rotr15(W[3]) + rotr25(state6 + V[6]); - W[6] = state6 + V[6] + 0x00000100U + rotr15(W[4]) + rotr25(state7 + V[7]); - W[7] = state7 + V[7] + W[0] + 0x11002000U + rotr15(W[5]); - W[8] = W[1] + 0x80000000U + rotr15(W[6]); - W[9] = W[2] + rotr15(W[7]); - W[10] = W[3] + rotr15(W[8]); - W[11] = W[4] + rotr15(W[9]); - W[12] = W[5] + rotr15(W[10]); - W[13] = W[6] + rotr15(W[11]); - W[14] = W[7] + 0x00400022U + rotr15(W[12]); - W[15] = W[8] + 0x00000100U + rotr15(W[13]) + rotr25(W[0]); - - // 0x71374491U + 0x1f83d9abU + state1 - const u state1AaddV1 = state1A + V[1]; - // 0xb5c0fbcfU + 0x9b05688cU + state2 - const u state2AaddV2 = state2A + V[2]; - // 0x510e527fU + 0xe9b5dba5U + state3 - const u state3AaddV3 = state3A + V[3]; - // 0x3956c25bU + state4 - const u state4AaddV4 = state4A + V[4]; - // 0x59f111f1U + state5 - const u state5AaddV5 = state5A + V[5]; - // 0x923f82a4U + state6 - const u state6AaddV6 = state6A + V[6]; - // 0xab1c5ed5U + state7 - const u state7AaddV7 = state7A + V[7]; - - // 0x98c7e2a2U + state0 - V[3] = state0A + V[0]; - // 0xfc08884dU + state0 - V[7] = state0B + V[0]; - V[0] = 0x6a09e667U; - V[1] = 0xbb67ae85U; - V[2] = 0x3c6ef372U; - V[4] = 0x510e527fU; - V[5] = 0x9b05688cU; - V[6] = 0x1f83d9abU; - - V[2] += state1AaddV1 + ch(V[3], V[4], V[5]) + rotr26(V[3]); - V[6] = state1AaddV1 + ch(V[3], V[4], V[5]) + rotr26(V[3]) + rotr30(V[7]) + ma(V[0], V[1], V[7]); - - V[1] += state2AaddV2 + ch(V[2], V[3], V[4]) + rotr26(V[2]); - V[5] = state2AaddV2 + ch(V[2], V[3], V[4]) + rotr26(V[2]) + rotr30(V[6]) + ma(V[7], V[0], V[6]); - - V[0] += state3AaddV3 + ch(V[1], V[2], V[3]) + rotr26(V[1]); - V[4] = state3AaddV3 + ch(V[1], V[2], V[3]) + rotr26(V[1]) + rotr30(V[5]) + ma(V[6], V[7], V[5]); - - V[7] += state4AaddV4 + V[3] + ch(V[0], V[1], V[2]) + rotr26(V[0]); - V[3] = state4AaddV4 + V[3] + ch(V[0], V[1], V[2]) + rotr26(V[0]) + rotr30(V[4]) + ma(V[5], V[6], V[4]); - - V[6] += state5AaddV5 + V[2] + ch(V[7], V[0], V[1]) + rotr26(V[7]); - V[2] = state5AaddV5 + V[2] + ch(V[7], V[0], V[1]) + rotr26(V[7]) + rotr30(V[3]) + ma(V[4], V[5], V[3]); - - V[5] += state6AaddV6 + V[1] + ch(V[6], V[7], V[0]) + rotr26(V[6]); - V[1] = state6AaddV6 + V[1] + ch(V[6], V[7], V[0]) + rotr26(V[6]) + rotr30(V[2]) + ma(V[3], V[4], V[2]); - - V[4] += state7AaddV7 + V[0] + ch(V[5], V[6], V[7]) + rotr26(V[5]); - V[0] = state7AaddV7 + V[0] + ch(V[5], V[6], V[7]) + rotr26(V[5]) + rotr30(V[1]) + ma(V[2], V[3], V[1]); - - V[3] += 0x5807aa98U + V[7] + ch(V[4], V[5], V[6]) + rotr26(V[4]); - V[7] = 0x5807aa98U + V[7] + ch(V[4], V[5], V[6]) + rotr26(V[4]) + rotr30(V[0]) + ma(V[1], V[2], V[0]); - - V[2] += 0x12835b01U + V[6] + ch(V[3], V[4], V[5]) + rotr26(V[3]); - V[6] = 0x12835b01U + V[6] + ch(V[3], V[4], V[5]) + rotr26(V[3]) + rotr30(V[7]) + ma(V[0], V[1], V[7]); - - V[1] += 0x243185beU + V[5] + ch(V[2], V[3], V[4]) + rotr26(V[2]); - V[5] = 0x243185beU + V[5] + ch(V[2], V[3], V[4]) + rotr26(V[2]) + rotr30(V[6]) + ma(V[7], V[0], V[6]); - - V[0] += 0x550c7dc3U + V[4] + ch(V[1], V[2], V[3]) + rotr26(V[1]); - V[4] = 0x550c7dc3U + V[4] + ch(V[1], V[2], V[3]) + rotr26(V[1]) + rotr30(V[5]) + ma(V[6], V[7], V[5]); - - V[7] += 0x72be5d74U + V[3] + ch(V[0], V[1], V[2]) + rotr26(V[0]); - V[3] = 0x72be5d74U + V[3] + ch(V[0], V[1], V[2]) + rotr26(V[0]) + rotr30(V[4]) + ma(V[5], V[6], V[4]); - - V[6] += 0x80deb1feU + V[2] + ch(V[7], V[0], V[1]) + rotr26(V[7]); - V[2] = 0x80deb1feU + V[2] + ch(V[7], V[0], V[1]) + rotr26(V[7]) + rotr30(V[3]) + ma(V[4], V[5], V[3]); - - V[5] += 0x9bdc06a7U + V[1] + ch(V[6], V[7], V[0]) + rotr26(V[6]); - V[1] = 0x9bdc06a7U + V[1] + ch(V[6], V[7], V[0]) + rotr26(V[6]) + rotr30(V[2]) + ma(V[3], V[4], V[2]); - - V[4] += 0xc19bf274U + V[0] + ch(V[5], V[6], V[7]) + rotr26(V[5]); - V[0] = 0xc19bf274U + V[0] + ch(V[5], V[6], V[7]) + rotr26(V[5]) + rotr30(V[1]) + ma(V[2], V[3], V[1]); - - V[3] += 0xe49b69c1U + V[7] + W[0] + ch(V[4], V[5], V[6]) + rotr26(V[4]); - V[7] = 0xe49b69c1U + V[7] + W[0] + ch(V[4], V[5], V[6]) + rotr26(V[4]) + rotr30(V[0]) + ma(V[1], V[2], V[0]); - - V[2] += 0xefbe4786U + V[6] + W[1] + ch(V[3], V[4], V[5]) + rotr26(V[3]); - V[6] = 0xefbe4786U + V[6] + W[1] + ch(V[3], V[4], V[5]) + rotr26(V[3]) + rotr30(V[7]) + ma(V[0], V[1], V[7]); - - V[1] += 0x0fc19dc6U + V[5] + W[2] + ch(V[2], V[3], V[4]) + rotr26(V[2]); - V[5] = 0x0fc19dc6U + V[5] + W[2] + ch(V[2], V[3], V[4]) + rotr26(V[2]) + rotr30(V[6]) + ma(V[7], V[0], V[6]); - - V[0] += 0x240ca1ccU + V[4] + W[3] + ch(V[1], V[2], V[3]) + rotr26(V[1]); - V[4] = 0x240ca1ccU + V[4] + W[3] + ch(V[1], V[2], V[3]) + rotr26(V[1]) + rotr30(V[5]) + ma(V[6], V[7], V[5]); - - V[7] += 0x2de92c6fU + V[3] + W[4] + ch(V[0], V[1], V[2]) + rotr26(V[0]); - V[3] = 0x2de92c6fU + V[3] + W[4] + ch(V[0], V[1], V[2]) + rotr26(V[0]) + rotr30(V[4]) + ma(V[5], V[6], V[4]); - - V[6] += 0x4a7484aaU + V[2] + W[5] + ch(V[7], V[0], V[1]) + rotr26(V[7]); - V[2] = 0x4a7484aaU + V[2] + W[5] + ch(V[7], V[0], V[1]) + rotr26(V[7]) + rotr30(V[3]) + ma(V[4], V[5], V[3]); - - V[5] += 0x5cb0a9dcU + V[1] + W[6] + ch(V[6], V[7], V[0]) + rotr26(V[6]); - V[1] = 0x5cb0a9dcU + V[1] + W[6] + ch(V[6], V[7], V[0]) + rotr26(V[6]) + rotr30(V[2]) + ma(V[3], V[4], V[2]); - - V[4] += 0x76f988daU + V[0] + W[7] + ch(V[5], V[6], V[7]) + rotr26(V[5]); - V[0] = 0x76f988daU + V[0] + W[7] + ch(V[5], V[6], V[7]) + rotr26(V[5]) + rotr30(V[1]) + ma(V[2], V[3], V[1]); - - V[3] += 0x983e5152U + V[7] + W[8] + ch(V[4], V[5], V[6]) + rotr26(V[4]); - V[7] = 0x983e5152U + V[7] + W[8] + ch(V[4], V[5], V[6]) + rotr26(V[4]) + rotr30(V[0]) + ma(V[1], V[2], V[0]); - - V[2] += 0xa831c66dU + V[6] + W[9] + ch(V[3], V[4], V[5]) + rotr26(V[3]); - V[6] = 0xa831c66dU + V[6] + W[9] + ch(V[3], V[4], V[5]) + rotr26(V[3]) + rotr30(V[7]) + ma(V[0], V[1], V[7]); - - V[1] += 0xb00327c8U + V[5] + W[10] + ch(V[2], V[3], V[4]) + rotr26(V[2]); - V[5] = 0xb00327c8U + V[5] + W[10] + ch(V[2], V[3], V[4]) + rotr26(V[2]) + rotr30(V[6]) + ma(V[7], V[0], V[6]); - - V[0] += 0xbf597fc7U + V[4] + W[11] + ch(V[1], V[2], V[3]) + rotr26(V[1]); - V[4] = 0xbf597fc7U + V[4] + W[11] + ch(V[1], V[2], V[3]) + rotr26(V[1]) + rotr30(V[5]) + ma(V[6], V[7], V[5]); - - V[7] += 0xc6e00bf3U + V[3] + W[12] + ch(V[0], V[1], V[2]) + rotr26(V[0]); - V[3] = 0xc6e00bf3U + V[3] + W[12] + ch(V[0], V[1], V[2]) + rotr26(V[0]) + rotr30(V[4]) + ma(V[5], V[6], V[4]); - - V[6] += 0xd5a79147U + V[2] + W[13] + ch(V[7], V[0], V[1]) + rotr26(V[7]); - V[2] = 0xd5a79147U + V[2] + W[13] + ch(V[7], V[0], V[1]) + rotr26(V[7]) + rotr30(V[3]) + ma(V[4], V[5], V[3]); - - V[5] += 0x06ca6351U + V[1] + W[14] + ch(V[6], V[7], V[0]) + rotr26(V[6]); - V[1] = 0x06ca6351U + V[1] + W[14] + ch(V[6], V[7], V[0]) + rotr26(V[6]) + rotr30(V[2]) + ma(V[3], V[4], V[2]); - - V[4] += 0x14292967U + V[0] + W[15] + ch(V[5], V[6], V[7]) + rotr26(V[5]); - V[0] = 0x14292967U + V[0] + W[15] + ch(V[5], V[6], V[7]) + rotr26(V[5]) + rotr30(V[1]) + ma(V[2], V[3], V[1]); - -//---------------------------------------------------------------------------------- - - W[0] = W[0] + W[9] + rotr15(W[14]) + rotr25( W[1]); - W[1] = W[1] + W[10] + rotr15(W[15]) + rotr25( W[2]); - W[2] = W[2] + W[11] + rotr15( W[0]) + rotr25( W[3]); - W[3] = W[3] + W[12] + rotr15( W[1]) + rotr25( W[4]); - W[4] = W[4] + W[13] + rotr15( W[2]) + rotr25( W[5]); - W[5] = W[5] + W[14] + rotr15( W[3]) + rotr25( W[6]); - W[6] = W[6] + W[15] + rotr15( W[4]) + rotr25( W[7]); - W[7] = W[7] + W[0] + rotr15( W[5]) + rotr25( W[8]); - W[8] = W[8] + W[1] + rotr15( W[6]) + rotr25( W[9]); - W[9] = W[9] + W[2] + rotr15( W[7]) + rotr25(W[10]); - W[10] = W[10] + W[3] + rotr15( W[8]) + rotr25(W[11]); - W[11] = W[11] + W[4] + rotr15( W[9]) + rotr25(W[12]); - W[12] = W[12] + W[5] + rotr15(W[10]) + rotr25(W[13]); - W[13] = W[13] + W[6] + rotr15(W[11]) + rotr25(W[14]); - W[14] = W[14] + W[7] + rotr15(W[12]) + rotr25(W[15]); - W[15] = W[15] + W[8] + rotr15(W[13]) + rotr25( W[0]); - - V[3] += 0x27b70a85U + V[7] + W[0] + ch(V[4], V[5], V[6]) + rotr26(V[4]); - V[7] = 0x27b70a85U + V[7] + W[0] + ch(V[4], V[5], V[6]) + rotr26(V[4]) + rotr30(V[0]) + ma(V[1], V[2], V[0]); - - V[2] += 0x2e1b2138U + V[6] + W[1] + ch(V[3], V[4], V[5]) + rotr26(V[3]); - V[6] = 0x2e1b2138U + V[6] + W[1] + ch(V[3], V[4], V[5]) + rotr26(V[3]) + rotr30(V[7]) + ma(V[0], V[1], V[7]); - - V[1] += 0x4d2c6dfcU + V[5] + W[2] + ch(V[2], V[3], V[4]) + rotr26(V[2]); - V[5] = 0x4d2c6dfcU + V[5] + W[2] + ch(V[2], V[3], V[4]) + rotr26(V[2]) + rotr30(V[6]) + ma(V[7], V[0], V[6]); - - V[0] += 0x53380d13U + V[4] + W[3] + ch(V[1], V[2], V[3]) + rotr26(V[1]); - V[4] = 0x53380d13U + V[4] + W[3] + ch(V[1], V[2], V[3]) + rotr26(V[1]) + rotr30(V[5]) + ma(V[6], V[7], V[5]); - - V[7] += 0x650a7354U + V[3] + W[4] + ch(V[0], V[1], V[2]) + rotr26(V[0]); - V[3] = 0x650a7354U + V[3] + W[4] + ch(V[0], V[1], V[2]) + rotr26(V[0]) + rotr30(V[4]) + ma(V[5], V[6], V[4]); - - V[6] += 0x766a0abbU + V[2] + W[5] + ch(V[7], V[0], V[1]) + rotr26(V[7]); - V[2] = 0x766a0abbU + V[2] + W[5] + ch(V[7], V[0], V[1]) + rotr26(V[7]) + rotr30(V[3]) + ma(V[4], V[5], V[3]); - - V[5] += 0x81c2c92eU + V[1] + W[6] + ch(V[6], V[7], V[0]) + rotr26(V[6]); - V[1] = 0x81c2c92eU + V[1] + W[6] + ch(V[6], V[7], V[0]) + rotr26(V[6]) + rotr30(V[2]) + ma(V[3], V[4], V[2]); - - V[4] += 0x92722c85U + V[0] + W[7] + ch(V[5], V[6], V[7]) + rotr26(V[5]); - V[0] = 0x92722c85U + V[0] + W[7] + ch(V[5], V[6], V[7]) + rotr26(V[5]) + rotr30(V[1]) + ma(V[2], V[3], V[1]); - - V[3] += 0xa2bfe8a1U + V[7] + W[8] + ch(V[4], V[5], V[6]) + rotr26(V[4]); - V[7] = 0xa2bfe8a1U + V[7] + W[8] + ch(V[4], V[5], V[6]) + rotr26(V[4]) + rotr30(V[0]) + ma(V[1], V[2], V[0]); - - V[2] += 0xa81a664bU + V[6] + W[9] + ch(V[3], V[4], V[5]) + rotr26(V[3]); - V[6] = 0xa81a664bU + V[6] + W[9] + ch(V[3], V[4], V[5]) + rotr26(V[3]) + rotr30(V[7]) + ma(V[0], V[1], V[7]); - - V[1] += 0xc24b8b70U + V[5] + W[10] + ch(V[2], V[3], V[4]) + rotr26(V[2]); - V[5] = 0xc24b8b70U + V[5] + W[10] + ch(V[2], V[3], V[4]) + rotr26(V[2]) + rotr30(V[6]) + ma(V[7], V[0], V[6]); - - V[0] += 0xc76c51a3U + V[4] + W[11] + ch(V[1], V[2], V[3]) + rotr26(V[1]); - V[4] = 0xc76c51a3U + V[4] + W[11] + ch(V[1], V[2], V[3]) + rotr26(V[1]) + rotr30(V[5]) + ma(V[6], V[7], V[5]); - - V[7] += 0xd192e819U + V[3] + W[12] + ch(V[0], V[1], V[2]) + rotr26(V[0]); - V[3] = 0xd192e819U + V[3] + W[12] + ch(V[0], V[1], V[2]) + rotr26(V[0]) + rotr30(V[4]) + ma(V[5], V[6], V[4]); - - V[6] += 0xd6990624U + V[2] + W[13] + ch(V[7], V[0], V[1]) + rotr26(V[7]); - V[2] = 0xd6990624U + V[2] + W[13] + ch(V[7], V[0], V[1]) + rotr26(V[7]) + rotr30(V[3]) + ma(V[4], V[5], V[3]); - - V[5] += 0xf40e3585U + V[1] + W[14] + ch(V[6], V[7], V[0]) + rotr26(V[6]); - V[1] = 0xf40e3585U + V[1] + W[14] + ch(V[6], V[7], V[0]) + rotr26(V[6]) + rotr30(V[2]) + ma(V[3], V[4], V[2]); - - V[4] += 0x106aa070U + V[0] + W[15] + ch(V[5], V[6], V[7]) + rotr26(V[5]); - V[0] = 0x106aa070U + V[0] + W[15] + ch(V[5], V[6], V[7]) + rotr26(V[5]) + rotr30(V[1]) + ma(V[2], V[3], V[1]); - -//---------------------------------------------------------------------------------- - - W[0] = W[0] + W[9] + rotr15(W[14]) + rotr25( W[1]); - W[1] = W[1] + W[10] + rotr15(W[15]) + rotr25( W[2]); - W[2] = W[2] + W[11] + rotr15( W[0]) + rotr25( W[3]); - W[3] = W[3] + W[12] + rotr15( W[1]) + rotr25( W[4]); - W[4] = W[4] + W[13] + rotr15( W[2]) + rotr25( W[5]); - W[5] = W[5] + W[14] + rotr15( W[3]) + rotr25( W[6]); - W[6] = W[6] + W[15] + rotr15( W[4]) + rotr25( W[7]); - W[7] = W[7] + W[0] + rotr15( W[5]) + rotr25( W[8]); - W[8] = W[8] + W[1] + rotr15( W[6]) + rotr25( W[9]); - W[9] = W[9] + W[2] + rotr15( W[7]) + rotr25(W[10]); - W[10] = W[10] + W[3] + rotr15( W[8]) + rotr25(W[11]); - W[11] = W[11] + W[4] + rotr15( W[9]) + rotr25(W[12]); - W[12] = W[12] + W[5] + rotr15(W[10]) + rotr25(W[13]); - - V[3] += 0x19a4c116U + V[7] + W[0] + ch(V[4], V[5], V[6]) + rotr26(V[4]); - V[7] = 0x19a4c116U + V[7] + W[0] + ch(V[4], V[5], V[6]) + rotr26(V[4]) + rotr30(V[0]) + ma(V[1], V[2], V[0]); - - V[2] += 0x1e376c08U + V[6] + W[1] + ch(V[3], V[4], V[5]) + rotr26(V[3]); - V[6] = 0x1e376c08U + V[6] + W[1] + ch(V[3], V[4], V[5]) + rotr26(V[3]) + rotr30(V[7]) + ma(V[0], V[1], V[7]); - - V[1] += 0x2748774cU + V[5] + W[2] + ch(V[2], V[3], V[4]) + rotr26(V[2]); - V[5] = 0x2748774cU + V[5] + W[2] + ch(V[2], V[3], V[4]) + rotr26(V[2]) + rotr30(V[6]) + ma(V[7], V[0], V[6]); - - V[0] += 0x34b0bcb5U + V[4] + W[3] + ch(V[1], V[2], V[3]) + rotr26(V[1]); - V[4] = 0x34b0bcb5U + V[4] + W[3] + ch(V[1], V[2], V[3]) + rotr26(V[1]) + rotr30(V[5]) + ma(V[6], V[7], V[5]); - - V[7] += 0x391c0cb3U + V[3] + W[4] + ch(V[0], V[1], V[2]) + rotr26(V[0]); - V[3] = 0x391c0cb3U + V[3] + W[4] + ch(V[0], V[1], V[2]) + rotr26(V[0]) + rotr30(V[4]) + ma(V[5], V[6], V[4]); - - V[6] += 0x4ed8aa4aU + V[2] + W[5] + ch(V[7], V[0], V[1]) + rotr26(V[7]); - V[2] = 0x4ed8aa4aU + V[2] + W[5] + ch(V[7], V[0], V[1]) + rotr26(V[7]) + rotr30(V[3]) + ma(V[4], V[5], V[3]); - - V[5] += 0x5b9cca4fU + V[1] + W[6] + ch(V[6], V[7], V[0]) + rotr26(V[6]); - V[1] = 0x5b9cca4fU + V[1] + W[6] + ch(V[6], V[7], V[0]) + rotr26(V[6]) + rotr30(V[2]) + ma(V[3], V[4], V[2]); - - V[4] += 0x682e6ff3U + V[0] + W[7] + ch(V[5], V[6], V[7]) + rotr26(V[5]); - V[0] = 0x682e6ff3U + V[0] + W[7] + ch(V[5], V[6], V[7]) + rotr26(V[5]) + rotr30(V[1]) + ma(V[2], V[3], V[1]); - - V[3] += 0x748f82eeU + V[7] + W[8] + ch(V[4], V[5], V[6]) + rotr26(V[4]); - V[7] = 0x748f82eeU + V[7] + W[8] + ch(V[4], V[5], V[6]) + rotr26(V[4]) + rotr30(V[0]) + ma(V[1], V[2], V[0]); - - V[2] += 0x78a5636fU + V[6] + W[9] + ch(V[3], V[4], V[5]) + rotr26(V[3]); - - V[1] += 0x84c87814U + V[5] + W[10] + ch(V[2], V[3], V[4]) + rotr26(V[2]); - - V[0] += 0x8cc70208U + V[4] + W[11] + ch(V[1], V[2], V[3]) + rotr26(V[1]); - - V[7] += V[3] + W[12] + ch(V[0], V[1], V[2]) + rotr26(V[0]); - -#define FOUND (0x0F) -#define SETFOUND(Xnonce) output[output[FOUND]++] = Xnonce - -#ifdef VECTORS4 - if ((V[7].x == 0x136032edU) ^ (V[7].y == 0x136032edU) ^ (V[7].z == 0x136032edU) ^ (V[7].w == 0x136032edU)) { - if (V[7].x == 0x136032edU) - SETFOUND(nonce.x); - if (V[7].y == 0x136032edU) - SETFOUND(nonce.y); - if (V[7].z == 0x136032edU) - SETFOUND(nonce.z); - if (V[7].w == 0x136032edU) - SETFOUND(nonce.w); - } -#elif defined VECTORS2 - if ((V[7].x == 0x136032edU) + (V[7].y == 0x136032edU)) { - if (V[7].x == 0x136032edU) - SETFOUND(nonce.x); - if (V[7].y == 0x136032edU) - SETFOUND(nonce.y); - } -#else - if (V[7] == 0x136032edU) - SETFOUND(nonce); -#endif -} diff --git a/driver-avalon.c b/driver-avalon.c deleted file mode 100644 index 7cced1f9..00000000 --- a/driver-avalon.c +++ /dev/null @@ -1,1689 +0,0 @@ -/* - * Copyright 2013 Con Kolivas - * Copyright 2012-2013 Xiangfu - * Copyright 2012 Luke Dashjr - * Copyright 2012 Andrew Smith - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. See COPYING for more details. - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef WIN32 - #include - #include - #include - #include - #ifndef O_CLOEXEC - #define O_CLOEXEC 0 - #endif -#else - #include "compat.h" - #include - #include -#endif - -#include "elist.h" -#include "miner.h" -#include "usbutils.h" -#include "driver-avalon.h" -#include "hexdump.c" -#include "util.h" - -int opt_avalon_temp = AVALON_TEMP_TARGET; -int opt_avalon_overheat = AVALON_TEMP_OVERHEAT; -int opt_avalon_fan_min = AVALON_DEFAULT_FAN_MIN_PWM; -int opt_avalon_fan_max = AVALON_DEFAULT_FAN_MAX_PWM; -int opt_avalon_freq_min = AVALON_MIN_FREQUENCY; -int opt_avalon_freq_max = AVALON_MAX_FREQUENCY; -int opt_bitburner_core_voltage = BITBURNER_DEFAULT_CORE_VOLTAGE; -int opt_bitburner_fury_core_voltage = BITBURNER_FURY_DEFAULT_CORE_VOLTAGE; -bool opt_avalon_auto; - -static int option_offset = -1; -static int bbf_option_offset = -1; - -static int avalon_init_task(struct avalon_task *at, - uint8_t reset, uint8_t ff, uint8_t fan, - uint8_t timeout, uint8_t asic_num, - uint8_t miner_num, uint8_t nonce_elf, - uint8_t gate_miner, int frequency) -{ - uint16_t *lefreq16; - uint8_t *buf; - static bool first = true; - - if (unlikely(!at)) - return -1; - - if (unlikely(timeout <= 0 || asic_num <= 0 || miner_num <= 0)) - return -1; - - memset(at, 0, sizeof(struct avalon_task)); - - if (unlikely(reset)) { - at->reset = 1; - at->fan_eft = 1; - at->timer_eft = 1; - first = true; - } - - at->flush_fifo = (ff ? 1 : 0); - at->fan_eft = (fan ? 1 : 0); - - if (unlikely(first && !at->reset)) { - at->fan_eft = 1; - at->timer_eft = 1; - first = false; - } - - at->fan_pwm_data = (fan ? fan : AVALON_DEFAULT_FAN_MAX_PWM); - at->timeout_data = timeout; - at->asic_num = asic_num; - at->miner_num = miner_num; - at->nonce_elf = nonce_elf; - - at->gate_miner_elf = 1; - at->asic_pll = 1; - - if (unlikely(gate_miner)) { - at-> gate_miner = 1; - at->asic_pll = 0; - } - - buf = (uint8_t *)at; - buf[5] = 0x00; - buf[8] = 0x74; - buf[9] = 0x01; - buf[10] = 0x00; - buf[11] = 0x00; - lefreq16 = (uint16_t *)&buf[6]; - *lefreq16 = htole16(frequency * 8); - - return 0; -} - -static inline void avalon_create_task(struct avalon_task *at, - struct work *work) -{ - memcpy(at->midstate, work->midstate, 32); - memcpy(at->data, work->data + 64, 12); -} - -static int avalon_write(struct cgpu_info *avalon, char *buf, ssize_t len, int ep) -{ - int err, amount; - - err = usb_write(avalon, buf, len, &amount, ep); - applog(LOG_DEBUG, "%s%i: usb_write got err %d", avalon->drv->name, - avalon->device_id, err); - - if (unlikely(err != 0)) { - applog(LOG_WARNING, "usb_write error on avalon_write"); - return AVA_SEND_ERROR; - } - if (amount != len) { - applog(LOG_WARNING, "usb_write length mismatch on avalon_write"); - return AVA_SEND_ERROR; - } - - return AVA_SEND_OK; -} - -static int avalon_send_task(const struct avalon_task *at, struct cgpu_info *avalon) - -{ - uint8_t buf[AVALON_WRITE_SIZE + 4 * AVALON_DEFAULT_ASIC_NUM]; - int delay, ret, i, ep = C_AVALON_TASK; - struct avalon_info *info; - cgtimer_t ts_start; - uint32_t nonce_range; - size_t nr_len; - - if (at->nonce_elf) - nr_len = AVALON_WRITE_SIZE + 4 * at->asic_num; - else - nr_len = AVALON_WRITE_SIZE; - - memcpy(buf, at, AVALON_WRITE_SIZE); - - if (at->nonce_elf) { - nonce_range = (uint32_t)0xffffffff / at->asic_num; - for (i = 0; i < at->asic_num; i++) { - buf[AVALON_WRITE_SIZE + (i * 4) + 3] = - (i * nonce_range & 0xff000000) >> 24; - buf[AVALON_WRITE_SIZE + (i * 4) + 2] = - (i * nonce_range & 0x00ff0000) >> 16; - buf[AVALON_WRITE_SIZE + (i * 4) + 1] = - (i * nonce_range & 0x0000ff00) >> 8; - buf[AVALON_WRITE_SIZE + (i * 4) + 0] = - (i * nonce_range & 0x000000ff) >> 0; - } - } -#if defined(__BIG_ENDIAN__) || defined(MIPSEB) - uint8_t tt = 0; - - tt = (buf[0] & 0x0f) << 4; - tt |= ((buf[0] & 0x10) ? (1 << 3) : 0); - tt |= ((buf[0] & 0x20) ? (1 << 2) : 0); - tt |= ((buf[0] & 0x40) ? (1 << 1) : 0); - tt |= ((buf[0] & 0x80) ? (1 << 0) : 0); - buf[0] = tt; - - tt = (buf[4] & 0x0f) << 4; - tt |= ((buf[4] & 0x10) ? (1 << 3) : 0); - tt |= ((buf[4] & 0x20) ? (1 << 2) : 0); - tt |= ((buf[4] & 0x40) ? (1 << 1) : 0); - tt |= ((buf[4] & 0x80) ? (1 << 0) : 0); - buf[4] = tt; -#endif - info = avalon->device_data; - delay = nr_len * 10 * 1000000; - delay = delay / info->baud; - delay += 4000; - - if (at->reset) { - ep = C_AVALON_RESET; - nr_len = 1; - } - if (opt_debug) { - applog(LOG_DEBUG, "Avalon: Sent(%u):", (unsigned int)nr_len); - hexdump(buf, nr_len); - } - cgsleep_prepare_r(&ts_start); - ret = avalon_write(avalon, (char *)buf, nr_len, ep); - cgsleep_us_r(&ts_start, delay); - - applog(LOG_DEBUG, "Avalon: Sent: Buffer delay: %dus", delay); - - return ret; -} - -static int bitburner_send_task(const struct avalon_task *at, struct cgpu_info *avalon) - -{ - uint8_t buf[AVALON_WRITE_SIZE + 4 * AVALON_DEFAULT_ASIC_NUM]; - int ret, ep = C_AVALON_TASK; - cgtimer_t ts_start; - size_t nr_len; - - if (at->nonce_elf) - nr_len = AVALON_WRITE_SIZE + 4 * at->asic_num; - else - nr_len = AVALON_WRITE_SIZE; - - memset(buf, 0, nr_len); - memcpy(buf, at, AVALON_WRITE_SIZE); - -#if defined(__BIG_ENDIAN__) || defined(MIPSEB) - uint8_t tt = 0; - - tt = (buf[0] & 0x0f) << 4; - tt |= ((buf[0] & 0x10) ? (1 << 3) : 0); - tt |= ((buf[0] & 0x20) ? (1 << 2) : 0); - tt |= ((buf[0] & 0x40) ? (1 << 1) : 0); - tt |= ((buf[0] & 0x80) ? (1 << 0) : 0); - buf[0] = tt; - - tt = (buf[4] & 0x0f) << 4; - tt |= ((buf[4] & 0x10) ? (1 << 3) : 0); - tt |= ((buf[4] & 0x20) ? (1 << 2) : 0); - tt |= ((buf[4] & 0x40) ? (1 << 1) : 0); - tt |= ((buf[4] & 0x80) ? (1 << 0) : 0); - buf[4] = tt; -#endif - - if (at->reset) { - ep = C_AVALON_RESET; - nr_len = 1; - } - if (opt_debug) { - applog(LOG_DEBUG, "Avalon: Sent(%u):", (unsigned int)nr_len); - hexdump(buf, nr_len); - } - cgsleep_prepare_r(&ts_start); - ret = avalon_write(avalon, (char *)buf, nr_len, ep); - cgsleep_us_r(&ts_start, 3000); // 3 ms = 333 tasks per second, or 1.4 TH/s - - return ret; -} - -static bool avalon_decode_nonce(struct thr_info *thr, struct cgpu_info *avalon, - struct avalon_info *info, struct avalon_result *ar, - struct work *work) -{ - uint32_t nonce; - - info = avalon->device_data; - info->matching_work[work->subid]++; - nonce = htole32(ar->nonce); - applog(LOG_DEBUG, "Avalon: nonce = %0x08x", nonce); - return submit_nonce(thr, work, nonce); -} - -/* Wait until the ftdi chip returns a CTS saying we can send more data. */ -static void wait_avalon_ready(struct cgpu_info *avalon) -{ - while (avalon_buffer_full(avalon)) { - cgsleep_ms(40); - } -} - -#define AVALON_CTS (1 << 4) - -static inline bool avalon_cts(char c) -{ - return (c & AVALON_CTS); -} - -static int avalon_read(struct cgpu_info *avalon, unsigned char *buf, - size_t bufsize, int timeout, int ep) -{ - size_t total = 0, readsize = bufsize + 2; - char readbuf[AVALON_READBUF_SIZE]; - int err, amount, ofs = 2, cp; - - err = usb_read_once_timeout(avalon, readbuf, readsize, &amount, timeout, ep); - applog(LOG_DEBUG, "%s%i: Get avalon read got err %d", - avalon->drv->name, avalon->device_id, err); - - if (amount < 2) - goto out; - - /* The first 2 of every 64 bytes are status on FTDIRL */ - while (amount > 2) { - cp = amount - 2; - if (cp > 62) - cp = 62; - memcpy(&buf[total], &readbuf[ofs], cp); - total += cp; - amount -= cp + 2; - ofs += 64; - } -out: - return total; -} - -static int avalon_reset(struct cgpu_info *avalon, bool initial) -{ - struct avalon_result ar; - int ret, i, spare; - struct avalon_task at; - uint8_t *buf, *tmp; - struct timespec p; - struct avalon_info *info = avalon->device_data; - - /* Send reset, then check for result */ - avalon_init_task(&at, 1, 0, - AVALON_DEFAULT_FAN_MAX_PWM, - AVALON_DEFAULT_TIMEOUT, - AVALON_DEFAULT_ASIC_NUM, - AVALON_DEFAULT_MINER_NUM, - 0, 0, - AVALON_DEFAULT_FREQUENCY); - - wait_avalon_ready(avalon); - ret = avalon_send_task(&at, avalon); - if (unlikely(ret == AVA_SEND_ERROR)) - return -1; - - if (!initial) { - applog(LOG_ERR, "%s%d reset sequence sent", avalon->drv->name, avalon->device_id); - return 0; - } - - ret = avalon_read(avalon, (unsigned char *)&ar, AVALON_READ_SIZE, - AVALON_RESET_TIMEOUT, C_GET_AVALON_RESET); - - /* What do these sleeps do?? */ - p.tv_sec = 0; - p.tv_nsec = AVALON_RESET_PITCH; - nanosleep(&p, NULL); - - /* Look for the first occurrence of 0xAA, the reset response should be: - * AA 55 AA 55 00 00 00 00 00 00 */ - spare = ret - 10; - buf = tmp = (uint8_t *)&ar; - if (opt_debug) { - applog(LOG_DEBUG, "%s%d reset: get:", avalon->drv->name, avalon->device_id); - hexdump(tmp, AVALON_READ_SIZE); - } - - for (i = 0; i <= spare; i++) { - buf = &tmp[i]; - if (buf[0] == 0xAA) - break; - } - i = 0; - - if (buf[0] == 0xAA && buf[1] == 0x55 && - buf[2] == 0xAA && buf[3] == 0x55) { - for (i = 4; i < 11; i++) - if (buf[i] != 0) - break; - } - - if (i != 11) { - applog(LOG_ERR, "%s%d: Reset failed! not an Avalon?" - " (%d: %02x %02x %02x %02x)", avalon->drv->name, avalon->device_id, - i, buf[0], buf[1], buf[2], buf[3]); - /* FIXME: return 1; */ - } else { - /* buf[44]: minor - * buf[45]: day - * buf[46]: year,month, d6: 201306 - */ - info->ctlr_ver = ((buf[46] >> 4) + 2000) * 1000000 + - (buf[46] & 0x0f) * 10000 + - buf[45] * 100 + buf[44]; - applog(LOG_WARNING, "%s%d: Reset succeeded (Controller version: %d)", - avalon->drv->name, avalon->device_id, info->ctlr_ver); - } - - return 0; -} - -static int avalon_calc_timeout(int frequency) -{ - return AVALON_TIMEOUT_FACTOR / frequency; -} - -static bool get_options(int this_option_offset, int *baud, int *miner_count, - int *asic_count, int *timeout, int *frequency, char *options) -{ - char buf[BUFSIZ+1]; - char *ptr, *comma, *colon, *colon2, *colon3, *colon4; - bool timeout_default; - size_t max; - int i, tmp; - - if (options == NULL) - buf[0] = '\0'; - else { - ptr = options; - for (i = 0; i < this_option_offset; i++) { - comma = strchr(ptr, ','); - if (comma == NULL) - break; - ptr = comma + 1; - } - - comma = strchr(ptr, ','); - if (comma == NULL) - max = strlen(ptr); - else - max = comma - ptr; - - if (max > BUFSIZ) - max = BUFSIZ; - strncpy(buf, ptr, max); - buf[max] = '\0'; - } - - if (!(*buf)) - return false; - - colon = strchr(buf, ':'); - if (colon) - *(colon++) = '\0'; - - tmp = atoi(buf); - switch (tmp) { - case 115200: - *baud = 115200; - break; - case 57600: - *baud = 57600; - break; - case 38400: - *baud = 38400; - break; - case 19200: - *baud = 19200; - break; - default: - quit(1, "Invalid avalon-options for baud (%s) " - "must be 115200, 57600, 38400 or 19200", buf); - } - - if (colon && *colon) { - colon2 = strchr(colon, ':'); - if (colon2) - *(colon2++) = '\0'; - - if (*colon) { - tmp = atoi(colon); - if (tmp > 0 && tmp <= AVALON_MAX_MINER_NUM) { - *miner_count = tmp; - } else { - quit(1, "Invalid avalon-options for " - "miner_count (%s) must be 1 ~ %d", - colon, AVALON_MAX_MINER_NUM); - } - } - - if (colon2 && *colon2) { - colon3 = strchr(colon2, ':'); - if (colon3) - *(colon3++) = '\0'; - - tmp = atoi(colon2); - if (tmp > 0 && tmp <= AVALON_DEFAULT_ASIC_NUM) - *asic_count = tmp; - else { - quit(1, "Invalid avalon-options for " - "asic_count (%s) must be 1 ~ %d", - colon2, AVALON_DEFAULT_ASIC_NUM); - } - - timeout_default = false; - if (colon3 && *colon3) { - colon4 = strchr(colon3, ':'); - if (colon4) - *(colon4++) = '\0'; - - if (tolower(*colon3) == 'd') - timeout_default = true; - else { - tmp = atoi(colon3); - if (tmp > 0 && tmp <= 0xff) - *timeout = tmp; - else { - quit(1, "Invalid avalon-options for " - "timeout (%s) must be 1 ~ %d", - colon3, 0xff); - } - } - if (colon4 && *colon4) { - tmp = atoi(colon4); - if (tmp < AVALON_MIN_FREQUENCY || tmp > AVALON_MAX_FREQUENCY) { - quit(1, "Invalid avalon-options for frequency, must be %d <= frequency <= %d", - AVALON_MIN_FREQUENCY, AVALON_MAX_FREQUENCY); - } - *frequency = tmp; - if (timeout_default) - *timeout = avalon_calc_timeout(*frequency); - } - } - } - } - return true; -} - -char *set_avalon_fan(char *arg) -{ - int val1, val2, ret; - - ret = sscanf(arg, "%d-%d", &val1, &val2); - if (ret < 1) - return "No values passed to avalon-fan"; - if (ret == 1) - val2 = val1; - - if (val1 < 0 || val1 > 100 || val2 < 0 || val2 > 100 || val2 < val1) - return "Invalid value passed to avalon-fan"; - - opt_avalon_fan_min = val1 * AVALON_PWM_MAX / 100; - opt_avalon_fan_max = val2 * AVALON_PWM_MAX / 100; - - return NULL; -} - -char *set_avalon_freq(char *arg) -{ - int val1, val2, ret; - - ret = sscanf(arg, "%d-%d", &val1, &val2); - if (ret < 1) - return "No values passed to avalon-freq"; - if (ret == 1) - val2 = val1; - - if (val1 < AVALON_MIN_FREQUENCY || val1 > AVALON_MAX_FREQUENCY || - val2 < AVALON_MIN_FREQUENCY || val2 > AVALON_MAX_FREQUENCY || - val2 < val1) - return "Invalid value passed to avalon-freq"; - - opt_avalon_freq_min = val1; - opt_avalon_freq_max = val2; - - return NULL; -} - -static void avalon_idle(struct cgpu_info *avalon, struct avalon_info *info) -{ - int i; - - wait_avalon_ready(avalon); - /* Send idle to all miners */ - for (i = 0; i < info->miner_count; i++) { - struct avalon_task at; - - if (unlikely(avalon_buffer_full(avalon))) - break; - info->idle++; - avalon_init_task(&at, 0, 0, info->fan_pwm, info->timeout, - info->asic_count, info->miner_count, 1, 1, - info->frequency); - avalon_send_task(&at, avalon); - } - applog(LOG_WARNING, "%s%i: Idling %d miners", avalon->drv->name, avalon->device_id, i); - wait_avalon_ready(avalon); -} - -static void avalon_initialise(struct cgpu_info *avalon) -{ - int err, interface; - - if (avalon->usbinfo.nodev) - return; - - interface = usb_interface(avalon); - // Reset - err = usb_transfer(avalon, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, - FTDI_VALUE_RESET, interface, C_RESET); - - applog(LOG_DEBUG, "%s%i: reset got err %d", - avalon->drv->name, avalon->device_id, err); - - if (avalon->usbinfo.nodev) - return; - - // Set latency - err = usb_transfer(avalon, FTDI_TYPE_OUT, FTDI_REQUEST_LATENCY, - AVALON_LATENCY, interface, C_LATENCY); - - applog(LOG_DEBUG, "%s%i: latency got err %d", - avalon->drv->name, avalon->device_id, err); - - if (avalon->usbinfo.nodev) - return; - - // Set data - err = usb_transfer(avalon, FTDI_TYPE_OUT, FTDI_REQUEST_DATA, - FTDI_VALUE_DATA_AVA, interface, C_SETDATA); - - applog(LOG_DEBUG, "%s%i: data got err %d", - avalon->drv->name, avalon->device_id, err); - - if (avalon->usbinfo.nodev) - return; - - // Set the baud - err = usb_transfer(avalon, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, FTDI_VALUE_BAUD_AVA, - (FTDI_INDEX_BAUD_AVA & 0xff00) | interface, - C_SETBAUD); - - applog(LOG_DEBUG, "%s%i: setbaud got err %d", - avalon->drv->name, avalon->device_id, err); - - if (avalon->usbinfo.nodev) - return; - - // Set Modem Control - err = usb_transfer(avalon, FTDI_TYPE_OUT, FTDI_REQUEST_MODEM, - FTDI_VALUE_MODEM, interface, C_SETMODEM); - - applog(LOG_DEBUG, "%s%i: setmodemctrl got err %d", - avalon->drv->name, avalon->device_id, err); - - if (avalon->usbinfo.nodev) - return; - - // Set Flow Control - err = usb_transfer(avalon, FTDI_TYPE_OUT, FTDI_REQUEST_FLOW, - FTDI_VALUE_FLOW, interface, C_SETFLOW); - - applog(LOG_DEBUG, "%s%i: setflowctrl got err %d", - avalon->drv->name, avalon->device_id, err); - - if (avalon->usbinfo.nodev) - return; - - /* Avalon repeats the following */ - // Set Modem Control - err = usb_transfer(avalon, FTDI_TYPE_OUT, FTDI_REQUEST_MODEM, - FTDI_VALUE_MODEM, interface, C_SETMODEM); - - applog(LOG_DEBUG, "%s%i: setmodemctrl 2 got err %d", - avalon->drv->name, avalon->device_id, err); - - if (avalon->usbinfo.nodev) - return; - - // Set Flow Control - err = usb_transfer(avalon, FTDI_TYPE_OUT, FTDI_REQUEST_FLOW, - FTDI_VALUE_FLOW, interface, C_SETFLOW); - - applog(LOG_DEBUG, "%s%i: setflowctrl 2 got err %d", - avalon->drv->name, avalon->device_id, err); -} - -static bool is_bitburner(struct cgpu_info *avalon) -{ - enum sub_ident ident; - - ident = usb_ident(avalon); - return ident == IDENT_BTB || ident == IDENT_BBF; -} - -static bool bitburner_set_core_voltage(struct cgpu_info *avalon, int core_voltage) -{ - uint8_t buf[2]; - int err; - - if (is_bitburner(avalon)) { - buf[0] = (uint8_t)core_voltage; - buf[1] = (uint8_t)(core_voltage >> 8); - err = usb_transfer_data(avalon, FTDI_TYPE_OUT, BITBURNER_REQUEST, - BITBURNER_VALUE, BITBURNER_INDEX_SET_VOLTAGE, - (uint32_t *)buf, sizeof(buf), C_BB_SET_VOLTAGE); - if (unlikely(err < 0)) { - applog(LOG_ERR, "%s%i: SetCoreVoltage failed: err = %d", - avalon->drv->name, avalon->device_id, err); - return false; - } else { - applog(LOG_WARNING, "%s%i: Core voltage set to %d millivolts", - avalon->drv->name, avalon->device_id, - core_voltage); - } - return true; - } - return false; -} - -static int bitburner_get_core_voltage(struct cgpu_info *avalon) -{ - uint8_t buf[2]; - int err; - int amount; - - if (is_bitburner(avalon)) { - err = usb_transfer_read(avalon, FTDI_TYPE_IN, BITBURNER_REQUEST, - BITBURNER_VALUE, BITBURNER_INDEX_GET_VOLTAGE, - (char *)buf, sizeof(buf), &amount, - C_BB_GET_VOLTAGE); - if (unlikely(err != 0 || amount != 2)) { - applog(LOG_ERR, "%s%i: GetCoreVoltage failed: err = %d, amount = %d", - avalon->drv->name, avalon->device_id, err, amount); - return 0; - } else { - return (int)(buf[0] + ((unsigned int)buf[1] << 8)); - } - } else { - return 0; - } -} - -static void bitburner_get_version(struct cgpu_info *avalon) -{ - struct avalon_info *info = avalon->device_data; - uint8_t buf[3]; - int err; - int amount; - - err = usb_transfer_read(avalon, FTDI_TYPE_IN, BITBURNER_REQUEST, - BITBURNER_VALUE, BITBURNER_INDEX_GET_VERSION, - (char *)buf, sizeof(buf), &amount, - C_GETVERSION); - if (unlikely(err != 0 || amount != sizeof(buf))) { - applog(LOG_DEBUG, "%s%i: GetVersion failed: err=%d, amt=%d assuming %d.%d.%d", - avalon->drv->name, avalon->device_id, err, amount, - BITBURNER_VERSION1, BITBURNER_VERSION2, BITBURNER_VERSION3); - info->version1 = BITBURNER_VERSION1; - info->version2 = BITBURNER_VERSION2; - info->version3 = BITBURNER_VERSION3; - } else { - info->version1 = buf[0]; - info->version2 = buf[1]; - info->version3 = buf[2]; - } -} - -static bool avalon_detect_one(libusb_device *dev, struct usb_find_devices *found) -{ - int baud, miner_count, asic_count, timeout, frequency; - int this_option_offset; - struct avalon_info *info; - struct cgpu_info *avalon; - bool configured; - int ret; - - avalon = usb_alloc_cgpu(&avalon_drv, AVALON_MINER_THREADS); - - baud = AVALON_IO_SPEED; - miner_count = AVALON_DEFAULT_MINER_NUM; - asic_count = AVALON_DEFAULT_ASIC_NUM; - timeout = AVALON_DEFAULT_TIMEOUT; - frequency = AVALON_DEFAULT_FREQUENCY; - - if (!usb_init(avalon, dev, found)) - goto shin; - - this_option_offset = usb_ident(avalon) == IDENT_BBF ? ++bbf_option_offset : ++option_offset; - configured = get_options(this_option_offset, &baud, &miner_count, - &asic_count, &timeout, &frequency, - (usb_ident(avalon) == IDENT_BBF && opt_bitburner_fury_options != NULL) ? opt_bitburner_fury_options : opt_avalon_options); - - /* Even though this is an FTDI type chip, we want to do the parsing - * all ourselves so set it to std usb type */ - avalon->usbdev->usb_type = USB_TYPE_STD; - - /* We have a real Avalon! */ - avalon_initialise(avalon); - - avalon->device_data = calloc(sizeof(struct avalon_info), 1); - if (unlikely(!(avalon->device_data))) - quit(1, "Failed to calloc avalon_info data"); - info = avalon->device_data; - - if (configured) { - info->baud = baud; - info->miner_count = miner_count; - info->asic_count = asic_count; - info->timeout = timeout; - info->frequency = frequency; - } else { - info->baud = AVALON_IO_SPEED; - info->asic_count = AVALON_DEFAULT_ASIC_NUM; - switch (usb_ident(avalon)) { - case IDENT_BBF: - info->miner_count = BITBURNER_FURY_DEFAULT_MINER_NUM; - info->timeout = BITBURNER_FURY_DEFAULT_TIMEOUT; - info->frequency = BITBURNER_FURY_DEFAULT_FREQUENCY; - break; - default: - info->miner_count = AVALON_DEFAULT_MINER_NUM; - info->timeout = AVALON_DEFAULT_TIMEOUT; - info->frequency = AVALON_DEFAULT_FREQUENCY; - } - } - - info->fan_pwm = AVALON_DEFAULT_FAN_MIN_PWM; - info->temp_max = 0; - /* This is for check the temp/fan every 3~4s */ - info->temp_history_count = (4 / (float)((float)info->timeout * ((float)1.67/0x32))) + 1; - if (info->temp_history_count <= 0) - info->temp_history_count = 1; - - info->temp_history_index = 0; - info->temp_sum = 0; - info->temp_old = 0; - - if (!add_cgpu(avalon)) - goto unshin; - - ret = avalon_reset(avalon, true); - if (ret && !configured) - goto unshin; - - update_usb_stats(avalon); - - avalon_idle(avalon, info); - - applog(LOG_DEBUG, "Avalon Detected: %s " - "(miner_count=%d asic_count=%d timeout=%d frequency=%d)", - avalon->device_path, info->miner_count, info->asic_count, info->timeout, - info->frequency); - - if (usb_ident(avalon) == IDENT_BTB) { - if (opt_bitburner_core_voltage < BITBURNER_MIN_COREMV || - opt_bitburner_core_voltage > BITBURNER_MAX_COREMV) { - quit(1, "Invalid bitburner-voltage %d must be %dmv - %dmv", - opt_bitburner_core_voltage, - BITBURNER_MIN_COREMV, - BITBURNER_MAX_COREMV); - } else - bitburner_set_core_voltage(avalon, opt_bitburner_core_voltage); - } else if (usb_ident(avalon) == IDENT_BBF) { - if (opt_bitburner_fury_core_voltage < BITBURNER_FURY_MIN_COREMV || - opt_bitburner_fury_core_voltage > BITBURNER_FURY_MAX_COREMV) { - quit(1, "Invalid bitburner-fury-voltage %d must be %dmv - %dmv", - opt_bitburner_fury_core_voltage, - BITBURNER_FURY_MIN_COREMV, - BITBURNER_FURY_MAX_COREMV); - } else - bitburner_set_core_voltage(avalon, opt_bitburner_fury_core_voltage); - } - - if (is_bitburner(avalon)) { - bitburner_get_version(avalon); - } - - return true; - -unshin: - - usb_uninit(avalon); - -shin: - - free(avalon->device_data); - avalon->device_data = NULL; - - avalon = usb_free_cgpu(avalon); - - return false; -} - -static void avalon_detect(bool __maybe_unused hotplug) -{ - usb_detect(&avalon_drv, avalon_detect_one); -} - -static void avalon_init(struct cgpu_info *avalon) -{ - applog(LOG_INFO, "Avalon: Opened on %s", avalon->device_path); -} - -static struct work *avalon_valid_result(struct cgpu_info *avalon, struct avalon_result *ar) -{ - return clone_queued_work_bymidstate(avalon, (char *)ar->midstate, 32, - (char *)ar->data, 64, 12); -} - -static void avalon_update_temps(struct cgpu_info *avalon, struct avalon_info *info, - struct avalon_result *ar); - -static void avalon_inc_nvw(struct avalon_info *info, struct thr_info *thr) -{ - applog(LOG_INFO, "%s%d: No matching work - HW error", - thr->cgpu->drv->name, thr->cgpu->device_id); - - inc_hw_errors(thr); - info->no_matching_work++; -} - -static void avalon_parse_results(struct cgpu_info *avalon, struct avalon_info *info, - struct thr_info *thr, char *buf, int *offset) -{ - int i, spare = *offset - AVALON_READ_SIZE; - bool found = false; - - for (i = 0; i <= spare; i++) { - struct avalon_result *ar; - struct work *work; - - ar = (struct avalon_result *)&buf[i]; - work = avalon_valid_result(avalon, ar); - if (work) { - bool gettemp = false; - - found = true; - - if (avalon_decode_nonce(thr, avalon, info, ar, work)) { - mutex_lock(&info->lock); - if (!info->nonces++) - gettemp = true; - info->auto_nonces++; - mutex_unlock(&info->lock); - } else if (opt_avalon_auto) { - mutex_lock(&info->lock); - info->auto_hw++; - mutex_unlock(&info->lock); - } - free_work(work); - - if (gettemp) - avalon_update_temps(avalon, info, ar); - break; - } - } - - if (!found) { - spare = *offset - AVALON_READ_SIZE; - /* We are buffering and haven't accumulated one more corrupt - * work result. */ - if (spare < (int)AVALON_READ_SIZE) - return; - avalon_inc_nvw(info, thr); - } else { - spare = AVALON_READ_SIZE + i; - if (i) { - if (i >= (int)AVALON_READ_SIZE) - avalon_inc_nvw(info, thr); - else - applog(LOG_WARNING, "Avalon: Discarding %d bytes from buffer", i); - } - } - - *offset -= spare; - memmove(buf, buf + spare, *offset); -} - -static void avalon_running_reset(struct cgpu_info *avalon, - struct avalon_info *info) -{ - avalon_reset(avalon, false); - avalon_idle(avalon, info); - avalon->results = 0; - info->reset = false; -} - -static void *avalon_get_results(void *userdata) -{ - struct cgpu_info *avalon = (struct cgpu_info *)userdata; - struct avalon_info *info = avalon->device_data; - const int rsize = AVALON_FTDI_READSIZE; - char readbuf[AVALON_READBUF_SIZE]; - struct thr_info *thr = info->thr; - cgtimer_t ts_start; - int offset = 0, ret = 0; - char threadname[24]; - - snprintf(threadname, 24, "ava_recv/%d", avalon->device_id); - RenameThread(threadname); - cgsleep_prepare_r(&ts_start); - - while (likely(!avalon->shutdown)) { - unsigned char buf[rsize]; - - if (offset >= (int)AVALON_READ_SIZE) - avalon_parse_results(avalon, info, thr, readbuf, &offset); - - if (unlikely(offset + rsize >= AVALON_READBUF_SIZE)) { - /* This should never happen */ - applog(LOG_ERR, "Avalon readbuf overflow, resetting buffer"); - offset = 0; - } - - if (unlikely(info->reset)) { - avalon_running_reset(avalon, info); - /* Discard anything in the buffer */ - offset = 0; - } - - /* As the usb read returns after just 1ms, sleep long enough - * to leave the interface idle for writes to occur, but do not - * sleep if we have been receiving data, and we do not yet have - * a full result as more may be coming. */ - if (ret < 1 || offset == 0) - cgsleep_ms_r(&ts_start, AVALON_READ_TIMEOUT); - - cgsleep_prepare_r(&ts_start); - ret = avalon_read(avalon, buf, rsize, AVALON_READ_TIMEOUT, - C_AVALON_READ); - - if (ret < 1) - continue; - - if (opt_debug) { - applog(LOG_DEBUG, "Avalon: get:"); - hexdump((uint8_t *)buf, ret); - } - - memcpy(&readbuf[offset], &buf, ret); - offset += ret; - } - return NULL; -} - -static void avalon_rotate_array(struct cgpu_info *avalon) -{ - avalon->queued = 0; - if (++avalon->work_array >= AVALON_ARRAY_SIZE) - avalon->work_array = 0; -} - -static void bitburner_rotate_array(struct cgpu_info *avalon) -{ - avalon->queued = 0; - if (++avalon->work_array >= BITBURNER_ARRAY_SIZE) - avalon->work_array = 0; -} - -static void avalon_set_timeout(struct avalon_info *info) -{ - info->timeout = avalon_calc_timeout(info->frequency); -} - -static void avalon_set_freq(struct cgpu_info *avalon, int frequency) -{ - struct avalon_info *info = avalon->device_data; - - info->frequency = frequency; - if (info->frequency > opt_avalon_freq_max) - info->frequency = opt_avalon_freq_max; - if (info->frequency < opt_avalon_freq_min) - info->frequency = opt_avalon_freq_min; - avalon_set_timeout(info); - applog(LOG_WARNING, "%s%i: Set frequency to %d, timeout %d", - avalon->drv->name, avalon->device_id, - info->frequency, info->timeout); -} - -static void avalon_inc_freq(struct avalon_info *info) -{ - info->frequency += 2; - if (info->frequency > opt_avalon_freq_max) - info->frequency = opt_avalon_freq_max; - avalon_set_timeout(info); - applog(LOG_NOTICE, "Avalon increasing frequency to %d, timeout %d", - info->frequency, info->timeout); -} - -static void avalon_dec_freq(struct avalon_info *info) -{ - info->frequency -= 1; - if (info->frequency < opt_avalon_freq_min) - info->frequency = opt_avalon_freq_min; - avalon_set_timeout(info); - applog(LOG_NOTICE, "Avalon decreasing frequency to %d, timeout %d", - info->frequency, info->timeout); -} - -static void avalon_reset_auto(struct avalon_info *info) -{ - info->auto_queued = - info->auto_nonces = - info->auto_hw = 0; -} - -static void avalon_adjust_freq(struct avalon_info *info, struct cgpu_info *avalon) -{ - if (opt_avalon_auto && info->auto_queued >= AVALON_AUTO_CYCLE) { - mutex_lock(&info->lock); - if (!info->optimal) { - if (info->fan_pwm >= opt_avalon_fan_max) { - applog(LOG_WARNING, - "%s%i: Above optimal temperature, throttling", - avalon->drv->name, avalon->device_id); - avalon_dec_freq(info); - } - } else if (info->auto_nonces >= (AVALON_AUTO_CYCLE * 19 / 20) && - info->auto_nonces <= (AVALON_AUTO_CYCLE * 21 / 20)) { - int total = info->auto_nonces + info->auto_hw; - - /* Try to keep hw errors < 2% */ - if (info->auto_hw * 100 < total) - avalon_inc_freq(info); - else if (info->auto_hw * 66 > total) - avalon_dec_freq(info); - } - avalon_reset_auto(info); - mutex_unlock(&info->lock); - } -} - -static void *avalon_send_tasks(void *userdata) -{ - struct cgpu_info *avalon = (struct cgpu_info *)userdata; - struct avalon_info *info = avalon->device_data; - const int avalon_get_work_count = info->miner_count; - char threadname[24]; - - snprintf(threadname, 24, "ava_send/%d", avalon->device_id); - RenameThread(threadname); - - while (likely(!avalon->shutdown)) { - int start_count, end_count, i, j, ret; - cgtimer_t ts_start; - struct avalon_task at; - bool idled = false; - int64_t us_timeout; - - while (avalon_buffer_full(avalon)) - cgsleep_ms(40); - - avalon_adjust_freq(info, avalon); - - /* A full nonce range */ - us_timeout = 0x100000000ll / info->asic_count / info->frequency; - cgsleep_prepare_r(&ts_start); - - mutex_lock(&info->qlock); - start_count = avalon->work_array * avalon_get_work_count; - end_count = start_count + avalon_get_work_count; - for (i = start_count, j = 0; i < end_count; i++, j++) { - if (avalon_buffer_full(avalon)) { - applog(LOG_INFO, - "%s%i: Buffer full after only %d of %d work queued", - avalon->drv->name, avalon->device_id, j, avalon_get_work_count); - break; - } - - if (likely(j < avalon->queued && !info->overheat && avalon->works[i])) { - avalon_init_task(&at, 0, 0, info->fan_pwm, - info->timeout, info->asic_count, - info->miner_count, 1, 0, info->frequency); - avalon_create_task(&at, avalon->works[i]); - info->auto_queued++; - } else { - int idle_freq = info->frequency; - - if (!info->idle++) - idled = true; - if (unlikely(info->overheat && opt_avalon_auto)) - idle_freq = AVALON_MIN_FREQUENCY; - avalon_init_task(&at, 0, 0, info->fan_pwm, - info->timeout, info->asic_count, - info->miner_count, 1, 1, idle_freq); - /* Reset the auto_queued count if we end up - * idling any miners. */ - avalon_reset_auto(info); - } - - ret = avalon_send_task(&at, avalon); - - if (unlikely(ret == AVA_SEND_ERROR)) { - applog(LOG_ERR, "%s%i: Comms error(buffer)", - avalon->drv->name, avalon->device_id); - dev_error(avalon, REASON_DEV_COMMS_ERROR); - info->reset = true; - break; - } - } - - avalon_rotate_array(avalon); - mutex_unlock(&info->qlock); - - cgsem_post(&info->qsem); - - if (unlikely(idled)) { - applog(LOG_WARNING, "%s%i: Idled %d miners", - avalon->drv->name, avalon->device_id, idled); - } - - /* Sleep how long it would take to complete a full nonce range - * at the current frequency using the clock_nanosleep function - * timed from before we started loading new work so it will - * fall short of the full duration. */ - cgsleep_us_r(&ts_start, us_timeout); - } - return NULL; -} - -static void *bitburner_send_tasks(void *userdata) -{ - struct cgpu_info *avalon = (struct cgpu_info *)userdata; - struct avalon_info *info = avalon->device_data; - const int avalon_get_work_count = info->miner_count; - char threadname[24]; - - snprintf(threadname, 24, "ava_send/%d", avalon->device_id); - RenameThread(threadname); - - while (likely(!avalon->shutdown)) { - int start_count, end_count, i, j, ret; - struct avalon_task at; - bool idled = false; - - while (avalon_buffer_full(avalon)) - cgsleep_ms(40); - - avalon_adjust_freq(info, avalon); - - /* Give other threads a chance to acquire qlock. */ - i = 0; - do { - cgsleep_ms(40); - } while (!avalon->shutdown && i++ < 15 - && avalon->queued < avalon_get_work_count); - - mutex_lock(&info->qlock); - start_count = avalon->work_array * avalon_get_work_count; - end_count = start_count + avalon_get_work_count; - for (i = start_count, j = 0; i < end_count; i++, j++) { - while (avalon_buffer_full(avalon)) - cgsleep_ms(40); - - if (likely(j < avalon->queued && !info->overheat && avalon->works[i])) { - avalon_init_task(&at, 0, 0, info->fan_pwm, - info->timeout, info->asic_count, - info->miner_count, 1, 0, info->frequency); - avalon_create_task(&at, avalon->works[i]); - info->auto_queued++; - } else { - int idle_freq = info->frequency; - - if (!info->idle++) - idled = true; - if (unlikely(info->overheat && opt_avalon_auto)) - idle_freq = AVALON_MIN_FREQUENCY; - avalon_init_task(&at, 0, 0, info->fan_pwm, - info->timeout, info->asic_count, - info->miner_count, 1, 1, idle_freq); - /* Reset the auto_queued count if we end up - * idling any miners. */ - avalon_reset_auto(info); - } - - ret = bitburner_send_task(&at, avalon); - - if (unlikely(ret == AVA_SEND_ERROR)) { - applog(LOG_ERR, "%s%i: Comms error(buffer)", - avalon->drv->name, avalon->device_id); - dev_error(avalon, REASON_DEV_COMMS_ERROR); - info->reset = true; - break; - } - } - - bitburner_rotate_array(avalon); - mutex_unlock(&info->qlock); - - cgsem_post(&info->qsem); - - if (unlikely(idled)) { - applog(LOG_WARNING, "%s%i: Idled %d miners", - avalon->drv->name, avalon->device_id, idled); - } - } - return NULL; -} - -static bool avalon_prepare(struct thr_info *thr) -{ - struct cgpu_info *avalon = thr->cgpu; - struct avalon_info *info = avalon->device_data; - int array_size = AVALON_ARRAY_SIZE; - void *(*write_thread_fn)(void *) = avalon_send_tasks; - - if (is_bitburner(avalon)) { - array_size = BITBURNER_ARRAY_SIZE; - write_thread_fn = bitburner_send_tasks; - } - - free(avalon->works); - avalon->works = calloc(info->miner_count * sizeof(struct work *), - array_size); - if (!avalon->works) - quit(1, "Failed to calloc avalon works in avalon_prepare"); - - info->thr = thr; - mutex_init(&info->lock); - mutex_init(&info->qlock); - cgsem_init(&info->qsem); - - if (pthread_create(&info->read_thr, NULL, avalon_get_results, (void *)avalon)) - quit(1, "Failed to create avalon read_thr"); - - if (pthread_create(&info->write_thr, NULL, write_thread_fn, (void *)avalon)) - quit(1, "Failed to create avalon write_thr"); - - avalon_init(avalon); - - return true; -} - -static inline void record_temp_fan(struct avalon_info *info, struct avalon_result *ar, float *temp_avg) -{ - info->fan0 = ar->fan0 * AVALON_FAN_FACTOR; - info->fan1 = ar->fan1 * AVALON_FAN_FACTOR; - info->fan2 = ar->fan2 * AVALON_FAN_FACTOR; - - info->temp0 = ar->temp0; - info->temp1 = ar->temp1; - info->temp2 = ar->temp2; - if (ar->temp0 & 0x80) { - ar->temp0 &= 0x7f; - info->temp0 = 0 - ((~ar->temp0 & 0x7f) + 1); - } - if (ar->temp1 & 0x80) { - ar->temp1 &= 0x7f; - info->temp1 = 0 - ((~ar->temp1 & 0x7f) + 1); - } - if (ar->temp2 & 0x80) { - ar->temp2 &= 0x7f; - info->temp2 = 0 - ((~ar->temp2 & 0x7f) + 1); - } - - *temp_avg = info->temp2 > info->temp1 ? info->temp2 : info->temp1; - - if (info->temp0 > info->temp_max) - info->temp_max = info->temp0; - if (info->temp1 > info->temp_max) - info->temp_max = info->temp1; - if (info->temp2 > info->temp_max) - info->temp_max = info->temp2; -} - -static void temp_rise(struct avalon_info *info, int temp) -{ - if (temp >= opt_avalon_temp + AVALON_TEMP_HYSTERESIS * 3) { - info->fan_pwm = AVALON_PWM_MAX; - return; - } - if (temp >= opt_avalon_temp + AVALON_TEMP_HYSTERESIS * 2) - info->fan_pwm += 10; - else if (temp > opt_avalon_temp) - info->fan_pwm += 5; - else if (temp >= opt_avalon_temp - AVALON_TEMP_HYSTERESIS) - info->fan_pwm += 1; - else - return; - - if (info->fan_pwm > opt_avalon_fan_max) - info->fan_pwm = opt_avalon_fan_max; -} - -static void temp_drop(struct avalon_info *info, int temp) -{ - if (temp <= opt_avalon_temp - AVALON_TEMP_HYSTERESIS * 3) { - info->fan_pwm = opt_avalon_fan_min; - return; - } - if (temp <= opt_avalon_temp - AVALON_TEMP_HYSTERESIS * 2) - info->fan_pwm -= 10; - else if (temp <= opt_avalon_temp - AVALON_TEMP_HYSTERESIS) - info->fan_pwm -= 5; - else if (temp < opt_avalon_temp) - info->fan_pwm -= 1; - - if (info->fan_pwm < opt_avalon_fan_min) - info->fan_pwm = opt_avalon_fan_min; -} - -static inline void adjust_fan(struct avalon_info *info) -{ - int temp_new; - - temp_new = info->temp_sum / info->temp_history_count; - - if (temp_new > info->temp_old) - temp_rise(info, temp_new); - else if (temp_new < info->temp_old) - temp_drop(info, temp_new); - else { - /* temp_new == info->temp_old */ - if (temp_new > opt_avalon_temp) - temp_rise(info, temp_new); - else if (temp_new < opt_avalon_temp - AVALON_TEMP_HYSTERESIS) - temp_drop(info, temp_new); - } - info->temp_old = temp_new; - if (info->temp_old <= opt_avalon_temp) - info->optimal = true; - else - info->optimal = false; -} - -static void avalon_update_temps(struct cgpu_info *avalon, struct avalon_info *info, - struct avalon_result *ar) -{ - record_temp_fan(info, ar, &(avalon->temp)); - applog(LOG_INFO, - "Avalon: Fan1: %d/m, Fan2: %d/m, Fan3: %d/m\t" - "Temp1: %dC, Temp2: %dC, Temp3: %dC, TempMAX: %dC", - info->fan0, info->fan1, info->fan2, - info->temp0, info->temp1, info->temp2, info->temp_max); - info->temp_history_index++; - info->temp_sum += avalon->temp; - applog(LOG_DEBUG, "Avalon: temp_index: %d, temp_count: %d, temp_old: %d", - info->temp_history_index, info->temp_history_count, info->temp_old); - if (is_bitburner(avalon)) { - info->core_voltage = bitburner_get_core_voltage(avalon); - } - if (info->temp_history_index == info->temp_history_count) { - adjust_fan(info); - info->temp_history_index = 0; - info->temp_sum = 0; - } - if (unlikely(info->temp_old >= opt_avalon_overheat)) { - applog(LOG_WARNING, "%s%d overheat! Idling", avalon->drv->name, avalon->device_id); - info->overheat = true; - } else if (info->overheat && info->temp_old <= opt_avalon_temp) { - applog(LOG_WARNING, "%s%d cooled, restarting", avalon->drv->name, avalon->device_id); - info->overheat = false; - } -} - -static void get_avalon_statline_before(char *buf, size_t bufsiz, struct cgpu_info *avalon) -{ - struct avalon_info *info = avalon->device_data; - int lowfan = 10000; - - if (is_bitburner(avalon)) { - int temp = info->temp0; - if (info->temp2 > temp) - temp = info->temp2; - if (temp > 99) - temp = 99; - if (temp < 0) - temp = 0; - tailsprintf(buf, bufsiz, "%2dC %3d %4dmV | ", temp, info->frequency, info->core_voltage); - } else { - /* Find the lowest fan speed of the ASIC cooling fans. */ - if (info->fan1 >= 0 && info->fan1 < lowfan) - lowfan = info->fan1; - if (info->fan2 >= 0 && info->fan2 < lowfan) - lowfan = info->fan2; - - tailsprintf(buf, bufsiz, "%2dC/%3dC %04dR | ", info->temp0, info->temp2, lowfan); - } -} - -/* We use a replacement algorithm to only remove references to work done from - * the buffer when we need the extra space for new work. */ -static bool avalon_fill(struct cgpu_info *avalon) -{ - struct avalon_info *info = avalon->device_data; - int subid, slot, mc; - struct work *work; - bool ret = true; - - mc = info->miner_count; - mutex_lock(&info->qlock); - if (avalon->queued >= mc) - goto out_unlock; - work = get_queued(avalon); - if (unlikely(!work)) { - ret = false; - goto out_unlock; - } - subid = avalon->queued++; - work->subid = subid; - slot = avalon->work_array * mc + subid; - if (likely(avalon->works[slot])) - work_completed(avalon, avalon->works[slot]); - avalon->works[slot] = work; - if (avalon->queued < mc) - ret = false; -out_unlock: - mutex_unlock(&info->qlock); - - return ret; -} - -static int64_t avalon_scanhash(struct thr_info *thr) -{ - struct cgpu_info *avalon = thr->cgpu; - struct avalon_info *info = avalon->device_data; - const int miner_count = info->miner_count; - int64_t hash_count, ms_timeout; - - /* Half nonce range */ - ms_timeout = 0x80000000ll / info->asic_count / info->frequency / 1000; - - /* Wait until avalon_send_tasks signals us that it has completed - * sending its work or a full nonce range timeout has occurred. We use - * cgsems to never miss a wakeup. */ - cgsem_mswait(&info->qsem, ms_timeout); - - mutex_lock(&info->lock); - hash_count = 0xffffffffull * (uint64_t)info->nonces; - avalon->results += info->nonces + info->idle; - if (avalon->results > miner_count) - avalon->results = miner_count; - if (!info->reset) - avalon->results--; - info->nonces = info->idle = 0; - mutex_unlock(&info->lock); - - /* Check for nothing but consecutive bad results or consistently less - * results than we should be getting and reset the FPGA if necessary */ - if (!is_bitburner(avalon)) { - if (avalon->results < -miner_count && !info->reset) { - applog(LOG_ERR, "%s%d: Result return rate low, resetting!", - avalon->drv->name, avalon->device_id); - info->reset = true; - } - } - - if (unlikely(avalon->usbinfo.nodev)) { - applog(LOG_ERR, "%s%d: Device disappeared, shutting down thread", - avalon->drv->name, avalon->device_id); - avalon->shutdown = true; - } - - /* This hashmeter is just a utility counter based on returned shares */ - return hash_count; -} - -static void avalon_flush_work(struct cgpu_info *avalon) -{ - struct avalon_info *info = avalon->device_data; - - mutex_lock(&info->qlock); - /* Will overwrite any work queued */ - avalon->queued = 0; - mutex_unlock(&info->qlock); - - /* Signal main loop we need more work */ - cgsem_post(&info->qsem); -} - -static struct api_data *avalon_api_stats(struct cgpu_info *cgpu) -{ - struct api_data *root = NULL; - struct avalon_info *info = cgpu->device_data; - char buf[64]; - int i; - double hwp = (cgpu->hw_errors + cgpu->diff1) ? - (double)(cgpu->hw_errors) / (double)(cgpu->hw_errors + cgpu->diff1) : 0; - - root = api_add_int(root, "baud", &(info->baud), false); - root = api_add_int(root, "miner_count", &(info->miner_count),false); - root = api_add_int(root, "asic_count", &(info->asic_count), false); - root = api_add_int(root, "timeout", &(info->timeout), false); - root = api_add_int(root, "frequency", &(info->frequency), false); - - root = api_add_int(root, "fan1", &(info->fan0), false); - root = api_add_int(root, "fan2", &(info->fan1), false); - root = api_add_int(root, "fan3", &(info->fan2), false); - - root = api_add_int(root, "temp1", &(info->temp0), false); - root = api_add_int(root, "temp2", &(info->temp1), false); - root = api_add_int(root, "temp3", &(info->temp2), false); - root = api_add_int(root, "temp_max", &(info->temp_max), false); - - root = api_add_percent(root, "Device Hardware%", &hwp, true); - root = api_add_int(root, "no_matching_work", &(info->no_matching_work), false); - for (i = 0; i < info->miner_count; i++) { - char mcw[24]; - - sprintf(mcw, "match_work_count%d", i + 1); - root = api_add_int(root, mcw, &(info->matching_work[i]), false); - } - if (is_bitburner(cgpu)) { - root = api_add_int(root, "core_voltage", &(info->core_voltage), false); - snprintf(buf, sizeof(buf), "%"PRIu8".%"PRIu8".%"PRIu8, - info->version1, info->version2, info->version3); - root = api_add_string(root, "version", buf, true); - } - root = api_add_uint32(root, "Controller Version", &(info->ctlr_ver), false); - - return root; -} - -static void avalon_shutdown(struct thr_info *thr) -{ - struct cgpu_info *avalon = thr->cgpu; - struct avalon_info *info = avalon->device_data; - - pthread_join(info->read_thr, NULL); - pthread_join(info->write_thr, NULL); - avalon_running_reset(avalon, info); - cgsem_destroy(&info->qsem); - mutex_destroy(&info->qlock); - mutex_destroy(&info->lock); - free(avalon->works); - avalon->works = NULL; -} - -static char *avalon_set_device(struct cgpu_info *avalon, char *option, char *setting, char *replybuf) -{ - int val; - - if (strcasecmp(option, "help") == 0) { - sprintf(replybuf, "freq: range %d-%d millivolts: range %d-%d", - AVALON_MIN_FREQUENCY, AVALON_MAX_FREQUENCY, - BITBURNER_MIN_COREMV, BITBURNER_MAX_COREMV); - return replybuf; - } - - if (strcasecmp(option, "millivolts") == 0 || strcasecmp(option, "mv") == 0) { - if (!is_bitburner(avalon)) { - sprintf(replybuf, "%s cannot set millivolts", avalon->drv->name); - return replybuf; - } - - if (!setting || !*setting) { - sprintf(replybuf, "missing millivolts setting"); - return replybuf; - } - - val = atoi(setting); - if (val < BITBURNER_MIN_COREMV || val > BITBURNER_MAX_COREMV) { - sprintf(replybuf, "invalid millivolts: '%s' valid range %d-%d", - setting, BITBURNER_MIN_COREMV, BITBURNER_MAX_COREMV); - return replybuf; - } - - if (bitburner_set_core_voltage(avalon, val)) - return NULL; - else { - sprintf(replybuf, "Set millivolts failed"); - return replybuf; - } - } - - if (strcasecmp(option, "freq") == 0) { - if (!setting || !*setting) { - sprintf(replybuf, "missing freq setting"); - return replybuf; - } - - val = atoi(setting); - if (val < AVALON_MIN_FREQUENCY || val > AVALON_MAX_FREQUENCY) { - sprintf(replybuf, "invalid freq: '%s' valid range %d-%d", - setting, AVALON_MIN_FREQUENCY, AVALON_MAX_FREQUENCY); - return replybuf; - } - - avalon_set_freq(avalon, val); - return NULL; - } - - sprintf(replybuf, "Unknown option: %s", option); - return replybuf; -} - -struct device_drv avalon_drv = { - .drv_id = DRIVER_avalon, - .dname = "avalon", - .name = "AVA", - .drv_detect = avalon_detect, - .thread_prepare = avalon_prepare, - .hash_work = hash_queued_work, - .queue_full = avalon_fill, - .scanwork = avalon_scanhash, - .flush_work = avalon_flush_work, - .get_api_stats = avalon_api_stats, - .get_statline_before = get_avalon_statline_before, - .set_device = avalon_set_device, - .reinit_device = avalon_init, - .thread_shutdown = avalon_shutdown, -}; diff --git a/driver-avalon.h b/driver-avalon.h deleted file mode 100644 index 05ad8491..00000000 --- a/driver-avalon.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright 2013 Avalon project - * Copyright 2013 Con Kolivas - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. See COPYING for more details. - */ - -#ifndef AVALON_H -#define AVALON_H - -#ifdef USE_AVALON - -#include "util.h" - -#define AVALON_RESET_FAULT_DECISECONDS 1 -#define AVALON_MINER_THREADS 1 - -#define AVALON_IO_SPEED 115200 -#define AVALON_HASH_TIME_FACTOR ((float)1.67/0x32) -#define AVALON_RESET_PITCH (300*1000*1000) - -#define AVALON_FAN_FACTOR 120 -#define AVALON_PWM_MAX 0xA0 -#define AVALON_DEFAULT_FAN_MIN 20 -#define AVALON_DEFAULT_FAN_MAX 100 -#define AVALON_DEFAULT_FAN_MAX_PWM 0xA0 /* 100% */ -#define AVALON_DEFAULT_FAN_MIN_PWM 0x20 /* 20% */ - -#define AVALON_TEMP_TARGET 50 -#define AVALON_TEMP_HYSTERESIS 3 -#define AVALON_TEMP_OVERHEAT 60 - -/* Avalon-based BitBurner. */ -#define BITBURNER_DEFAULT_CORE_VOLTAGE 1200 /* in millivolts */ -#define BITBURNER_MIN_COREMV 1000 -/* change here if you want to risk killing it :) */ -#define BITBURNER_MAX_COREMV 1400 - -/* BitFury-based BitBurner. */ -#define BITBURNER_FURY_DEFAULT_CORE_VOLTAGE 900 /* in millivolts */ -#define BITBURNER_FURY_MIN_COREMV 700 -/* change here if you want to risk killing it :) */ -#define BITBURNER_FURY_MAX_COREMV 1100 - - -#define AVALON_DEFAULT_TIMEOUT 0x2D -#define AVALON_MIN_FREQUENCY 256 -#define AVALON_MAX_FREQUENCY 1024 -#define AVALON_TIMEOUT_FACTOR 12690 -#define AVALON_DEFAULT_FREQUENCY 282 -#define AVALON_DEFAULT_MINER_NUM 0x20 -#define AVALON_MAX_MINER_NUM 0x100 -#define AVALON_DEFAULT_ASIC_NUM 0xA - -/* Default number of miners for Bitburner Fury is for a stack of 8 boards, - but it will work acceptably for smaller stacks, too */ -#define BITBURNER_FURY_DEFAULT_MINER_NUM 128 -#define BITBURNER_FURY_DEFAULT_FREQUENCY 256 -#define BITBURNER_FURY_DEFAULT_TIMEOUT 50 - -#define AVALON_AUTO_CYCLE 1024 - -#define AVALON_FTDI_READSIZE 510 -#define AVALON_READBUF_SIZE 8192 -#define AVALON_RESET_TIMEOUT 100 -#define AVALON_READ_TIMEOUT 18 /* Enough to only half fill the buffer */ -#define AVALON_LATENCY 1 - -struct avalon_task { - uint8_t reset :1; - uint8_t flush_fifo :1; - uint8_t fan_eft :1; - uint8_t timer_eft :1; - uint8_t asic_num :4; - uint8_t fan_pwm_data; - uint8_t timeout_data; - uint8_t miner_num; - - uint8_t nonce_elf :1; - uint8_t gate_miner_elf :1; - uint8_t asic_pll :1; - uint8_t gate_miner :1; - uint8_t _pad0 :4; - uint8_t _pad1[3]; - uint32_t _pad2; - - uint8_t midstate[32]; - uint8_t data[12]; -} __attribute__((packed, aligned(4))); - -struct avalon_result { - uint32_t nonce; - uint8_t data[12]; - uint8_t midstate[32]; - - uint8_t fan0; - uint8_t fan1; - uint8_t fan2; - uint8_t temp0; - uint8_t temp1; - uint8_t temp2; - uint8_t _pad0[2]; - - uint16_t fifo_wp; - uint16_t fifo_rp; - uint8_t chip_num; - uint8_t pwm_data; - uint8_t timeout; - uint8_t miner_num; -} __attribute__((packed, aligned(4))); - -struct avalon_info { - int baud; - int miner_count; - int asic_count; - int timeout; - - int fan0; - int fan1; - int fan2; - - int temp0; - int temp1; - int temp2; - int temp_max; - int temp_history_count; - int temp_history_index; - int temp_sum; - int temp_old; - int fan_pwm; - - int core_voltage; - - int no_matching_work; - int matching_work[AVALON_MAX_MINER_NUM]; - - int frequency; - uint32_t ctlr_ver; - - struct thr_info *thr; - pthread_t read_thr; - pthread_t write_thr; - pthread_mutex_t lock; - pthread_mutex_t qlock; - cgsem_t qsem; - int nonces; - - int auto_queued; - int auto_nonces; - int auto_hw; - - int idle; - bool reset; - bool overheat; - bool optimal; - - uint8_t version1; - uint8_t version2; - uint8_t version3; -}; - -#define BITBURNER_VERSION1 1 -#define BITBURNER_VERSION2 0 -#define BITBURNER_VERSION3 0 - -#define AVALON_WRITE_SIZE (sizeof(struct avalon_task)) -#define AVALON_READ_SIZE (sizeof(struct avalon_result)) -#define AVALON_ARRAY_SIZE 3 -#define BITBURNER_ARRAY_SIZE 4 - -#define AVA_GETS_ERROR -1 -#define AVA_GETS_OK 0 - -#define AVA_SEND_ERROR -1 -#define AVA_SEND_OK 0 - -#define avalon_buffer_full(avalon) !usb_ftdi_cts(avalon) - -#define AVALON_READ_TIME(baud) ((double)AVALON_READ_SIZE * (double)8.0 / (double)(baud)) -#define ASSERT1(condition) __maybe_unused static char sizeof_uint32_t_must_be_4[(condition)?1:-1] -ASSERT1(sizeof(uint32_t) == 4); - -extern struct avalon_info **avalon_info; -extern int opt_avalon_temp; -extern int opt_avalon_overheat; -extern int opt_avalon_fan_min; -extern int opt_avalon_fan_max; -extern int opt_avalon_freq_min; -extern int opt_avalon_freq_max; -extern bool opt_avalon_auto; -extern int opt_bitburner_core_voltage; -extern int opt_bitburner_fury_core_voltage; -extern char *set_avalon_fan(char *arg); -extern char *set_avalon_freq(char *arg); - -#endif /* USE_AVALON */ -#endif /* AVALON_H */ diff --git a/driver-bflsc.c b/driver-bflsc.c deleted file mode 100644 index f3e45c4f..00000000 --- a/driver-bflsc.c +++ /dev/null @@ -1,1948 +0,0 @@ -/* - * Copyright 2013 Andrew Smith - * Copyright 2013 Con Kolivas - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. See COPYING for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" - -#ifdef WIN32 -#include -#endif - -#include "compat.h" -#include "miner.h" -#include "usbutils.h" -#include "driver-bflsc.h" - -int opt_bflsc_overheat = BFLSC_TEMP_OVERHEAT; - -static const char *blank = ""; - -static enum driver_version drv_ver(struct cgpu_info *bflsc, const char *ver) -{ - char *tmp; - - if (strstr(ver, "1.0.0")) - return BFLSC_DRV1; - - if (strstr(ver, "1.0.") || strstr(ver, "1.1.")) { - applog(LOG_WARNING, "%s detect (%s) Warning assuming firmware '%s' is Ver1", - bflsc->drv->dname, bflsc->device_path, ver); - return BFLSC_DRV1; - } - - if (strstr(ver, "1.2.")) - return BFLSC_DRV2; - - tmp = str_text((char *)ver); - applog(LOG_WARNING, "%s detect (%s) Warning unknown firmware '%s' using Ver2", - bflsc->drv->dname, bflsc->device_path, tmp); - free(tmp); - return BFLSC_DRV2; -} - -static void xlinkstr(char *xlink, size_t siz, int dev, struct bflsc_info *sc_info) -{ - if (dev > 0) - snprintf(xlink, siz, " x-%d", dev); - else { - if (sc_info->sc_count > 1) - strcpy(xlink, " master"); - else - *xlink = '\0'; - } -} - -static void bflsc_applog(struct cgpu_info *bflsc, int dev, enum usb_cmds cmd, int amount, int err) -{ - struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); - char xlink[17]; - - xlinkstr(xlink, sizeof(xlink), dev, sc_info); - - usb_applog(bflsc, cmd, xlink, amount, err); -} - -// Break an input up into lines with LFs removed -// false means an error, but if *lines > 0 then data was also found -// error would be no data or missing LF at the end -static bool tolines(struct cgpu_info *bflsc, int dev, char *buf, int *lines, char ***items, enum usb_cmds cmd) -{ - bool ok = false; - char *ptr; - -#define p_lines (*lines) -#define p_items (*items) - - p_lines = 0; - p_items = NULL; - - if (!buf || !(*buf)) { - applog(LOG_DEBUG, "USB: %s%i: (%d) empty %s", - bflsc->drv->name, bflsc->device_id, dev, usb_cmdname(cmd)); - return ok; - } - - ptr = strdup(buf); - while (ptr && *ptr) { - p_items = realloc(p_items, ++p_lines * sizeof(*p_items)); - if (unlikely(!p_items)) - quit(1, "Failed to realloc p_items in tolines"); - p_items[p_lines-1] = ptr; - ptr = strchr(ptr, '\n'); - if (ptr) - *(ptr++) = '\0'; - else { - applog(LOG_DEBUG, "USB: %s%i: (%d) missing lf(s) in %s", - bflsc->drv->name, bflsc->device_id, dev, usb_cmdname(cmd)); - return ok; - } - } - ok = true; - - return ok; -} - -static void freetolines(int *lines, char ***items) -{ - if (*lines > 0) { - free(**items); - free(*items); - } - *lines = 0; - *items = NULL; -} - -enum breakmode { - NOCOLON, - ONECOLON, - ALLCOLON // Temperature uses this -}; - -// Break down a single line into 'fields' -// 'lf' will be a pointer to the final LF if it is there (or NULL) -// firstname will be the allocated buf copy pointer which is also -// the string before ':' for ONECOLON and ALLCOLON -// If any string is missing the ':' when it was expected, false is returned -static bool breakdown(enum breakmode mode, char *buf, int *count, char **firstname, char ***fields, char **lf) -{ - char *ptr, *colon, *comma; - bool ok = false; - -#define p_count (*count) -#define p_firstname (*firstname) -#define p_fields (*fields) -#define p_lf (*lf) - - p_count = 0; - p_firstname = NULL; - p_fields = NULL; - p_lf = NULL; - - if (!buf || !(*buf)) - return ok; - - ptr = p_firstname = strdup(buf); - p_lf = strchr(p_firstname, '\n'); - if (mode == ONECOLON) { - colon = strchr(ptr, ':'); - if (colon) { - ptr = colon; - *(ptr++) = '\0'; - } else - return ok; - } - - while (ptr && *ptr) { - if (mode == ALLCOLON) { - colon = strchr(ptr, ':'); - if (colon) - ptr = colon + 1; - else - return ok; - } - comma = strchr(ptr, ','); - if (comma) - *(comma++) = '\0'; - p_fields = realloc(p_fields, ++p_count * sizeof(*p_fields)); - if (unlikely(!p_fields)) - quit(1, "Failed to realloc p_fields in breakdown"); - p_fields[p_count-1] = ptr; - ptr = comma; - } - - ok = true; - return ok; -} - -static void freebreakdown(int *count, char **firstname, char ***fields) -{ - if (*firstname) - free(*firstname); - if (*count > 0) - free(*fields); - *count = 0; - *firstname = NULL; - *fields = NULL; -} - -static bool isokerr(int err, char *buf, int amount) -{ - if (err < 0 || amount < (int)BFLSC_OK_LEN) - return false; - else { - if (strstr(buf, BFLSC_ANERR)) - return false; - else - return true; - } -} - -// send+receive dual stage - always single line replies -static int send_recv_ds(struct cgpu_info *bflsc, int dev, int *stage, bool *sent, int *amount, char *send1, int send1_len, enum usb_cmds send1_cmd, enum usb_cmds recv1_cmd, char *send2, int send2_len, enum usb_cmds send2_cmd, enum usb_cmds recv2_cmd, char *recv, int recv_siz) -{ - struct DataForwardToChain data; - int len, err, tried; - - if (dev == 0) { - usb_buffer_clear(bflsc); - - *stage = 1; - *sent = false; - err = usb_write(bflsc, send1, send1_len, amount, send1_cmd); - if (err < 0 || *amount < send1_len) - return err; - - *sent = true; - err = usb_read_nl(bflsc, recv, recv_siz, amount, recv1_cmd); - if (!isokerr(err, recv, *amount)) - return err; - - usb_buffer_clear(bflsc); - - *stage = 2; - *sent = false; - err = usb_write(bflsc, send2, send2_len, amount, send2_cmd); - if (err < 0 || *amount < send2_len) - return err; - - *sent = true; - err = usb_read_nl(bflsc, recv, recv_siz, amount, recv2_cmd); - - return err; - } - - data.header = BFLSC_XLINKHDR; - data.deviceAddress = (uint8_t)dev; - tried = 0; - while (tried++ < 3) { - data.payloadSize = send1_len; - memcpy(data.payloadData, send1, send1_len); - len = DATAFORWARDSIZE(data); - - usb_buffer_clear(bflsc); - - *stage = 1; - *sent = false; - err = usb_write(bflsc, (char *)&data, len, amount, send1_cmd); - if (err < 0 || *amount < send1_len) - return err; - - *sent = true; - err = usb_read_nl(bflsc, recv, recv_siz, amount, recv1_cmd); - - if (err != LIBUSB_SUCCESS) - return err; - - // x-link timeout? - try again? - if (strstr(recv, BFLSC_XTIMEOUT)) - continue; - - if (!isokerr(err, recv, *amount)) - return err; - - data.payloadSize = send2_len; - memcpy(data.payloadData, send2, send2_len); - len = DATAFORWARDSIZE(data); - - usb_buffer_clear(bflsc); - - *stage = 2; - *sent = false; - err = usb_write(bflsc, (char *)&data, len, amount, send2_cmd); - if (err < 0 || *amount < send2_len) - return err; - - *sent = true; - err = usb_read_nl(bflsc, recv, recv_siz, amount, recv2_cmd); - - if (err != LIBUSB_SUCCESS) - return err; - - // x-link timeout? - try again? - if (strstr(recv, BFLSC_XTIMEOUT)) - continue; - - // SUCCESS - return it - break; - } - return err; -} - -#define READ_OK true -#define READ_NL false - -// send+receive single stage -static int send_recv_ss(struct cgpu_info *bflsc, int dev, bool *sent, int *amount, char *send, int send_len, enum usb_cmds send_cmd, char *recv, int recv_siz, enum usb_cmds recv_cmd, bool read_ok) -{ - struct DataForwardToChain data; - int len, err, tried; - - if (dev == 0) { - usb_buffer_clear(bflsc); - - *sent = false; - err = usb_write(bflsc, send, send_len, amount, send_cmd); - if (err < 0 || *amount < send_len) { - // N.B. thus !(*sent) directly implies err < 0 or *amount < send_len - return err; - } - - *sent = true; - if (read_ok == READ_OK) - err = usb_read_ok(bflsc, recv, recv_siz, amount, recv_cmd); - else - err = usb_read_nl(bflsc, recv, recv_siz, amount, recv_cmd); - - return err; - } - - data.header = BFLSC_XLINKHDR; - data.deviceAddress = (uint8_t)dev; - data.payloadSize = send_len; - memcpy(data.payloadData, send, send_len); - len = DATAFORWARDSIZE(data); - - tried = 0; - while (tried++ < 3) { - usb_buffer_clear(bflsc); - - *sent = false; - err = usb_write(bflsc, (char *)&data, len, amount, recv_cmd); - if (err < 0 || *amount < send_len) - return err; - - *sent = true; - if (read_ok == READ_OK) - err = usb_read_ok(bflsc, recv, recv_siz, amount, recv_cmd); - else - err = usb_read_nl(bflsc, recv, recv_siz, amount, recv_cmd); - - if (err != LIBUSB_SUCCESS && err != LIBUSB_ERROR_TIMEOUT) - return err; - - // read_ok can err timeout if it's looking for OK - // TODO: add a usb_read() option to spot the ERR: and convert end=OK to just - // x-link timeout? - try again? - if ((err == LIBUSB_SUCCESS || (read_ok == READ_OK && err == LIBUSB_ERROR_TIMEOUT)) && - strstr(recv, BFLSC_XTIMEOUT)) - continue; - - // SUCCESS or TIMEOUT - return it - break; - } - return err; -} - -static int write_to_dev(struct cgpu_info *bflsc, int dev, char *buf, int buflen, int *amount, enum usb_cmds cmd) -{ - struct DataForwardToChain data; - int len; - - /* - * The protocol is syncronous so any previous excess can be - * discarded and assumed corrupt data or failed USB transfers - */ - usb_buffer_clear(bflsc); - - if (dev == 0) - return usb_write(bflsc, buf, buflen, amount, cmd); - - data.header = BFLSC_XLINKHDR; - data.deviceAddress = (uint8_t)dev; - data.payloadSize = buflen; - memcpy(data.payloadData, buf, buflen); - len = DATAFORWARDSIZE(data); - - return usb_write(bflsc, (char *)&data, len, amount, cmd); -} - -static void bflsc_send_flush_work(struct cgpu_info *bflsc, int dev) -{ - char buf[BFLSC_BUFSIZ+1]; - int err, amount; - bool sent; - - // Device is gone - if (bflsc->usbinfo.nodev) - return; - - mutex_lock(&bflsc->device_mutex); - err = send_recv_ss(bflsc, dev, &sent, &amount, - BFLSC_QFLUSH, BFLSC_QFLUSH_LEN, C_QUEFLUSH, - buf, sizeof(buf)-1, C_QUEFLUSHREPLY, READ_NL); - mutex_unlock(&bflsc->device_mutex); - - if (!sent) - bflsc_applog(bflsc, dev, C_QUEFLUSH, amount, err); - else { - // TODO: do we care if we don't get 'OK'? (always will in normal processing) - } -} - -/* return True = attempted usb_read_ok() - * set ignore to true means no applog/ignore errors */ -static bool bflsc_qres(struct cgpu_info *bflsc, char *buf, size_t bufsiz, int dev, int *err, int *amount, bool ignore) -{ - bool readok = false; - - mutex_lock(&(bflsc->device_mutex)); - *err = send_recv_ss(bflsc, dev, &readok, amount, - BFLSC_QRES, BFLSC_QRES_LEN, C_REQUESTRESULTS, - buf, bufsiz-1, C_GETRESULTS, READ_OK); - mutex_unlock(&(bflsc->device_mutex)); - - if (!readok) { - if (!ignore) - bflsc_applog(bflsc, dev, C_REQUESTRESULTS, *amount, *err); - - // TODO: do what? flag as dead device? - // count how many times it has happened and reset/fail it - // or even make sure it is all x-link and that means device - // has failed after some limit of this? - // of course all other I/O must also be failing ... - } else { - if (*err < 0 || *amount < 1) { - if (!ignore) - bflsc_applog(bflsc, dev, C_GETRESULTS, *amount, *err); - - // TODO: do what? ... see above - } - } - - return readok; -} - -static void __bflsc_initialise(struct cgpu_info *bflsc) -{ - int err, interface; - -// TODO: does x-link bypass the other device FTDI? (I think it does) -// So no initialisation required except for the master device? - - if (bflsc->usbinfo.nodev) - return; - - interface = usb_interface(bflsc); - // Reset - err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, - FTDI_VALUE_RESET, interface, C_RESET); - - applog(LOG_DEBUG, "%s%i: reset got err %d", - bflsc->drv->name, bflsc->device_id, err); - - if (bflsc->usbinfo.nodev) - return; - - usb_ftdi_set_latency(bflsc); - - if (bflsc->usbinfo.nodev) - return; - - // Set data control - err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_DATA, - FTDI_VALUE_DATA_BAS, interface, C_SETDATA); - - applog(LOG_DEBUG, "%s%i: setdata got err %d", - bflsc->drv->name, bflsc->device_id, err); - - if (bflsc->usbinfo.nodev) - return; - - // Set the baud - err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, FTDI_VALUE_BAUD_BAS, - (FTDI_INDEX_BAUD_BAS & 0xff00) | interface, - C_SETBAUD); - - applog(LOG_DEBUG, "%s%i: setbaud got err %d", - bflsc->drv->name, bflsc->device_id, err); - - if (bflsc->usbinfo.nodev) - return; - - // Set Flow Control - err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_FLOW, - FTDI_VALUE_FLOW, interface, C_SETFLOW); - - applog(LOG_DEBUG, "%s%i: setflowctrl got err %d", - bflsc->drv->name, bflsc->device_id, err); - - if (bflsc->usbinfo.nodev) - return; - - // Set Modem Control - err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_MODEM, - FTDI_VALUE_MODEM, interface, C_SETMODEM); - - applog(LOG_DEBUG, "%s%i: setmodemctrl got err %d", - bflsc->drv->name, bflsc->device_id, err); - - if (bflsc->usbinfo.nodev) - return; - - // Clear any sent data - err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, - FTDI_VALUE_PURGE_TX, interface, C_PURGETX); - - applog(LOG_DEBUG, "%s%i: purgetx got err %d", - bflsc->drv->name, bflsc->device_id, err); - - if (bflsc->usbinfo.nodev) - return; - - // Clear any received data - err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, - FTDI_VALUE_PURGE_RX, interface, C_PURGERX); - - applog(LOG_DEBUG, "%s%i: purgerx got err %d", - bflsc->drv->name, bflsc->device_id, err); - - if (!bflsc->cutofftemp) - bflsc->cutofftemp = opt_bflsc_overheat; -} - -static void bflsc_initialise(struct cgpu_info *bflsc) -{ - struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); - char buf[BFLSC_BUFSIZ+1]; - int err, amount; - int dev; - - mutex_lock(&(bflsc->device_mutex)); - __bflsc_initialise(bflsc); - mutex_unlock(&(bflsc->device_mutex)); - - for (dev = 0; dev < sc_info->sc_count; dev++) { - bflsc_send_flush_work(bflsc, dev); - bflsc_qres(bflsc, buf, sizeof(buf), dev, &err, &amount, true); - } -} - -static bool getinfo(struct cgpu_info *bflsc, int dev) -{ - struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); - struct bflsc_dev sc_dev; - char buf[BFLSC_BUFSIZ+1]; - int err, amount; - char **items, *firstname, **fields, *lf; - bool res, ok = false; - int i, lines, count; - char *tmp; - - /* - * Kano's first dev Jalapeno output: - * DEVICE: BitFORCE SC - * FIRMWARE: 1.0.0 - * ENGINES: 30 - * FREQUENCY: [UNKNOWN] - * XLINK MODE: MASTER - * XLINK PRESENT: YES - * --DEVICES IN CHAIN: 0 - * --CHAIN PRESENCE MASK: 00000000 - * OK - */ - - /* - * Don't use send_recv_ss() since we have a different receive timeout - * Also getinfo() is called multiple times if it fails anyway - */ - err = write_to_dev(bflsc, dev, BFLSC_DETAILS, BFLSC_DETAILS_LEN, &amount, C_REQUESTDETAILS); - if (err < 0 || amount != BFLSC_DETAILS_LEN) { - applog(LOG_ERR, "%s detect (%s) send details request failed (%d:%d)", - bflsc->drv->dname, bflsc->device_path, amount, err); - return ok; - } - - err = usb_read_ok_timeout(bflsc, buf, sizeof(buf)-1, &amount, - BFLSC_INFO_TIMEOUT, C_GETDETAILS); - if (err < 0 || amount < 1) { - if (err < 0) { - applog(LOG_ERR, "%s detect (%s) get details return invalid/timed out (%d:%d)", - bflsc->drv->dname, bflsc->device_path, amount, err); - } else { - applog(LOG_ERR, "%s detect (%s) get details returned nothing (%d:%d)", - bflsc->drv->dname, bflsc->device_path, amount, err); - } - return ok; - } - - memset(&sc_dev, 0, sizeof(struct bflsc_dev)); - sc_info->sc_count = 1; - res = tolines(bflsc, dev, &(buf[0]), &lines, &items, C_GETDETAILS); - if (!res) - return ok; - - tmp = str_text(buf); - strncpy(sc_dev.getinfo, tmp, sizeof(sc_dev.getinfo)); - sc_dev.getinfo[sizeof(sc_dev.getinfo)-1] = '\0'; - free(tmp); - - for (i = 0; i < lines-2; i++) { - res = breakdown(ONECOLON, items[i], &count, &firstname, &fields, &lf); - if (lf) - *lf = '\0'; - if (!res || count != 1) { - tmp = str_text(items[i]); - applogsiz(LOG_WARNING, BFLSC_APPLOGSIZ, - "%s detect (%s) invalid details line: '%s' %d", - bflsc->drv->dname, bflsc->device_path, tmp, count); - free(tmp); - dev_error(bflsc, REASON_DEV_COMMS_ERROR); - goto mata; - } - if (strstr(firstname, BFLSC_DI_FIRMWARE)) { - sc_dev.firmware = strdup(fields[0]); - sc_info->driver_version = drv_ver(bflsc, sc_dev.firmware); - } - else if (strstr(firstname, BFLSC_DI_ENGINES)) { - sc_dev.engines = atoi(fields[0]); - if (sc_dev.engines < 1) { - tmp = str_text(items[i]); - applogsiz(LOG_WARNING, BFLSC_APPLOGSIZ, - "%s detect (%s) invalid engine count: '%s'", - bflsc->drv->dname, bflsc->device_path, tmp); - free(tmp); - goto mata; - } - } - else if (strstr(firstname, BFLSC_DI_XLINKMODE)) - sc_dev.xlink_mode = strdup(fields[0]); - else if (strstr(firstname, BFLSC_DI_XLINKPRESENT)) - sc_dev.xlink_present = strdup(fields[0]); - else if (strstr(firstname, BFLSC_DI_DEVICESINCHAIN)) { - if (fields[0][0] == '0' || - (fields[0][0] == ' ' && fields[0][1] == '0')) - sc_info->sc_count = 1; - else - sc_info->sc_count = atoi(fields[0]); - if (sc_info->sc_count < 1 || sc_info->sc_count > 30) { - tmp = str_text(items[i]); - applogsiz(LOG_WARNING, BFLSC_APPLOGSIZ, - "%s detect (%s) invalid x-link count: '%s'", - bflsc->drv->dname, bflsc->device_path, tmp); - free(tmp); - goto mata; - } - } - else if (strstr(firstname, BFLSC_DI_CHIPS)) - sc_dev.chips = strdup(fields[0]); - - freebreakdown(&count, &firstname, &fields); - } - - if (sc_info->driver_version == BFLSC_DRVUNDEF) { - applog(LOG_WARNING, "%s detect (%s) missing %s", - bflsc->drv->dname, bflsc->device_path, BFLSC_DI_FIRMWARE); - goto ne; - } - - sc_info->sc_devs = calloc(sc_info->sc_count, sizeof(struct bflsc_dev)); - if (unlikely(!sc_info->sc_devs)) - quit(1, "Failed to calloc in getinfo"); - memcpy(&(sc_info->sc_devs[0]), &sc_dev, sizeof(sc_dev)); - // TODO: do we care about getting this info for the rest if > 0 x-link - - ok = true; - goto ne; - -mata: - freebreakdown(&count, &firstname, &fields); - ok = false; -ne: - freetolines(&lines, &items); - return ok; -} - -static bool bflsc_detect_one(struct libusb_device *dev, struct usb_find_devices *found) -{ - struct bflsc_info *sc_info = NULL; - char buf[BFLSC_BUFSIZ+1]; - int i, err, amount; - struct timeval init_start, init_now; - int init_sleep, init_count; - bool ident_first, sent; - char *newname; - uint16_t latency; - - struct cgpu_info *bflsc = usb_alloc_cgpu(&bflsc_drv, 1); - - sc_info = calloc(1, sizeof(*sc_info)); - if (unlikely(!sc_info)) - quit(1, "Failed to calloc sc_info in bflsc_detect_one"); - // TODO: fix ... everywhere ... - bflsc->device_data = (FILE *)sc_info; - - if (!usb_init(bflsc, dev, found)) - goto shin; - - // Allow 2 complete attempts if the 1st time returns an unrecognised reply - ident_first = true; -retry: - init_count = 0; - init_sleep = REINIT_TIME_FIRST_MS; - cgtime(&init_start); -reinit: - __bflsc_initialise(bflsc); - - err = send_recv_ss(bflsc, 0, &sent, &amount, - BFLSC_IDENTIFY, BFLSC_IDENTIFY_LEN, C_REQUESTIDENTIFY, - buf, sizeof(buf)-1, C_GETIDENTIFY, READ_NL); - - if (!sent) { - applog(LOG_ERR, "%s detect (%s) send identify request failed (%d:%d)", - bflsc->drv->dname, bflsc->device_path, amount, err); - goto unshin; - } - - if (err < 0 || amount < 1) { - init_count++; - cgtime(&init_now); - if (us_tdiff(&init_now, &init_start) <= REINIT_TIME_MAX) { - if (init_count == 2) { - applog(LOG_WARNING, "%s detect (%s) 2nd init failed (%d:%d) - retrying", - bflsc->drv->dname, bflsc->device_path, amount, err); - } - cgsleep_ms(init_sleep); - if ((init_sleep * 2) <= REINIT_TIME_MAX_MS) - init_sleep *= 2; - goto reinit; - } - - if (init_count > 0) - applog(LOG_WARNING, "%s detect (%s) init failed %d times %.2fs", - bflsc->drv->dname, bflsc->device_path, init_count, tdiff(&init_now, &init_start)); - - if (err < 0) { - applog(LOG_ERR, "%s detect (%s) error identify reply (%d:%d)", - bflsc->drv->dname, bflsc->device_path, amount, err); - } else { - applog(LOG_ERR, "%s detect (%s) empty identify reply (%d)", - bflsc->drv->dname, bflsc->device_path, amount); - } - - goto unshin; - } - buf[amount] = '\0'; - - if (unlikely(!strstr(buf, BFLSC_BFLSC))) { - applog(LOG_DEBUG, "%s detect (%s) found an FPGA '%s' ignoring", - bflsc->drv->dname, bflsc->device_path, buf); - goto unshin; - } - - if (unlikely(strstr(buf, BFLSC_IDENTITY))) { - if (ident_first) { - applog(LOG_DEBUG, "%s detect (%s) didn't recognise '%s' trying again ...", - bflsc->drv->dname, bflsc->device_path, buf); - ident_first = false; - goto retry; - } - applog(LOG_DEBUG, "%s detect (%s) didn't recognise '%s' on 2nd attempt", - bflsc->drv->dname, bflsc->device_path, buf); - goto unshin; - } - - int tries = 0; - while (7734) { - if (getinfo(bflsc, 0)) - break; - - // N.B. we will get displayed errors each time it fails - if (++tries > 2) - goto unshin; - - cgsleep_ms(40); - } - - switch (sc_info->driver_version) { - case BFLSC_DRV1: - sc_info->que_size = BFLSC_QUE_SIZE_V1; - sc_info->que_full_enough = BFLSC_QUE_FULL_ENOUGH_V1; - sc_info->que_watermark = BFLSC_QUE_WATERMARK_V1; - sc_info->que_low = BFLSC_QUE_LOW_V1; - sc_info->que_noncecount = QUE_NONCECOUNT_V1; - sc_info->que_fld_min = QUE_FLD_MIN_V1; - sc_info->que_fld_max = QUE_FLD_MAX_V1; - // Only Jalapeno uses 1.0.0 - sc_info->flush_size = 1; - break; - case BFLSC_DRV2: - case BFLSC_DRVUNDEF: - default: - sc_info->driver_version = BFLSC_DRV2; - - sc_info->que_size = BFLSC_QUE_SIZE_V2; - sc_info->que_full_enough = BFLSC_QUE_FULL_ENOUGH_V2; - sc_info->que_watermark = BFLSC_QUE_WATERMARK_V2; - sc_info->que_low = BFLSC_QUE_LOW_V2; - sc_info->que_noncecount = QUE_NONCECOUNT_V2; - sc_info->que_fld_min = QUE_FLD_MIN_V2; - sc_info->que_fld_max = QUE_FLD_MAX_V2; - // TODO: this can be reduced to total chip count - sc_info->flush_size = 16 * sc_info->sc_count; - break; - } - - // Set parallelization based on the getinfo() response if it is present - if (sc_info->sc_devs[0].chips && strlen(sc_info->sc_devs[0].chips)) { - if (strstr(sc_info->sc_devs[0].chips, BFLSC_DI_CHIPS_PARALLEL)) { - sc_info->que_noncecount = QUE_NONCECOUNT_V2; - sc_info->que_fld_min = QUE_FLD_MIN_V2; - sc_info->que_fld_max = QUE_FLD_MAX_V2; - } else { - sc_info->que_noncecount = QUE_NONCECOUNT_V1; - sc_info->que_fld_min = QUE_FLD_MIN_V1; - sc_info->que_fld_max = QUE_FLD_MAX_V1; - } - } - - sc_info->scan_sleep_time = BAS_SCAN_TIME; - sc_info->results_sleep_time = BFLSC_RES_TIME; - sc_info->default_ms_work = BAS_WORK_TIME; - latency = BAS_LATENCY; - - /* When getinfo() "FREQUENCY: [UNKNOWN]" is fixed - - * use 'freq * engines' to estimate. - * Otherwise for now: */ - newname = NULL; - if (sc_info->sc_count > 1) { - newname = BFLSC_MINIRIG; - sc_info->scan_sleep_time = BAM_SCAN_TIME; - sc_info->default_ms_work = BAM_WORK_TIME; - bflsc->usbdev->ident = IDENT_BAM; - latency = BAM_LATENCY; - } else { - if (sc_info->sc_devs[0].engines < 34) { // 16 * 2 + 2 - newname = BFLSC_JALAPENO; - sc_info->scan_sleep_time = BAJ_SCAN_TIME; - sc_info->default_ms_work = BAJ_WORK_TIME; - bflsc->usbdev->ident = IDENT_BAJ; - latency = BAJ_LATENCY; - } else if (sc_info->sc_devs[0].engines < 130) { // 16 * 8 + 2 - newname = BFLSC_LITTLESINGLE; - sc_info->scan_sleep_time = BAL_SCAN_TIME; - sc_info->default_ms_work = BAL_WORK_TIME; - bflsc->usbdev->ident = IDENT_BAL; - latency = BAL_LATENCY; - } - } - - if (latency != bflsc->usbdev->found->latency) { - bflsc->usbdev->found->latency = latency; - usb_ftdi_set_latency(bflsc); - } - - for (i = 0; i < sc_info->sc_count; i++) - sc_info->sc_devs[i].ms_work = sc_info->default_ms_work; - - if (newname) { - if (!bflsc->drv->copy) - bflsc->drv = copy_drv(bflsc->drv); - bflsc->drv->name = newname; - } - - // We have a real BFLSC! - applog(LOG_DEBUG, "%s (%s) identified as: '%s'", - bflsc->drv->dname, bflsc->device_path, bflsc->drv->name); - - if (!add_cgpu(bflsc)) - goto unshin; - - update_usb_stats(bflsc); - - mutex_init(&bflsc->device_mutex); - rwlock_init(&sc_info->stat_lock); - - return true; - -unshin: - - usb_uninit(bflsc); - -shin: - - free(bflsc->device_data); - bflsc->device_data = NULL; - - if (bflsc->name != blank) { - free(bflsc->name); - bflsc->name = NULL; - } - - bflsc = usb_free_cgpu(bflsc); - - return false; -} - -static void bflsc_detect(bool __maybe_unused hotplug) -{ - usb_detect(&bflsc_drv, bflsc_detect_one); -} - -static void get_bflsc_statline_before(char *buf, size_t bufsiz, struct cgpu_info *bflsc) -{ - struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); - float temp = 0; - float vcc1 = 0; - int i; - - rd_lock(&(sc_info->stat_lock)); - for (i = 0; i < sc_info->sc_count; i++) { - if (sc_info->sc_devs[i].temp1 > temp) - temp = sc_info->sc_devs[i].temp1; - if (sc_info->sc_devs[i].temp2 > temp) - temp = sc_info->sc_devs[i].temp2; - if (sc_info->sc_devs[i].vcc1 > vcc1) - vcc1 = sc_info->sc_devs[i].vcc1; - } - rd_unlock(&(sc_info->stat_lock)); - - tailsprintf(buf, bufsiz, " max%3.0fC %4.2fV | ", temp, vcc1); -} - -static void flush_one_dev(struct cgpu_info *bflsc, int dev) -{ - struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); - struct work *work, *tmp; - bool did = false; - - bflsc_send_flush_work(bflsc, dev); - - rd_lock(&bflsc->qlock); - - HASH_ITER(hh, bflsc->queued_work, work, tmp) { - if (work->subid == dev) { - // devflag is used to flag stale work - work->devflag = true; - did = true; - } - } - - rd_unlock(&bflsc->qlock); - - if (did) { - wr_lock(&(sc_info->stat_lock)); - sc_info->sc_devs[dev].flushed = true; - sc_info->sc_devs[dev].flush_id = sc_info->sc_devs[dev].result_id; - sc_info->sc_devs[dev].work_queued = 0; - wr_unlock(&(sc_info->stat_lock)); - } -} - -static void bflsc_flush_work(struct cgpu_info *bflsc) -{ - struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); - int dev; - - for (dev = 0; dev < sc_info->sc_count; dev++) - flush_one_dev(bflsc, dev); -} - -static void bflsc_flash_led(struct cgpu_info *bflsc, int dev) -{ - struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); - char buf[BFLSC_BUFSIZ+1]; - int err, amount; - bool sent; - - // Device is gone - if (bflsc->usbinfo.nodev) - return; - - // It is not critical flashing the led so don't get stuck if we - // can't grab the mutex now - if (mutex_trylock(&bflsc->device_mutex)) - return; - - err = send_recv_ss(bflsc, dev, &sent, &amount, - BFLSC_FLASH, BFLSC_FLASH_LEN, C_REQUESTFLASH, - buf, sizeof(buf)-1, C_FLASHREPLY, READ_NL); - mutex_unlock(&(bflsc->device_mutex)); - - if (!sent) - bflsc_applog(bflsc, dev, C_REQUESTFLASH, amount, err); - else { - // Don't care - } - - // Once we've tried - don't do it until told to again - // - even if it failed - sc_info->flash_led = false; - - return; -} - -static bool bflsc_get_temp(struct cgpu_info *bflsc, int dev) -{ - struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); - struct bflsc_dev *sc_dev; - char temp_buf[BFLSC_BUFSIZ+1]; - char volt_buf[BFLSC_BUFSIZ+1]; - char *tmp; - int err, amount; - char *firstname, **fields, *lf; - char xlink[17]; - int count; - bool res, sent; - float temp, temp1, temp2; - float vcc1, vcc2, vmain; - - // Device is gone - if (bflsc->usbinfo.nodev) - return false; - - if (dev >= sc_info->sc_count) { - applog(LOG_ERR, "%s%i: temp invalid xlink device %d - limit %d", - bflsc->drv->name, bflsc->device_id, dev, sc_info->sc_count - 1); - return false; - } - - // Flash instead of Temp - if (sc_info->flash_led) { - bflsc_flash_led(bflsc, dev); - return true; - } - - xlinkstr(xlink, sizeof(xlink), dev, sc_info); - - /* It is not very critical getting temp so don't get stuck if we - * can't grab the mutex here */ - if (mutex_trylock(&bflsc->device_mutex)) - return false; - - err = send_recv_ss(bflsc, dev, &sent, &amount, - BFLSC_TEMPERATURE, BFLSC_TEMPERATURE_LEN, C_REQUESTTEMPERATURE, - temp_buf, sizeof(temp_buf)-1, C_GETTEMPERATURE, READ_NL); - mutex_unlock(&(bflsc->device_mutex)); - - if (!sent) { - applog(LOG_ERR, "%s%i: Error: Request%s temp invalid/timed out (%d:%d)", - bflsc->drv->name, bflsc->device_id, xlink, amount, err); - return false; - } else { - if (err < 0 || amount < 1) { - if (err < 0) { - applog(LOG_ERR, "%s%i: Error: Get%s temp return invalid/timed out (%d:%d)", - bflsc->drv->name, bflsc->device_id, xlink, amount, err); - } else { - applog(LOG_ERR, "%s%i: Error: Get%s temp returned nothing (%d:%d)", - bflsc->drv->name, bflsc->device_id, xlink, amount, err); - } - return false; - } - } - - // Ignore it if we can't get the V - if (mutex_trylock(&bflsc->device_mutex)) - return false; - - err = send_recv_ss(bflsc, dev, &sent, &amount, - BFLSC_VOLTAGE, BFLSC_VOLTAGE_LEN, C_REQUESTVOLTS, - volt_buf, sizeof(volt_buf)-1, C_GETVOLTS, READ_NL); - mutex_unlock(&(bflsc->device_mutex)); - - if (!sent) { - applog(LOG_ERR, "%s%i: Error: Request%s volts invalid/timed out (%d:%d)", - bflsc->drv->name, bflsc->device_id, xlink, amount, err); - return false; - } else { - if (err < 0 || amount < 1) { - if (err < 0) { - applog(LOG_ERR, "%s%i: Error: Get%s volt return invalid/timed out (%d:%d)", - bflsc->drv->name, bflsc->device_id, xlink, amount, err); - } else { - applog(LOG_ERR, "%s%i: Error: Get%s volt returned nothing (%d:%d)", - bflsc->drv->name, bflsc->device_id, xlink, amount, err); - } - return false; - } - } - - res = breakdown(ALLCOLON, temp_buf, &count, &firstname, &fields, &lf); - if (lf) - *lf = '\0'; - if (!res || count != 2 || !lf) { - tmp = str_text(temp_buf); - applog(LOG_WARNING, "%s%i: Invalid%s temp reply: '%s'", - bflsc->drv->name, bflsc->device_id, xlink, tmp); - free(tmp); - freebreakdown(&count, &firstname, &fields); - dev_error(bflsc, REASON_DEV_COMMS_ERROR); - return false; - } - - temp = temp1 = (float)atoi(fields[0]); - temp2 = (float)atoi(fields[1]); - - freebreakdown(&count, &firstname, &fields); - - res = breakdown(NOCOLON, volt_buf, &count, &firstname, &fields, &lf); - if (lf) - *lf = '\0'; - if (!res || count != 3 || !lf) { - tmp = str_text(volt_buf); - applog(LOG_WARNING, "%s%i: Invalid%s volt reply: '%s'", - bflsc->drv->name, bflsc->device_id, xlink, tmp); - free(tmp); - freebreakdown(&count, &firstname, &fields); - dev_error(bflsc, REASON_DEV_COMMS_ERROR); - return false; - } - - sc_dev = &sc_info->sc_devs[dev]; - vcc1 = (float)atoi(fields[0]) / 1000.0; - vcc2 = (float)atoi(fields[1]) / 1000.0; - vmain = (float)atoi(fields[2]) / 1000.0; - - freebreakdown(&count, &firstname, &fields); - - if (vcc1 > 0 || vcc2 > 0 || vmain > 0) { - wr_lock(&(sc_info->stat_lock)); - if (vcc1 > 0) { - if (unlikely(sc_dev->vcc1 == 0)) - sc_dev->vcc1 = vcc1; - else { - sc_dev->vcc1 += vcc1 * 0.63; - sc_dev->vcc1 /= 1.63; - } - } - if (vcc2 > 0) { - if (unlikely(sc_dev->vcc2 == 0)) - sc_dev->vcc2 = vcc2; - else { - sc_dev->vcc2 += vcc2 * 0.63; - sc_dev->vcc2 /= 1.63; - } - } - if (vmain > 0) { - if (unlikely(sc_dev->vmain == 0)) - sc_dev->vmain = vmain; - else { - sc_dev->vmain += vmain * 0.63; - sc_dev->vmain /= 1.63; - } - } - wr_unlock(&(sc_info->stat_lock)); - } - - if (temp1 > 0 || temp2 > 0) { - wr_lock(&(sc_info->stat_lock)); - if (unlikely(!sc_dev->temp1)) - sc_dev->temp1 = temp1; - else { - sc_dev->temp1 += temp1 * 0.63; - sc_dev->temp1 /= 1.63; - } - if (unlikely(!sc_dev->temp2)) - sc_dev->temp2 = temp2; - else { - sc_dev->temp2 += temp2 * 0.63; - sc_dev->temp2 /= 1.63; - } - if (temp1 > sc_dev->temp1_max) { - sc_dev->temp1_max = temp1; - sc_dev->temp1_max_time = time(NULL); - } - if (temp2 > sc_dev->temp2_max) { - sc_dev->temp2_max = temp2; - sc_dev->temp2_max_time = time(NULL); - } - - if (unlikely(sc_dev->temp1_5min_av == 0)) - sc_dev->temp1_5min_av = temp1; - else { - sc_dev->temp1_5min_av += temp1 * .0042; - sc_dev->temp1_5min_av /= 1.0042; - } - if (unlikely(sc_dev->temp2_5min_av == 0)) - sc_dev->temp2_5min_av = temp2; - else { - sc_dev->temp2_5min_av += temp2 * .0042; - sc_dev->temp2_5min_av /= 1.0042; - } - wr_unlock(&(sc_info->stat_lock)); - - if (temp < temp2) - temp = temp2; - - bflsc->temp = temp; - - if (bflsc->cutofftemp > 0 && temp >= bflsc->cutofftemp) { - applog(LOG_WARNING, "%s%i:%s temp (%.1f) hit thermal cutoff limit %d, stopping work!", - bflsc->drv->name, bflsc->device_id, xlink, - temp, bflsc->cutofftemp); - dev_error(bflsc, REASON_DEV_THERMAL_CUTOFF); - sc_dev->overheat = true; - flush_one_dev(bflsc, dev); - return false; - } - - if (bflsc->cutofftemp > 0 && temp < (bflsc->cutofftemp - BFLSC_TEMP_RECOVER)) - sc_dev->overheat = false; - } - - return true; -} - -static void process_nonces(struct cgpu_info *bflsc, int dev, char *xlink, char *data, int count, char **fields, int *nonces) -{ - struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); - char midstate[MIDSTATE_BYTES], blockdata[MERKLE_BYTES]; - struct work *work; - uint32_t nonce; - int i, num, x; - bool res; - char *tmp; - - if (count < sc_info->que_fld_min) { - tmp = str_text(data); - applogsiz(LOG_INFO, BFLSC_APPLOGSIZ, - "%s%i:%s work returned too small (%d,%s)", - bflsc->drv->name, bflsc->device_id, xlink, count, tmp); - free(tmp); - inc_hw_errors(bflsc->thr[0]); - return; - } - - if (count > sc_info->que_fld_max) { - applog(LOG_INFO, "%s%i:%s work returned too large (%d) processing %d anyway", - bflsc->drv->name, bflsc->device_id, xlink, count, sc_info->que_fld_max); - count = sc_info->que_fld_max; - inc_hw_errors(bflsc->thr[0]); - } - - num = atoi(fields[sc_info->que_noncecount]); - if (num != count - sc_info->que_fld_min) { - tmp = str_text(data); - applogsiz(LOG_INFO, BFLSC_APPLOGSIZ, - "%s%i:%s incorrect data count (%d) will use %d instead from (%s)", - bflsc->drv->name, bflsc->device_id, xlink, num, - count - sc_info->que_fld_max, tmp); - free(tmp); - inc_hw_errors(bflsc->thr[0]); - } - - memset(midstate, 0, MIDSTATE_BYTES); - memset(blockdata, 0, MERKLE_BYTES); - if (!hex2bin((unsigned char *)midstate, fields[QUE_MIDSTATE], MIDSTATE_BYTES) || - !hex2bin((unsigned char *)blockdata, fields[QUE_BLOCKDATA], MERKLE_BYTES)) { - applog(LOG_INFO, "%s%i:%s Failed to convert binary data to hex result - ignored", - bflsc->drv->name, bflsc->device_id, xlink); - inc_hw_errors(bflsc->thr[0]); - return; - } - - work = take_queued_work_bymidstate(bflsc, midstate, MIDSTATE_BYTES, - blockdata, MERKLE_OFFSET, MERKLE_BYTES); - if (!work) { - if (sc_info->not_first_work) { - applog(LOG_INFO, "%s%i:%s failed to find nonce work - can't be processed - ignored", - bflsc->drv->name, bflsc->device_id, xlink); - inc_hw_errors(bflsc->thr[0]); - } - return; - } - - res = false; - x = 0; - for (i = sc_info->que_fld_min; i < count; i++) { - if (strlen(fields[i]) != 8) { - tmp = str_text(data); - applogsiz(LOG_INFO, BFLSC_APPLOGSIZ, - "%s%i:%s invalid nonce (%s) will try to process anyway", - bflsc->drv->name, bflsc->device_id, xlink, tmp); - free(tmp); - } - - hex2bin((void*)&nonce, fields[i], 4); - nonce = htobe32(nonce); - res = submit_nonce(bflsc->thr[0], work, nonce); - if (res) { - wr_lock(&(sc_info->stat_lock)); - sc_info->sc_devs[dev].nonces_found++; - wr_unlock(&(sc_info->stat_lock)); - - (*nonces)++; - x++; - } - } - - wr_lock(&(sc_info->stat_lock)); - if (res) - sc_info->sc_devs[dev].result_id++; - if (x > QUE_MAX_RESULTS) - x = QUE_MAX_RESULTS + 1; - (sc_info->result_size[x])++; - sc_info->sc_devs[dev].work_complete++; - sc_info->sc_devs[dev].hashes_unsent += FULLNONCE; - // If not flushed (stale) - if (!(work->devflag)) - sc_info->sc_devs[dev].work_queued -= 1; - wr_unlock(&(sc_info->stat_lock)); - - free_work(work); -} - -static int process_results(struct cgpu_info *bflsc, int dev, char *pbuf, int *nonces) -{ - struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); - char **items, *firstname, **fields, *lf; - int que = 0, i, lines, count; - char *tmp, *tmp2, *buf; - char xlink[17]; - bool res; - - *nonces = 0; - - xlinkstr(xlink, sizeof(xlink), dev, sc_info); - - buf = strdup(pbuf); - res = tolines(bflsc, dev, buf, &lines, &items, C_GETRESULTS); - free(buf); - if (!res || lines < 1) { - tmp = str_text(pbuf); - applogsiz(LOG_ERR, BFLSC_APPLOGSIZ, - "%s%i:%s empty result (%s) ignored", - bflsc->drv->name, bflsc->device_id, xlink, tmp); - free(tmp); - goto arigatou; - } - - if (lines < QUE_RES_LINES_MIN) { - tmp = str_text(pbuf); - applogsiz(LOG_ERR, BFLSC_APPLOGSIZ, - "%s%i:%s result of %d too small (%s) ignored", - bflsc->drv->name, bflsc->device_id, xlink, lines, tmp); - free(tmp); - goto arigatou; - } - - breakdown(ONECOLON, items[1], &count, &firstname, &fields, &lf); - if (count < 1) { - tmp = str_text(pbuf); - tmp2 = str_text(items[1]); - applogsiz(LOG_ERR, BFLSC_APPLOGSIZ, - "%s%i:%s empty result count (%s) in (%s) ignoring", - bflsc->drv->name, bflsc->device_id, xlink, tmp2, tmp); - free(tmp2); - free(tmp); - goto arigatou; - } else if (count != 1) { - tmp = str_text(pbuf); - tmp2 = str_text(items[1]); - applogsiz(LOG_ERR, BFLSC_APPLOGSIZ, - "%s%i:%s incorrect result count %d (%s) in (%s) will try anyway", - bflsc->drv->name, bflsc->device_id, xlink, count, tmp2, tmp); - free(tmp2); - free(tmp); - } - - que = atoi(fields[0]); - if (que != (lines - QUE_RES_LINES_MIN)) { - i = que; - // 1+ In case the last line isn't 'OK' - try to process it - que = 1 + lines - QUE_RES_LINES_MIN; - - tmp = str_text(pbuf); - tmp2 = str_text(items[0]); - applogsiz(LOG_ERR, BFLSC_APPLOGSIZ, - "%s%i:%s incorrect result count %d (%s) will try %d (%s)", - bflsc->drv->name, bflsc->device_id, xlink, i, tmp2, que, tmp); - free(tmp2); - free(tmp); - - } - - freebreakdown(&count, &firstname, &fields); - - for (i = 0; i < que; i++) { - res = breakdown(NOCOLON, items[i + QUE_RES_LINES_MIN - 1], &count, &firstname, &fields, &lf); - if (likely(res)) - process_nonces(bflsc, dev, &(xlink[0]), items[i], count, fields, nonces); - else - applogsiz(LOG_ERR, BFLSC_APPLOGSIZ, - "%s%i:%s failed to process nonce %s", - bflsc->drv->name, bflsc->device_id, xlink, items[i]); - freebreakdown(&count, &firstname, &fields); - sc_info->not_first_work = true; - } - -arigatou: - freetolines(&lines, &items); - - return que; -} - -#define TVF(tv) ((float)((tv)->tv_sec) + ((float)((tv)->tv_usec) / 1000000.0)) -#define TVFMS(tv) (TVF(tv) * 1000.0) - -// Thread to simply keep looking for results -static void *bflsc_get_results(void *userdata) -{ - struct cgpu_info *bflsc = (struct cgpu_info *)userdata; - struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); - struct timeval elapsed, now; - float oldest, f; - char buf[BFLSC_BUFSIZ+1]; - int err, amount; - int i, que, dev, nonces; - bool readok; - - cgtime(&now); - for (i = 0; i < sc_info->sc_count; i++) { - copy_time(&(sc_info->sc_devs[i].last_check_result), &now); - copy_time(&(sc_info->sc_devs[i].last_dev_result), &now); - copy_time(&(sc_info->sc_devs[i].last_nonce_result), &now); - } - - while (sc_info->shutdown == false) { - cgtimer_t ts_start; - - if (bflsc->usbinfo.nodev) - return NULL; - - dev = -1; - oldest = FLT_MAX; - cgtime(&now); - - // Find the first oldest ... that also needs checking - for (i = 0; i < sc_info->sc_count; i++) { - timersub(&now, &(sc_info->sc_devs[i].last_check_result), &elapsed); - f = TVFMS(&elapsed); - if (f < oldest && f >= sc_info->sc_devs[i].ms_work) { - f = oldest; - dev = i; - } - } - - if (bflsc->usbinfo.nodev) - return NULL; - - cgsleep_prepare_r(&ts_start); - if (dev == -1) - goto utsura; - - cgtime(&(sc_info->sc_devs[dev].last_check_result)); - - readok = bflsc_qres(bflsc, buf, sizeof(buf), dev, &err, &amount, false); - if (err < 0 || (!readok && amount != BFLSC_QRES_LEN) || (readok && amount < 1)) { - // TODO: do what else? - } else { - que = process_results(bflsc, dev, buf, &nonces); - sc_info->not_first_work = true; // in case it failed processing it - if (que > 0) - cgtime(&(sc_info->sc_devs[dev].last_dev_result)); - if (nonces > 0) - cgtime(&(sc_info->sc_devs[dev].last_nonce_result)); - - // TODO: if not getting results ... reinit? - } - -utsura: - cgsleep_ms_r(&ts_start, sc_info->results_sleep_time); - } - - return NULL; -} - -static bool bflsc_thread_prepare(struct thr_info *thr) -{ - struct cgpu_info *bflsc = thr->cgpu; - struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); - - if (thr_info_create(&(sc_info->results_thr), NULL, bflsc_get_results, (void *)bflsc)) { - applog(LOG_ERR, "%s%i: thread create failed", bflsc->drv->name, bflsc->device_id); - return false; - } - pthread_detach(sc_info->results_thr.pth); - - return true; -} - -static void bflsc_shutdown(struct thr_info *thr) -{ - struct cgpu_info *bflsc = thr->cgpu; - struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); - - bflsc_flush_work(bflsc); - sc_info->shutdown = true; -} - -static void bflsc_thread_enable(struct thr_info *thr) -{ - struct cgpu_info *bflsc = thr->cgpu; - - if (bflsc->usbinfo.nodev) - return; - - bflsc_initialise(bflsc); -} - -static bool bflsc_send_work(struct cgpu_info *bflsc, int dev, bool mandatory) -{ - struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); - struct FullNonceRangeJob data; - char buf[BFLSC_BUFSIZ+1]; - bool sent, ret = false; - struct work *work; - int err, amount; - int len, try; - int stage; - - // Device is gone - if (bflsc->usbinfo.nodev) - return false; - - // TODO: handle this everywhere - if (sc_info->sc_devs[dev].overheat == true) - return false; - - // Initially code only deals with sending one work item - data.payloadSize = BFLSC_JOBSIZ; - data.endOfBlock = BFLSC_EOB; - - len = sizeof(struct FullNonceRangeJob); - - /* On faster devices we have a lot of lock contention so only - * mandatorily grab the lock and send work if the queue is empty since - * we have a submit queue. */ - if (mandatory) - mutex_lock(&(bflsc->device_mutex)); - else { - if (mutex_trylock(&bflsc->device_mutex)) - return ret; - } - - work = get_queued(bflsc); - if (unlikely(!work)) { - mutex_unlock(&bflsc->device_mutex); - return ret; - } - memcpy(data.midState, work->midstate, MIDSTATE_BYTES); - memcpy(data.blockData, work->data + MERKLE_OFFSET, MERKLE_BYTES); - try = 0; -re_send: - err = send_recv_ds(bflsc, dev, &stage, &sent, &amount, - BFLSC_QJOB, BFLSC_QJOB_LEN, C_REQUESTQUEJOB, C_REQUESTQUEJOBSTATUS, - (char *)&data, len, C_QUEJOB, C_QUEJOBSTATUS, - buf, sizeof(buf)-1); - mutex_unlock(&(bflsc->device_mutex)); - - switch (stage) { - case 1: - if (!sent) { - bflsc_applog(bflsc, dev, C_REQUESTQUEJOB, amount, err); - goto out; - } else { - // TODO: handle other errors ... - - // Try twice - if (try++ < 1 && amount > 1 && - strstr(buf, BFLSC_TIMEOUT)) - goto re_send; - - bflsc_applog(bflsc, dev, C_REQUESTQUEJOBSTATUS, amount, err); - goto out; - } - break; - case 2: - if (!sent) { - bflsc_applog(bflsc, dev, C_QUEJOB, amount, err); - goto out; - } else { - if (!isokerr(err, buf, amount)) { - // TODO: check for QUEUE FULL and set work_queued to sc_info->que_size - // and report a code bug LOG_ERR - coz it should never happen - // TODO: handle other errors ... - - // Try twice - if (try++ < 1 && amount > 1 && - strstr(buf, BFLSC_TIMEOUT)) - goto re_send; - - bflsc_applog(bflsc, dev, C_QUEJOBSTATUS, amount, err); - goto out; - } - } - break; - } - - wr_lock(&(sc_info->stat_lock)); - sc_info->sc_devs[dev].work_queued++; - wr_unlock(&(sc_info->stat_lock)); - - work->subid = dev; - ret = true; -out: - if (unlikely(!ret)) - work_completed(bflsc, work); - return ret; -} - -static bool bflsc_queue_full(struct cgpu_info *bflsc) -{ - struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); - int i, dev, tried, que; - bool ret = false; - int tries = 0; - - tried = -1; - // if something is wrong with a device try the next one available - // TODO: try them all? Add an unavailable flag to sc_devs[i] init to 0 here first - while (++tries < 3) { - bool mandatory = false; - - // Device is gone - shouldn't normally get here - if (bflsc->usbinfo.nodev) { - ret = true; - break; - } - - dev = -1; - rd_lock(&(sc_info->stat_lock)); - // Anything waiting - gets the work first - for (i = 0; i < sc_info->sc_count; i++) { - // TODO: and ignore x-link dead - once I work out how to decide it is dead - if (i != tried && sc_info->sc_devs[i].work_queued == 0 && - !sc_info->sc_devs[i].overheat) { - dev = i; - break; - } - } - - if (dev == -1) { - que = sc_info->que_size * 10; // 10x is certainly above the MAX it could be - // The first device with the smallest amount queued - for (i = 0; i < sc_info->sc_count; i++) { - if (i != tried && sc_info->sc_devs[i].work_queued < que && - !sc_info->sc_devs[i].overheat) { - dev = i; - que = sc_info->sc_devs[i].work_queued; - } - } - if (que > sc_info->que_full_enough) - dev = -1; - else if (que < sc_info->que_low) - mandatory = true; - } - rd_unlock(&(sc_info->stat_lock)); - - // nothing needs work yet - if (dev == -1) { - ret = true; - break; - } - - if (bflsc_send_work(bflsc, dev, mandatory)) - break; - else - tried = dev; - } - - return ret; -} - -static int64_t bflsc_scanwork(struct thr_info *thr) -{ - struct cgpu_info *bflsc = thr->cgpu; - struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); - int64_t ret, unsent; - bool flushed, cleanup; - struct work *work, *tmp; - int dev, waited, i; - - // Device is gone - if (bflsc->usbinfo.nodev) - return -1; - - flushed = false; - // Single lock check if any are flagged as flushed - rd_lock(&(sc_info->stat_lock)); - for (dev = 0; dev < sc_info->sc_count; dev++) - flushed |= sc_info->sc_devs[dev].flushed; - rd_unlock(&(sc_info->stat_lock)); - - // > 0 flagged as flushed - if (flushed) { -// TODO: something like this ...... - for (dev = 0; dev < sc_info->sc_count; dev++) { - cleanup = false; - - // Is there any flushed work that can be removed? - rd_lock(&(sc_info->stat_lock)); - if (sc_info->sc_devs[dev].flushed) { - if (sc_info->sc_devs[dev].result_id > (sc_info->sc_devs[dev].flush_id + sc_info->flush_size)) - cleanup = true; - } - rd_unlock(&(sc_info->stat_lock)); - - // yes remove the flushed work that can be removed - if (cleanup) { - wr_lock(&bflsc->qlock); - HASH_ITER(hh, bflsc->queued_work, work, tmp) { - if (work->devflag && work->subid == dev) { - bflsc->queued_count--; - HASH_DEL(bflsc->queued_work, work); - discard_work(work); - } - } - wr_unlock(&bflsc->qlock); - - wr_lock(&(sc_info->stat_lock)); - sc_info->sc_devs[dev].flushed = false; - wr_unlock(&(sc_info->stat_lock)); - } - } - } - - waited = restart_wait(thr, sc_info->scan_sleep_time); - if (waited == ETIMEDOUT) { - unsigned int old_sleep_time, new_sleep_time = 0; - int min_queued = sc_info->que_size; - /* Only adjust the scan_sleep_time if we did not receive a - * restart message while waiting. Try to adjust sleep time - * so we drop to sc_info->que_watermark before getting more work. - */ - - rd_lock(&sc_info->stat_lock); - old_sleep_time = sc_info->scan_sleep_time; - for (i = 0; i < sc_info->sc_count; i++) { - if (sc_info->sc_devs[i].work_queued < min_queued) - min_queued = sc_info->sc_devs[i].work_queued; - } - rd_unlock(&sc_info->stat_lock); - new_sleep_time = old_sleep_time; - - /* Increase slowly but decrease quickly */ - if (min_queued > sc_info->que_full_enough && old_sleep_time < BFLSC_MAX_SLEEP) - new_sleep_time = old_sleep_time * 21 / 20; - else if (min_queued < sc_info->que_low) - new_sleep_time = old_sleep_time * 2 / 3; - - /* Do not sleep more than BFLSC_MAX_SLEEP so we can always - * report in at least 2 results per 5s log interval. */ - if (new_sleep_time != old_sleep_time) { - if (new_sleep_time > BFLSC_MAX_SLEEP) - new_sleep_time = BFLSC_MAX_SLEEP; - else if (new_sleep_time == 0) - new_sleep_time = 1; - applog(LOG_DEBUG, "%s%i: Changed scan sleep time to %d", - bflsc->drv->name, bflsc->device_id, new_sleep_time); - - wr_lock(&sc_info->stat_lock); - sc_info->scan_sleep_time = new_sleep_time; - wr_unlock(&sc_info->stat_lock); - } - } - - // Count up the work done since we last were here - ret = 0; - wr_lock(&(sc_info->stat_lock)); - for (dev = 0; dev < sc_info->sc_count; dev++) { - unsent = sc_info->sc_devs[dev].hashes_unsent; - sc_info->sc_devs[dev].hashes_unsent = 0; - sc_info->sc_devs[dev].hashes_sent += unsent; - sc_info->hashes_sent += unsent; - ret += unsent; - } - wr_unlock(&(sc_info->stat_lock)); - - return ret; -} - -#define BFLSC_OVER_TEMP 60 - -/* Set the fanspeed to auto for any valid value <= BFLSC_OVER_TEMP, - * or max for any value > BFLSC_OVER_TEMP or if we don't know the temperature. */ -static void bflsc_set_fanspeed(struct cgpu_info *bflsc) -{ - struct bflsc_info *sc_info = (struct bflsc_info *)bflsc->device_data; - char buf[BFLSC_BUFSIZ+1]; - char data[16+1]; - int amount; - bool sent; - - if ((bflsc->temp <= BFLSC_OVER_TEMP && bflsc->temp > 0 && sc_info->fanauto) || - ((bflsc->temp > BFLSC_OVER_TEMP || !bflsc->temp) && !sc_info->fanauto)) - return; - - if (bflsc->temp > BFLSC_OVER_TEMP || !bflsc->temp) { - strcpy(data, BFLSC_FAN4); - sc_info->fanauto = false; - } else { - strcpy(data, BFLSC_FANAUTO); - sc_info->fanauto = true; - } - - applog(LOG_DEBUG, "%s%i: temp=%.0f over=%d set fan to %s", - bflsc->drv->name, bflsc->device_id, bflsc->temp, - BFLSC_OVER_TEMP, data); - - mutex_lock(&bflsc->device_mutex); - send_recv_ss(bflsc, 0, &sent, &amount, - data, strlen(data), C_SETFAN, - buf, sizeof(buf)-1, C_FANREPLY, READ_NL); - mutex_unlock(&bflsc->device_mutex); -} - -static bool bflsc_get_stats(struct cgpu_info *bflsc) -{ - struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); - bool allok = true; - int i; - - // Device is gone - if (bflsc->usbinfo.nodev) - return false; - - for (i = 0; i < sc_info->sc_count; i++) { - if (!bflsc_get_temp(bflsc, i)) - allok = false; - - // Device is gone - if (bflsc->usbinfo.nodev) - return false; - - if (i < (sc_info->sc_count - 1)) - cgsleep_ms(BFLSC_TEMP_SLEEPMS); - } - - bflsc_set_fanspeed(bflsc); - - return allok; -} - -static void bflsc_identify(struct cgpu_info *bflsc) -{ - struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); - - // TODO: handle x-link - sc_info->flash_led = true; -} - -static bool bflsc_thread_init(struct thr_info *thr) -{ - struct cgpu_info *bflsc = thr->cgpu; - - if (bflsc->usbinfo.nodev) - return false; - - bflsc_initialise(bflsc); - - return true; -} - -// there should be a new API function to return device info that isn't the standard stuff -// instead of bflsc_api_stats - since the stats should really just be internal code info -// and the new one should be UNusual device stats/extra details - like the stuff below - -static struct api_data *bflsc_api_stats(struct cgpu_info *bflsc) -{ - struct bflsc_info *sc_info = (struct bflsc_info *)(bflsc->device_data); - struct api_data *root = NULL; - char buf[256]; - int i; - -//if no x-link ... etc - rd_lock(&(sc_info->stat_lock)); - root = api_add_temp(root, "Temp1", &(sc_info->sc_devs[0].temp1), true); - root = api_add_temp(root, "Temp2", &(sc_info->sc_devs[0].temp2), true); - root = api_add_volts(root, "Vcc1", &(sc_info->sc_devs[0].vcc1), true); - root = api_add_volts(root, "Vcc2", &(sc_info->sc_devs[0].vcc2), true); - root = api_add_volts(root, "Vmain", &(sc_info->sc_devs[0].vmain), true); - root = api_add_temp(root, "Temp1 Max", &(sc_info->sc_devs[0].temp1_max), true); - root = api_add_temp(root, "Temp2 Max", &(sc_info->sc_devs[0].temp2_max), true); - root = api_add_time(root, "Temp1 Max Time", &(sc_info->sc_devs[0].temp1_max_time), true); - root = api_add_time(root, "Temp2 Max Time", &(sc_info->sc_devs[0].temp2_max_time), true); - root = api_add_int(root, "Work Queued", &(sc_info->sc_devs[0].work_queued), true); - root = api_add_int(root, "Work Complete", &(sc_info->sc_devs[0].work_complete), true); - root = api_add_bool(root, "Overheat", &(sc_info->sc_devs[0].overheat), true); - root = api_add_uint64(root, "Flush ID", &(sc_info->sc_devs[0].flush_id), true); - root = api_add_uint64(root, "Result ID", &(sc_info->sc_devs[0].result_id), true); - root = api_add_bool(root, "Flushed", &(sc_info->sc_devs[0].flushed), true); - root = api_add_uint(root, "Scan Sleep", &(sc_info->scan_sleep_time), true); - root = api_add_uint(root, "Results Sleep", &(sc_info->results_sleep_time), true); - root = api_add_uint(root, "Work ms", &(sc_info->default_ms_work), true); - - buf[0] = '\0'; - for (i = 0; i <= QUE_MAX_RESULTS + 1; i++) - tailsprintf(buf, sizeof(buf), "%s%"PRIu64, (i > 0) ? "/" : "", sc_info->result_size[i]); - root = api_add_string(root, "Result Size", buf, true); - - rd_unlock(&(sc_info->stat_lock)); - - i = (int)(sc_info->driver_version); - root = api_add_int(root, "Driver", &i, true); - root = api_add_string(root, "Firmware", sc_info->sc_devs[0].firmware, false); - root = api_add_string(root, "Chips", sc_info->sc_devs[0].chips, false); - root = api_add_int(root, "Que Size", &(sc_info->que_size), false); - root = api_add_int(root, "Que Full", &(sc_info->que_full_enough), false); - root = api_add_int(root, "Que Watermark", &(sc_info->que_watermark), false); - root = api_add_int(root, "Que Low", &(sc_info->que_low), false); - root = api_add_escape(root, "GetInfo", sc_info->sc_devs[0].getinfo, false); - -/* -else a whole lot of something like these ... etc - root = api_add_temp(root, "X-%d-Temp1", &(sc_info->temp1), false); - root = api_add_temp(root, "X-%d-Temp2", &(sc_info->temp2), false); - root = api_add_volts(root, "X-%d-Vcc1", &(sc_info->vcc1), false); - root = api_add_volts(root, "X-%d-Vcc2", &(sc_info->vcc2), false); - root = api_add_volts(root, "X-%d-Vmain", &(sc_info->vmain), false); -*/ - - return root; -} - -struct device_drv bflsc_drv = { - .drv_id = DRIVER_bflsc, - .dname = "BitForceSC", - .name = BFLSC_SINGLE, - .drv_detect = bflsc_detect, - .get_api_stats = bflsc_api_stats, - .get_statline_before = get_bflsc_statline_before, - .get_stats = bflsc_get_stats, - .identify_device = bflsc_identify, - .thread_prepare = bflsc_thread_prepare, - .thread_init = bflsc_thread_init, - .hash_work = hash_queued_work, - .scanwork = bflsc_scanwork, - .queue_full = bflsc_queue_full, - .flush_work = bflsc_flush_work, - .thread_shutdown = bflsc_shutdown, - .thread_enable = bflsc_thread_enable -}; diff --git a/driver-bflsc.h b/driver-bflsc.h deleted file mode 100644 index b547ded9..00000000 --- a/driver-bflsc.h +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright 2013 Con Kolivas - * Copyright 2013 Andrew Smith - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. See COPYING for more details. - */ - -#ifndef BFLSC_H -#define BFLSC_H -#define BLANK "" -#define LFSTR "" - -/* - * Firmware - * DRV_V2 expects (beyond V1) the GetInfo to return the chip count - * The queues are 40 instead of 20 and are *usually* consumed and filled - * in bursts due to e.g. a 16 chip device doing 16 items at a time and - * returning 16 results at a time - * If the device has varying chip speeds, it will gradually break up the - * burst of results as we progress - */ -enum driver_version { - BFLSC_DRVUNDEF = 0, - BFLSC_DRV1, - BFLSC_DRV2 -}; - -/* - * With Firmware 1.0.0 and a result queue of 20 the Max is: - * inprocess = 12 - * max count = 9 - * 64+1+24+1+1+(1+8)*8+1 per line = 164 * 20 - * OK = 3 - * Total: 3304 - * - * With Firmware 1.2.* and a result queue of 40 but a limit of 15 replies: - * inprocess = 12 - * max count = 9 - * 64+1+24+1+1+1+1+(1+8)*8+1 per line = 166 * 15 - * OK = 3 - * Total: 2514 - * - */ -#define BFLSC_BUFSIZ (0x1000) - -// Should be big enough -#define BFLSC_APPLOGSIZ 8192 - -#define BFLSC_INFO_TIMEOUT 999 - -#define BFLSC_DI_FIRMWARE "FIRMWARE" -#define BFLSC_DI_ENGINES "ENGINES" -#define BFLSC_DI_JOBSINQUE "JOBS IN QUEUE" -#define BFLSC_DI_XLINKMODE "XLINK MODE" -#define BFLSC_DI_XLINKPRESENT "XLINK PRESENT" -#define BFLSC_DI_DEVICESINCHAIN "DEVICES IN CHAIN" -#define BFLSC_DI_CHAINPRESENCE "CHAIN PRESENCE MASK" -#define BFLSC_DI_CHIPS "CHIP PARALLELIZATION" -#define BFLSC_DI_CHIPS_PARALLEL "YES" - -#define FULLNONCE 0x100000000ULL - -struct bflsc_dev { - // Work - unsigned int ms_work; - int work_queued; - int work_complete; - int nonces_hw; // TODO: this - need to add a paramter to submit_nonce() - // so can pass 'dev' to hw_error - uint64_t hashes_unsent; - uint64_t hashes_sent; - uint64_t nonces_found; - - struct timeval last_check_result; - struct timeval last_dev_result; // array > 0 - struct timeval last_nonce_result; // > 0 nonce - - // Info - char getinfo[(BFLSC_BUFSIZ+4)*4]; - char *firmware; - int engines; // each engine represents a 'thread' in a chip - char *xlink_mode; - char *xlink_present; - char *chips; - - // Status - bool dead; // TODO: handle seperate x-link devices failing? - bool overheat; - - // Stats - float temp1; - float temp2; - float vcc1; - float vcc2; - float vmain; - float temp1_max; - float temp2_max; - time_t temp1_max_time; - time_t temp2_max_time; - float temp1_5min_av; // TODO: - float temp2_5min_av; // TODO: - - // To handle the fact that flushing the queue may not remove all work - // (normally one item is still being processed) - // and also that once the queue is flushed, results may still be in - // the output queue - but we don't want to process them at the time of doing an LP - // when result_id > flush_id+1, flushed work can be discarded since it - // is no longer in the device - uint64_t flush_id; // counter when results were last flushed - uint64_t result_id; // counter when results were last checked - bool flushed; // are any flushed? -}; - -#define QUE_MAX_RESULTS 8 - -struct bflsc_info { - enum driver_version driver_version; - pthread_rwlock_t stat_lock; - struct thr_info results_thr; - uint64_t hashes_sent; - uint32_t update_count; - struct timeval last_update; - int sc_count; - struct bflsc_dev *sc_devs; - unsigned int scan_sleep_time; - unsigned int results_sleep_time; - unsigned int default_ms_work; - bool shutdown; - bool flash_led; - bool not_first_work; // allow ignoring the first nonce error - bool fanauto; - int que_size; - int que_full_enough; - int que_watermark; - int que_low; - int que_noncecount; - int que_fld_min; - int que_fld_max; - int flush_size; - // count of given size, [+2] is for any > QUE_MAX_RESULTS - uint64_t result_size[QUE_MAX_RESULTS+2]; -}; - -#define BFLSC_XLINKHDR '@' -#define BFLSC_MAXPAYLOAD 255 - -struct DataForwardToChain { - uint8_t header; - uint8_t payloadSize; - uint8_t deviceAddress; - uint8_t payloadData[BFLSC_MAXPAYLOAD]; -}; - -#define DATAFORWARDSIZE(data) (1 + 1 + 1 + data.payloadSize) - -#define MIDSTATE_BYTES 32 -#define MERKLE_OFFSET 64 -#define MERKLE_BYTES 12 -#define BFLSC_QJOBSIZ (MIDSTATE_BYTES+MERKLE_BYTES+1) -#define BFLSC_EOB 0xaa - -struct QueueJobStructure { - uint8_t payloadSize; - uint8_t midState[MIDSTATE_BYTES]; - uint8_t blockData[MERKLE_BYTES]; - uint8_t endOfBlock; -}; - -#define QUE_RES_LINES_MIN 3 -#define QUE_MIDSTATE 0 -#define QUE_BLOCKDATA 1 - -#define QUE_NONCECOUNT_V1 2 -#define QUE_FLD_MIN_V1 3 -#define QUE_FLD_MAX_V1 (QUE_MAX_RESULTS+QUE_FLD_MIN_V1) - -#define QUE_CHIP_V2 2 -#define QUE_NONCECOUNT_V2 3 -#define QUE_FLD_MIN_V2 4 -#define QUE_FLD_MAX_V2 (QUE_MAX_RESULTS+QUE_FLD_MIN_V2) - -#define BFLSC_SIGNATURE 0xc1 -#define BFLSC_EOW 0xfe - -// N.B. this will only work with 5 jobs -// requires a different jobs[N] for each job count -// but really only need to handle 5 anyway -struct QueueJobPackStructure { - uint8_t payloadSize; - uint8_t signature; - uint8_t jobsInArray; - struct QueueJobStructure jobs[5]; - uint8_t endOfWrapper; -}; - -// TODO: Implement in API and also in usb device selection -struct SaveString { - uint8_t payloadSize; - uint8_t payloadData[BFLSC_MAXPAYLOAD]; -}; - -// Commands (Single Stage) -#define BFLSC_IDENTIFY "ZGX" -#define BFLSC_IDENTIFY_LEN (sizeof(BFLSC_IDENTIFY)-1) -#define BFLSC_DETAILS "ZCX" -#define BFLSC_DETAILS_LEN (sizeof(BFLSC_DETAILS)-1) -#define BFLSC_FIRMWARE "ZJX" -#define BFLSC_FIRMWARE_LEN (sizeof(BFLSC_FIRMWARE)-1) -#define BFLSC_FLASH "ZMX" -#define BFLSC_FLASH_LEN (sizeof(BFLSC_FLASH)-1) -#define BFLSC_VOLTAGE "ZTX" -#define BFLSC_VOLTAGE_LEN (sizeof(BFLSC_VOLTAGE)-1) -#define BFLSC_TEMPERATURE "ZLX" -#define BFLSC_TEMPERATURE_LEN (sizeof(BFLSC_TEMPERATURE)-1) -#define BFLSC_QRES "ZOX" -#define BFLSC_QRES_LEN (sizeof(BFLSC_QRES)-1) -#define BFLSC_QFLUSH "ZQX" -#define BFLSC_QFLUSH_LEN (sizeof(BFLSC_QFLUSH)-1) -#define BFLSC_FANAUTO "Z9X" -#define BFLSC_FANOUT_LEN (sizeof(BFLSC_FANAUTO)-1) -#define BFLSC_FAN0 "Z0X" -#define BFLSC_FAN0_LEN (sizeof(BFLSC_FAN0)-1) -#define BFLSC_FAN1 "Z1X" -#define BFLSC_FAN1_LEN (sizeof(BFLSC_FAN1)-1) -#define BFLSC_FAN2 "Z2X" -#define BFLSC_FAN2_LEN (sizeof(BFLSC_FAN2)-1) -#define BFLSC_FAN3 "Z3X" -#define BFLSC_FAN3_LEN (sizeof(BFLSC_FAN3)-1) -#define BFLSC_FAN4 "Z4X" -#define BFLSC_FAN4_LEN (sizeof(BFLSC_FAN4)-1) -#define BFLSC_LOADSTR "ZUX" -#define BFLSC_LOADSTR_LEN (sizeof(BFLSC_LOADSTR)-1) - -// Commands (Dual Stage) -#define BFLSC_QJOB "ZNX" -#define BFLSC_QJOB_LEN (sizeof(BFLSC_QJOB)-1) -#define BFLSC_QJOBS "ZWX" -#define BFLSC_QJOBS_LEN (sizeof(BFLSC_QJOBS)-1) -#define BFLSC_SAVESTR "ZSX" -#define BFLSC_SAVESTR_LEN (sizeof(BFLSC_SAVESTR)-1) - -// Replies -#define BFLSC_IDENTITY "BitFORCE SC" -#define BFLSC_BFLSC "SHA256 SC" - -#define BFLSC_OK "OK\n" -#define BFLSC_OK_LEN (sizeof(BFLSC_OK)-1) -#define BFLSC_SUCCESS "SUCCESS\n" -#define BFLSC_SUCCESS_LEN (sizeof(BFLSC_SUCCESS)-1) - -#define BFLSC_RESULT "COUNT:" -#define BFLSC_RESULT_LEN (sizeof(BFLSC_RESULT)-1) - -#define BFLSC_ANERR "ERR:" -#define BFLSC_ANERR_LEN (sizeof(BFLSC_ANERR)-1) -#define BFLSC_TIMEOUT BFLSC_ANERR "TIMEOUT" -#define BFLSC_TIMEOUT_LEN (sizeof(BFLSC_TIMEOUT)-1) -// x-link timeout has a space (a number follows) -#define BFLSC_XTIMEOUT BFLSC_ANERR "TIMEOUT " -#define BFLSC_XTIMEOUT_LEN (sizeof(BFLSC_XTIMEOUT)-1) -#define BFLSC_INVALID BFLSC_ANERR "INVALID DATA" -#define BFLSC_INVALID_LEN (sizeof(BFLSC_INVALID)-1) -#define BFLSC_ERRSIG BFLSC_ANERR "SIGNATURE" -#define BFLSC_ERRSIG_LEN (sizeof(BFLSC_ERRSIG)-1) -#define BFLSC_OKQ "OK:QUEUED" -#define BFLSC_OKQ_LEN (sizeof(BFLSC_OKQ)-1) -#define BFLSC_INPROCESS "INPROCESS" -#define BFLSC_INPROCESS_LEN (sizeof(BFLSC_INPROCESS)-1) -// Followed by N=1..5 -#define BFLSC_OKQN "OK:QUEUED " -#define BFLSC_OKQN_LEN (sizeof(BFLSC_OKQN)-1) -#define BFLSC_QFULL "QUEUE FULL" -#define BFLSC_QFULL_LEN (sizeof(BFLSC_QFULL)-1) -#define BFLSC_HITEMP "HIGH TEMPERATURE RECOVERY" -#define BFLSC_HITEMP_LEN (sizeof(BFLSC_HITEMP)-1) -#define BFLSC_EMPTYSTR "MEMORY EMPTY" -#define BFLSC_EMPTYSTR_LEN (sizeof(BFLSC_EMPTYSTR)-1) - -// Queued and non-queued are the same -#define FullNonceRangeJob QueueJobStructure -#define BFLSC_JOBSIZ BFLSC_QJOBSIZ - -// Non queued commands (not used) -#define BFLSC_SENDWORK "ZDX" -#define BFLSC_SENDWORK_LEN (sizeof(BFLSC_SENDWORK)-1) -#define BFLSC_WORKSTATUS "ZFX" -#define BFLSC_WORKSTATUS_LEN (sizeof(BFLSC_WORKSTATUS)-1) -#define BFLSC_SENDRANGE "ZPX" -#define BFLSC_SENDRANGE_LEN (sizeof(BFLSC_SENDRANGE)-1) - -// Non queued work replies (not used) -#define BFLSC_NONCE "NONCE-FOUND:" -#define BFLSC_NONCE_LEN (sizeof(BFLSC_NONCE)-1) -#define BFLSC_NO_NONCE "NO-NONCE" -#define BFLSC_NO_NONCE_LEN (sizeof(BFLSC_NO_NONCE)-1) -#define BFLSC_IDLE "IDLE" -#define BFLSC_IDLE_LEN (sizeof(BFLSC_IDLE)-1) -#define BFLSC_BUSY "BUSY" -#define BFLSC_BUSY_LEN (sizeof(BFLSC_BUSY)-1) - -#define BFLSC_MINIRIG "BAM" -#define BFLSC_SINGLE "BAS" -#define BFLSC_LITTLESINGLE "BAL" -#define BFLSC_JALAPENO "BAJ" - -// Default expected time for a nonce range -// - thus no need to check until this + last time work was found -// 60GH/s MiniRig (1 board) or Single -#define BAM_WORK_TIME 71.58 -#define BAS_WORK_TIME 71.58 -// 30GH/s Little Single -#define BAL_WORK_TIME 143.17 -// 4.5GH/s Jalapeno -#define BAJ_WORK_TIME 954.44 - -// Defaults (slightly over half the work time) but ensure none are above 100 -// SCAN_TIME - delay after sending work -// RES_TIME - delay between checking for results -#define BAM_SCAN_TIME 20 -#define BAS_SCAN_TIME 360 -#define BAL_SCAN_TIME 720 -#define BAJ_SCAN_TIME 1000 -#define BFLSC_RES_TIME 100 -#define BFLSC_MAX_SLEEP 2000 - -#define BAJ_LATENCY LATENCY_STD -#define BAL_LATENCY 12 -#define BAS_LATENCY 12 -// For now a BAM doesn't really exist - it's currently 8 independent BASs -#define BAM_LATENCY 2 - -#define BFLSC_TEMP_SLEEPMS 5 - -#define BFLSC_QUE_SIZE_V1 20 -#define BFLSC_QUE_FULL_ENOUGH_V1 13 -#define BFLSC_QUE_WATERMARK_V1 6 -#define BFLSC_QUE_LOW_V1 3 - -// TODO: use 5 batch jobs -// TODO: base these numbers on the chip count? -#define BFLSC_QUE_SIZE_V2 40 -#define BFLSC_QUE_FULL_ENOUGH_V2 36 -#define BFLSC_QUE_WATERMARK_V2 32 -#define BFLSC_QUE_LOW_V2 16 - -#define BFLSC_TEMP_OVERHEAT 90 -// Must drop this far below cutoff before resuming work -#define BFLSC_TEMP_RECOVER 5 - -// If initialisation fails the first time, -// sleep this amount (ms) and try again -#define REINIT_TIME_FIRST_MS 100 -// Max ms per sleep -#define REINIT_TIME_MAX_MS 800 -// Keep trying up to this many us -#define REINIT_TIME_MAX 3000000 - -int opt_bflsc_overheat; - -#endif /* BFLSC_H */ diff --git a/driver-bitforce.c b/driver-bitforce.c deleted file mode 100644 index 6cd0d52e..00000000 --- a/driver-bitforce.c +++ /dev/null @@ -1,756 +0,0 @@ -/* - * Copyright 2012-2013 Andrew Smith - * Copyright 2012 Luke Dashjr - * Copyright 2012 Con Kolivas - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. See COPYING for more details. - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "compat.h" -#include "miner.h" -#include "usbutils.h" -#include "util.h" - -#ifdef WIN32 -#include -#endif /* WIN32 */ - -#define BITFORCE_IDENTIFY "ZGX" -#define BITFORCE_IDENTIFY_LEN (sizeof(BITFORCE_IDENTIFY)-1) -#define BITFORCE_FLASH "ZMX" -#define BITFORCE_FLASH_LEN (sizeof(BITFORCE_FLASH)-1) -#define BITFORCE_TEMPERATURE "ZLX" -#define BITFORCE_TEMPERATURE_LEN (sizeof(BITFORCE_TEMPERATURE)-1) -#define BITFORCE_SENDRANGE "ZPX" -#define BITFORCE_SENDRANGE_LEN (sizeof(BITFORCE_SENDRANGE)-1) -#define BITFORCE_SENDWORK "ZDX" -#define BITFORCE_SENDWORK_LEN (sizeof(BITFORCE_SENDWORK)-1) -#define BITFORCE_WORKSTATUS "ZFX" -#define BITFORCE_WORKSTATUS_LEN (sizeof(BITFORCE_WORKSTATUS)-1) - -// Either of Nonce or No-nonce start with: -#define BITFORCE_EITHER "N" -#define BITFORCE_EITHER_LEN 1 -#define BITFORCE_NONCE "NONCE-FOUND" -#define BITFORCE_NONCE_LEN (sizeof(BITFORCE_NONCE)-1) -#define BITFORCE_NO_NONCE "NO-NONCE" -#define BITFORCE_NO_NONCE_MATCH 3 -#define BITFORCE_IDLE "IDLE" -#define BITFORCE_IDLE_MATCH 1 - -#define BITFORCE_SLEEP_MS 500 -#define BITFORCE_TIMEOUT_S 7 -#define BITFORCE_TIMEOUT_MS (BITFORCE_TIMEOUT_S * 1000) -#define BITFORCE_LONG_TIMEOUT_S 30 -#define BITFORCE_LONG_TIMEOUT_MS (BITFORCE_LONG_TIMEOUT_S * 1000) -#define BITFORCE_CHECK_INTERVAL_MS 10 -#define WORK_CHECK_INTERVAL_MS 50 -#define MAX_START_DELAY_MS 100 -#define tv_to_ms(tval) (tval.tv_sec * 1000 + tval.tv_usec / 1000) -#define TIME_AVG_CONSTANT 8 - -#define KNAME_WORK "full work" -#define KNAME_RANGE "nonce range" - -#define BITFORCE_BUFSIZ (0x200) - -// If initialisation fails the first time, -// sleep this amount (ms) and try again -#define REINIT_TIME_FIRST_MS 100 -// Max ms per sleep -#define REINIT_TIME_MAX_MS 800 -// Keep trying up to this many us -#define REINIT_TIME_MAX 3000000 - -static const char *blank = ""; - -static void bitforce_initialise(struct cgpu_info *bitforce, bool lock) -{ - int err, interface; - - if (lock) - mutex_lock(&bitforce->device_mutex); - - if (bitforce->usbinfo.nodev) - goto failed; - - interface = usb_interface(bitforce); - // Reset - err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, - FTDI_VALUE_RESET, interface, C_RESET); - if (opt_debug) - applog(LOG_DEBUG, "%s%i: reset got err %d", - bitforce->drv->name, bitforce->device_id, err); - - if (bitforce->usbinfo.nodev) - goto failed; - - // Set data control - err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_DATA, - FTDI_VALUE_DATA_BFL, interface, C_SETDATA); - if (opt_debug) - applog(LOG_DEBUG, "%s%i: setdata got err %d", - bitforce->drv->name, bitforce->device_id, err); - - if (bitforce->usbinfo.nodev) - goto failed; - - // Set the baud - err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, FTDI_VALUE_BAUD_BFL, - (FTDI_INDEX_BAUD_BFL & 0xff00) | interface, - C_SETBAUD); - if (opt_debug) - applog(LOG_DEBUG, "%s%i: setbaud got err %d", - bitforce->drv->name, bitforce->device_id, err); - - if (bitforce->usbinfo.nodev) - goto failed; - - // Set Flow Control - err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_FLOW, - FTDI_VALUE_FLOW, interface, C_SETFLOW); - if (opt_debug) - applog(LOG_DEBUG, "%s%i: setflowctrl got err %d", - bitforce->drv->name, bitforce->device_id, err); - - if (bitforce->usbinfo.nodev) - goto failed; - - // Set Modem Control - err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_MODEM, - FTDI_VALUE_MODEM, interface, C_SETMODEM); - if (opt_debug) - applog(LOG_DEBUG, "%s%i: setmodemctrl got err %d", - bitforce->drv->name, bitforce->device_id, err); - - if (bitforce->usbinfo.nodev) - goto failed; - - // Clear any sent data - err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, - FTDI_VALUE_PURGE_TX, interface, C_PURGETX); - if (opt_debug) - applog(LOG_DEBUG, "%s%i: purgetx got err %d", - bitforce->drv->name, bitforce->device_id, err); - - if (bitforce->usbinfo.nodev) - goto failed; - - // Clear any received data - err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, - FTDI_VALUE_PURGE_RX, interface, C_PURGERX); - if (opt_debug) - applog(LOG_DEBUG, "%s%i: purgerx got err %d", - bitforce->drv->name, bitforce->device_id, err); - -failed: - - if (lock) - mutex_unlock(&bitforce->device_mutex); -} - -static bool bitforce_detect_one(struct libusb_device *dev, struct usb_find_devices *found) -{ - char buf[BITFORCE_BUFSIZ+1]; - int err, amount; - char *s; - struct timeval init_start, init_now; - int init_sleep, init_count; - bool ident_first; - - struct cgpu_info *bitforce = usb_alloc_cgpu(&bitforce_drv, 1); - - if (!usb_init(bitforce, dev, found)) - goto shin; - - // Allow 2 complete attempts if the 1st time returns an unrecognised reply - ident_first = true; -retry: - init_count = 0; - init_sleep = REINIT_TIME_FIRST_MS; - cgtime(&init_start); -reinit: - bitforce_initialise(bitforce, false); - if ((err = usb_write(bitforce, BITFORCE_IDENTIFY, BITFORCE_IDENTIFY_LEN, &amount, C_REQUESTIDENTIFY)) < 0 || amount != BITFORCE_IDENTIFY_LEN) { - applog(LOG_ERR, "%s detect (%s) send identify request failed (%d:%d)", - bitforce->drv->dname, bitforce->device_path, amount, err); - goto unshin; - } - - if ((err = usb_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_GETIDENTIFY)) < 0 || amount < 1) { - init_count++; - cgtime(&init_now); - if (us_tdiff(&init_now, &init_start) <= REINIT_TIME_MAX) { - if (init_count == 2) { - applog(LOG_WARNING, "%s detect (%s) 2nd init failed (%d:%d) - retrying", - bitforce->drv->dname, bitforce->device_path, amount, err); - } - cgsleep_ms(init_sleep); - if ((init_sleep * 2) <= REINIT_TIME_MAX_MS) - init_sleep *= 2; - goto reinit; - } - - if (init_count > 0) - applog(LOG_WARNING, "%s detect (%s) init failed %d times %.2fs", - bitforce->drv->dname, bitforce->device_path, init_count, tdiff(&init_now, &init_start)); - - if (err < 0) { - applog(LOG_ERR, "%s detect (%s) error identify reply (%d:%d)", - bitforce->drv->dname, bitforce->device_path, amount, err); - } else { - applog(LOG_ERR, "%s detect (%s) empty identify reply (%d)", - bitforce->drv->dname, bitforce->device_path, amount); - } - - goto unshin; - } - buf[amount] = '\0'; - - if (unlikely(!strstr(buf, "SHA256"))) { - if (ident_first) { - applog(LOG_WARNING, "%s detect (%s) didn't recognise '%s' trying again ...", - bitforce->drv->dname, bitforce->device_path, buf); - ident_first = false; - goto retry; - } - applog(LOG_ERR, "%s detect (%s) didn't recognise '%s' on 2nd attempt", - bitforce->drv->dname, bitforce->device_path, buf); - goto unshin; - } - - if (strstr(buf, "SHA256 SC")) { -#ifdef USE_BFLSC - applog(LOG_DEBUG, "SC device detected, will defer to BFLSC driver"); -#else - applog(LOG_WARNING, "SC device detected but no BFLSC support compiled in!"); -#endif - goto unshin; - } - - if (likely((!memcmp(buf, ">>>ID: ", 7)) && (s = strstr(buf + 3, ">>>")))) { - s[0] = '\0'; - bitforce->name = strdup(buf + 7); - } else { - bitforce->name = (char *)blank; - } - - // We have a real BitForce! - applog(LOG_DEBUG, "%s (%s) identified as: '%s'", - bitforce->drv->dname, bitforce->device_path, bitforce->name); - - /* Initially enable support for nonce range and disable it later if it - * fails */ - if (opt_bfl_noncerange) { - bitforce->nonce_range = true; - bitforce->sleep_ms = BITFORCE_SLEEP_MS; - bitforce->kname = KNAME_RANGE; - } else { - bitforce->sleep_ms = BITFORCE_SLEEP_MS * 5; - bitforce->kname = KNAME_WORK; - } - - if (!add_cgpu(bitforce)) - goto unshin; - - update_usb_stats(bitforce); - - mutex_init(&bitforce->device_mutex); - - return true; - -unshin: - - usb_uninit(bitforce); - -shin: - - if (bitforce->name != blank) { - free(bitforce->name); - bitforce->name = NULL; - } - - bitforce = usb_free_cgpu(bitforce); - - return false; -} - -static void bitforce_detect(bool __maybe_unused hotplug) -{ - usb_detect(&bitforce_drv, bitforce_detect_one); -} - -static void get_bitforce_statline_before(char *buf, size_t bufsiz, struct cgpu_info *bitforce) -{ - float gt = bitforce->temp; - - if (gt > 0) - tailsprintf(buf, bufsiz, "%5.1fC ", gt); - else - tailsprintf(buf, bufsiz, " "); - - tailsprintf(buf, bufsiz, " | "); -} - -static bool bitforce_thread_prepare(__maybe_unused struct thr_info *thr) -{ -// struct cgpu_info *bitforce = thr->cgpu; - - return true; -} - -static void bitforce_flash_led(struct cgpu_info *bitforce) -{ - int err, amount; - - /* Do not try to flash the led if we're polling for a result to - * minimise the chance of interleaved results */ - if (bitforce->polling) - return; - - /* It is not critical flashing the led so don't get stuck if we - * can't grab the mutex now */ - if (mutex_trylock(&bitforce->device_mutex)) - return; - - if ((err = usb_write(bitforce, BITFORCE_FLASH, BITFORCE_FLASH_LEN, &amount, C_REQUESTFLASH)) < 0 || amount != BITFORCE_FLASH_LEN) { - applog(LOG_ERR, "%s%i: flash request failed (%d:%d)", - bitforce->drv->name, bitforce->device_id, amount, err); - } else { - /* However, this stops anything else getting a reply - * So best to delay any other access to the BFL */ - cgsleep_ms(4000); - } - - /* Once we've tried - don't do it until told to again */ - bitforce->flash_led = false; - - mutex_unlock(&bitforce->device_mutex); - - return; // nothing is returned by the BFL -} - -static bool bitforce_get_temp(struct cgpu_info *bitforce) -{ - char buf[BITFORCE_BUFSIZ+1]; - int err, amount; - char *s; - - // Device is gone - if (bitforce->usbinfo.nodev) - return false; - - /* Do not try to get the temperature if we're polling for a result to - * minimise the chance of interleaved results */ - if (bitforce->polling) - return true; - - // Flash instead of Temp - doing both can be too slow - if (bitforce->flash_led) { - bitforce_flash_led(bitforce); - return true; - } - - /* It is not critical getting temperature so don't get stuck if we - * can't grab the mutex here */ - if (mutex_trylock(&bitforce->device_mutex)) - return false; - - if ((err = usb_write(bitforce, BITFORCE_TEMPERATURE, BITFORCE_TEMPERATURE_LEN, &amount, C_REQUESTTEMPERATURE)) < 0 || amount != BITFORCE_TEMPERATURE_LEN) { - mutex_unlock(&bitforce->device_mutex); - applog(LOG_ERR, "%s%i: Error: Request temp invalid/timed out (%d:%d)", - bitforce->drv->name, bitforce->device_id, amount, err); - bitforce->hw_errors++; - return false; - } - - if ((err = usb_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_GETTEMPERATURE)) < 0 || amount < 1) { - mutex_unlock(&bitforce->device_mutex); - if (err < 0) { - applog(LOG_ERR, "%s%i: Error: Get temp return invalid/timed out (%d:%d)", - bitforce->drv->name, bitforce->device_id, amount, err); - } else { - applog(LOG_ERR, "%s%i: Error: Get temp returned nothing (%d:%d)", - bitforce->drv->name, bitforce->device_id, amount, err); - } - bitforce->hw_errors++; - return false; - } - - mutex_unlock(&bitforce->device_mutex); - - if ((!strncasecmp(buf, "TEMP", 4)) && (s = strchr(buf + 4, ':'))) { - float temp = strtof(s + 1, NULL); - - /* Cope with older software that breaks and reads nonsense - * values */ - if (temp > 100) - temp = strtod(s + 1, NULL); - - if (temp > 0) { - bitforce->temp = temp; - if (unlikely(bitforce->cutofftemp > 0 && temp > bitforce->cutofftemp)) { - applog(LOG_WARNING, "%s%i: Hit thermal cutoff limit, disabling!", - bitforce->drv->name, bitforce->device_id); - bitforce->deven = DEV_RECOVER; - dev_error(bitforce, REASON_DEV_THERMAL_CUTOFF); - } - } - } else { - /* Use the temperature monitor as a kind of watchdog for when - * our responses are out of sync and flush the buffer to - * hopefully recover */ - applog(LOG_WARNING, "%s%i: Garbled response probably throttling, clearing buffer", - bitforce->drv->name, bitforce->device_id); - dev_error(bitforce, REASON_DEV_THROTTLE); - /* Count throttling episodes as hardware errors */ - bitforce->hw_errors++; - bitforce_initialise(bitforce, true); - return false; - } - - return true; -} - -static bool bitforce_send_work(struct thr_info *thr, struct work *work) -{ - struct cgpu_info *bitforce = thr->cgpu; - unsigned char ob[70]; - char buf[BITFORCE_BUFSIZ+1]; - int err, amount; - char *s; - char *cmd; - int len; - -re_send: - if (bitforce->nonce_range) { - cmd = BITFORCE_SENDRANGE; - len = BITFORCE_SENDRANGE_LEN; - } else { - cmd = BITFORCE_SENDWORK; - len = BITFORCE_SENDWORK_LEN; - } - - mutex_lock(&bitforce->device_mutex); - if ((err = usb_write(bitforce, cmd, len, &amount, C_REQUESTSENDWORK)) < 0 || amount != len) { - mutex_unlock(&bitforce->device_mutex); - applog(LOG_ERR, "%s%i: request send work failed (%d:%d)", - bitforce->drv->name, bitforce->device_id, amount, err); - return false; - } - - if ((err = usb_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_REQUESTSENDWORKSTATUS)) < 0) { - mutex_unlock(&bitforce->device_mutex); - applog(LOG_ERR, "%s%d: read request send work status failed (%d:%d)", - bitforce->drv->name, bitforce->device_id, amount, err); - return false; - } - - if (amount == 0 || !buf[0] || !strncasecmp(buf, "B", 1)) { - mutex_unlock(&bitforce->device_mutex); - cgsleep_ms(WORK_CHECK_INTERVAL_MS); - goto re_send; - } else if (unlikely(strncasecmp(buf, "OK", 2))) { - mutex_unlock(&bitforce->device_mutex); - if (bitforce->nonce_range) { - applog(LOG_WARNING, "%s%i: Does not support nonce range, disabling", - bitforce->drv->name, bitforce->device_id); - bitforce->nonce_range = false; - bitforce->sleep_ms *= 5; - bitforce->kname = KNAME_WORK; - goto re_send; - } - applog(LOG_ERR, "%s%i: Error: Send work reports: %s", - bitforce->drv->name, bitforce->device_id, buf); - return false; - } - - sprintf((char *)ob, ">>>>>>>>"); - memcpy(ob + 8, work->midstate, 32); - memcpy(ob + 8 + 32, work->data + 64, 12); - if (!bitforce->nonce_range) { - sprintf((char *)ob + 8 + 32 + 12, ">>>>>>>>"); - work->blk.nonce = bitforce->nonces = 0xffffffff; - len = 60; - } else { - uint32_t *nonce; - - nonce = (uint32_t *)(ob + 8 + 32 + 12); - *nonce = htobe32(work->blk.nonce); - nonce = (uint32_t *)(ob + 8 + 32 + 12 + 4); - /* Split work up into 1/5th nonce ranges */ - bitforce->nonces = 0x33333332; - *nonce = htobe32(work->blk.nonce + bitforce->nonces); - work->blk.nonce += bitforce->nonces + 1; - sprintf((char *)ob + 8 + 32 + 12 + 8, ">>>>>>>>"); - len = 68; - } - - if ((err = usb_write(bitforce, (char *)ob, len, &amount, C_SENDWORK)) < 0 || amount != len) { - mutex_unlock(&bitforce->device_mutex); - applog(LOG_ERR, "%s%i: send work failed (%d:%d)", - bitforce->drv->name, bitforce->device_id, amount, err); - return false; - } - - if ((err = usb_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_SENDWORKSTATUS)) < 0) { - mutex_unlock(&bitforce->device_mutex); - applog(LOG_ERR, "%s%d: read send work status failed (%d:%d)", - bitforce->drv->name, bitforce->device_id, amount, err); - return false; - } - - mutex_unlock(&bitforce->device_mutex); - - if (opt_debug) { - s = bin2hex(ob + 8, 44); - applog(LOG_DEBUG, "%s%i: block data: %s", - bitforce->drv->name, bitforce->device_id, s); - free(s); - } - - if (amount == 0 || !buf[0]) { - applog(LOG_ERR, "%s%i: Error: Send block data returned empty string/timed out", - bitforce->drv->name, bitforce->device_id); - return false; - } - - if (unlikely(strncasecmp(buf, "OK", 2))) { - applog(LOG_ERR, "%s%i: Error: Send block data reports: %s", - bitforce->drv->name, bitforce->device_id, buf); - return false; - } - - cgtime(&bitforce->work_start_tv); - return true; -} - -static int64_t bitforce_get_result(struct thr_info *thr, struct work *work) -{ - struct cgpu_info *bitforce = thr->cgpu; - unsigned int delay_time_ms; - struct timeval elapsed; - struct timeval now; - char buf[BITFORCE_BUFSIZ+1]; - int amount; - char *pnoncebuf; - uint32_t nonce; - - while (1) { - if (unlikely(thr->work_restart)) - return 0; - - mutex_lock(&bitforce->device_mutex); - usb_write(bitforce, BITFORCE_WORKSTATUS, BITFORCE_WORKSTATUS_LEN, &amount, C_REQUESTWORKSTATUS); - usb_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_GETWORKSTATUS); - mutex_unlock(&bitforce->device_mutex); - - cgtime(&now); - timersub(&now, &bitforce->work_start_tv, &elapsed); - - if (elapsed.tv_sec >= BITFORCE_LONG_TIMEOUT_S) { - applog(LOG_ERR, "%s%i: took %ldms - longer than %dms", - bitforce->drv->name, bitforce->device_id, - tv_to_ms(elapsed), BITFORCE_LONG_TIMEOUT_MS); - return 0; - } - - if (amount > 0 && buf[0] && strncasecmp(buf, "B", 1)) /* BFL does not respond during throttling */ - break; - - /* if BFL is throttling, no point checking so quickly */ - delay_time_ms = (buf[0] ? BITFORCE_CHECK_INTERVAL_MS : 2 * WORK_CHECK_INTERVAL_MS); - cgsleep_ms(delay_time_ms); - bitforce->wait_ms += delay_time_ms; - } - - if (elapsed.tv_sec > BITFORCE_TIMEOUT_S) { - applog(LOG_ERR, "%s%i: took %ldms - longer than %dms", - bitforce->drv->name, bitforce->device_id, - tv_to_ms(elapsed), BITFORCE_TIMEOUT_MS); - dev_error(bitforce, REASON_DEV_OVER_HEAT); - - /* Only return if we got nothing after timeout - there still may be results */ - if (amount == 0) - return 0; - } else if (!strncasecmp(buf, BITFORCE_EITHER, BITFORCE_EITHER_LEN)) { - /* Simple timing adjustment. Allow a few polls to cope with - * OS timer delays being variably reliable. wait_ms will - * always equal sleep_ms when we've waited greater than or - * equal to the result return time.*/ - delay_time_ms = bitforce->sleep_ms; - - if (bitforce->wait_ms > bitforce->sleep_ms + (WORK_CHECK_INTERVAL_MS * 2)) - bitforce->sleep_ms += (bitforce->wait_ms - bitforce->sleep_ms) / 2; - else if (bitforce->wait_ms == bitforce->sleep_ms) { - if (bitforce->sleep_ms > WORK_CHECK_INTERVAL_MS) - bitforce->sleep_ms -= WORK_CHECK_INTERVAL_MS; - else if (bitforce->sleep_ms > BITFORCE_CHECK_INTERVAL_MS) - bitforce->sleep_ms -= BITFORCE_CHECK_INTERVAL_MS; - } - - if (delay_time_ms != bitforce->sleep_ms) - applog(LOG_DEBUG, "%s%i: Wait time changed to: %d, waited %u", - bitforce->drv->name, bitforce->device_id, - bitforce->sleep_ms, bitforce->wait_ms); - - /* Work out the average time taken. Float for calculation, uint for display */ - bitforce->avg_wait_f += (tv_to_ms(elapsed) - bitforce->avg_wait_f) / TIME_AVG_CONSTANT; - bitforce->avg_wait_d = (unsigned int) (bitforce->avg_wait_f + 0.5); - } - - applog(LOG_DEBUG, "%s%i: waited %dms until %s", - bitforce->drv->name, bitforce->device_id, - bitforce->wait_ms, buf); - if (!strncasecmp(buf, BITFORCE_NO_NONCE, BITFORCE_NO_NONCE_MATCH)) - return bitforce->nonces; /* No valid nonce found */ - else if (!strncasecmp(buf, BITFORCE_IDLE, BITFORCE_IDLE_MATCH)) - return 0; /* Device idle */ - else if (strncasecmp(buf, BITFORCE_NONCE, BITFORCE_NONCE_LEN)) { - bitforce->hw_errors++; - applog(LOG_WARNING, "%s%i: Error: Get result reports: %s", - bitforce->drv->name, bitforce->device_id, buf); - bitforce_initialise(bitforce, true); - return 0; - } - - pnoncebuf = &buf[12]; - - while (1) { - hex2bin((void*)&nonce, pnoncebuf, 4); -#ifndef __BIG_ENDIAN__ - nonce = swab32(nonce); -#endif - if (unlikely(bitforce->nonce_range && (nonce >= work->blk.nonce || - (work->blk.nonce > 0 && nonce < work->blk.nonce - bitforce->nonces - 1)))) { - applog(LOG_WARNING, "%s%i: Disabling broken nonce range support", - bitforce->drv->name, bitforce->device_id); - bitforce->nonce_range = false; - work->blk.nonce = 0xffffffff; - bitforce->sleep_ms *= 5; - bitforce->kname = KNAME_WORK; - } - - submit_nonce(thr, work, nonce); - if (strncmp(&pnoncebuf[8], ",", 1)) - break; - pnoncebuf += 9; - } - - return bitforce->nonces; -} - -static void bitforce_shutdown(__maybe_unused struct thr_info *thr) -{ -// struct cgpu_info *bitforce = thr->cgpu; -} - -static void biforce_thread_enable(struct thr_info *thr) -{ - struct cgpu_info *bitforce = thr->cgpu; - - bitforce_initialise(bitforce, true); -} - -static int64_t bitforce_scanhash(struct thr_info *thr, struct work *work, int64_t __maybe_unused max_nonce) -{ - struct cgpu_info *bitforce = thr->cgpu; - bool send_ret; - int64_t ret; - - // Device is gone - if (bitforce->usbinfo.nodev) - return -1; - - send_ret = bitforce_send_work(thr, work); - - if (!restart_wait(thr, bitforce->sleep_ms)) - return 0; - - bitforce->wait_ms = bitforce->sleep_ms; - - if (send_ret) { - bitforce->polling = true; - ret = bitforce_get_result(thr, work); - bitforce->polling = false; - } else - ret = -1; - - if (ret == -1) { - ret = 0; - applog(LOG_ERR, "%s%i: Comms error", bitforce->drv->name, bitforce->device_id); - dev_error(bitforce, REASON_DEV_COMMS_ERROR); - bitforce->hw_errors++; - /* empty read buffer */ - bitforce_initialise(bitforce, true); - } - return ret; -} - -static bool bitforce_get_stats(struct cgpu_info *bitforce) -{ - return bitforce_get_temp(bitforce); -} - -static void bitforce_identify(struct cgpu_info *bitforce) -{ - bitforce->flash_led = true; -} - -static bool bitforce_thread_init(struct thr_info *thr) -{ - struct cgpu_info *bitforce = thr->cgpu; - unsigned int wait; - - /* Pause each new thread at least 100ms between initialising - * so the devices aren't making calls all at the same time. */ - wait = thr->id * MAX_START_DELAY_MS; - applog(LOG_DEBUG, "%s%d: Delaying start by %dms", - bitforce->drv->name, bitforce->device_id, wait / 1000); - cgsleep_ms(wait); - - return true; -} - -static struct api_data *bitforce_api_stats(struct cgpu_info *cgpu) -{ - struct api_data *root = NULL; - - // Warning, access to these is not locked - but we don't really - // care since hashing performance is way more important than - // locking access to displaying API debug 'stats' - // If locking becomes an issue for any of them, use copy_data=true also - root = api_add_uint(root, "Sleep Time", &(cgpu->sleep_ms), false); - root = api_add_uint(root, "Avg Wait", &(cgpu->avg_wait_d), false); - - return root; -} - -struct device_drv bitforce_drv = { - .drv_id = DRIVER_bitforce, - .dname = "BitForce", - .name = "BFL", - .drv_detect = bitforce_detect, - .get_api_stats = bitforce_api_stats, - .get_statline_before = get_bitforce_statline_before, - .get_stats = bitforce_get_stats, - .identify_device = bitforce_identify, - .thread_prepare = bitforce_thread_prepare, - .thread_init = bitforce_thread_init, - .scanhash = bitforce_scanhash, - .thread_shutdown = bitforce_shutdown, - .thread_enable = biforce_thread_enable -}; diff --git a/driver-bitfury.c b/driver-bitfury.c deleted file mode 100644 index 69f3acaa..00000000 --- a/driver-bitfury.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright 2013 Con Kolivas - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. See COPYING for more details. - */ - -#include "config.h" - -#include "miner.h" -#include "driver-bitfury.h" -#include "sha2.h" - -/* 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) -{ - char buf[512]; - int amount; - - do { - usb_read_once(bitfury, buf, 512, &amount, C_BF1_FLUSH); - } while (amount); -} - -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; - err = usb_transfer(bitfury, 0, 9, 1, 0, C_ATMEL_RESET); - if (!err) - err = usb_transfer(bitfury, 0x21, 0x22, 0, 0, C_ATMEL_OPEN); - if (!err) { - err = usb_transfer_data(bitfury, 0x21, 0x20, 0x0000, 0, buf, - BF1MSGSIZE, C_ATMEL_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) -{ - bitfury_empty_buffer(bitfury); -} - -static void bitfury_identify(struct cgpu_info *bitfury) -{ - int amount; - - usb_write(bitfury, "L", 1, &amount, C_BF1_IDENTIFY); -} - -static bool bitfury_getinfo(struct cgpu_info *bitfury, struct bitfury_info *info) -{ - int amount, err; - char buf[16]; - - err = usb_write(bitfury, "I", 1, &amount, C_BF1_REQINFO); - if (err) { - applog(LOG_INFO, "%s %d: Failed to write REQINFO", - bitfury->drv->name, bitfury->device_id); - return false; - } - 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 != 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]; - memcpy(&info->product, buf + 2, 8); - memcpy(&info->serial, buf + 10, 4); - - applog(LOG_INFO, "%s %d: Getinfo returned version %d, product %s serial %08x", bitfury->drv->name, - bitfury->device_id, info->version, info->product, info->serial); - bitfury_empty_buffer(bitfury); - return true; -} - -static bool bitfury_reset(struct cgpu_info *bitfury) -{ - int amount, err; - char buf[16]; - - err = usb_write(bitfury, "R", 1, &amount, C_BF1_REQRESET); - if (err) { - applog(LOG_INFO, "%s %d: Failed to write REQRESET", - bitfury->drv->name, bitfury->device_id); - return false; - } - 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 != 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, - bitfury->device_id, buf); - bitfury_empty_buffer(bitfury); - return true; -} - -static bool bitfury_detect_one(struct libusb_device *dev, struct usb_find_devices *found) -{ - struct cgpu_info *bitfury; - struct bitfury_info *info; - - bitfury = usb_alloc_cgpu(&bitfury_drv, 1); - - if (!usb_init(bitfury, dev, found)) - goto out; - applog(LOG_INFO, "%s %d: Found at %s", bitfury->drv->name, - bitfury->device_id, bitfury->device_path); - - info = calloc(sizeof(struct bitfury_info), 1); - 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; - - if (!bitfury_open(bitfury)) - goto out_close; - - /* Send getinfo request */ - if (!bitfury_getinfo(bitfury, info)) - goto out_close; - - /* Send reset request */ - if (!bitfury_reset(bitfury)) - goto out_close; - - bitfury_identify(bitfury); - bitfury_empty_buffer(bitfury); - - if (!add_cgpu(bitfury)) - quit(1, "Failed to add_cgpu in bitfury_detect_one"); - - update_usb_stats(bitfury); - applog(LOG_INFO, "%s %d: Successfully initialised %s", - bitfury->drv->name, bitfury->device_id, bitfury->device_path); - return true; -out_close: - bitfury_close(bitfury); - usb_uninit(bitfury); -out: - bitfury = usb_free_cgpu(bitfury); - return false; -} - -static void bitfury_detect(bool __maybe_unused hotplug) -{ - usb_detect(&bitfury_drv, bitfury_detect_one); -} - -static uint32_t decnonce(uint32_t in) -{ - uint32_t out; - - /* First part load */ - out = (in & 0xFF) << 24; in >>= 8; - - /* Byte reversal */ - in = (((in & 0xaaaaaaaa) >> 1) | ((in & 0x55555555) << 1)); - in = (((in & 0xcccccccc) >> 2) | ((in & 0x33333333) << 2)); - in = (((in & 0xf0f0f0f0) >> 4) | ((in & 0x0f0f0f0f) << 4)); - - out |= (in >> 2)&0x3FFFFF; - - /* Extraction */ - if (in & 1) out |= (1 << 23); - if (in & 2) out |= (1 << 22); - - out -= 0x800004; - return out; -} - -#define BT_OFFSETS 3 -const uint32_t bf_offsets[] = {-0x800000, 0, -0x400000}; - -static bool bitfury_checkresults(struct thr_info *thr, struct work *work, uint32_t nonce) -{ - int i; - - for (i = 0; i < BT_OFFSETS; i++) { - if (test_nonce(work, nonce + bf_offsets[i])) { - submit_tested_work(thr, work); - return true; - } - } - return false; -} - -static int64_t bitfury_scanwork(struct thr_info *thr) -{ - struct cgpu_info *bitfury = thr->cgpu; - struct bitfury_info *info = bitfury->device_data; - struct timeval tv_now; - struct work *work; - double nonce_rate; - int64_t ret = 0; - int amount, i; - char buf[45]; - int ms_diff; - - work = get_work(thr, thr->id); - if (unlikely(thr->work_restart)) { - free_work(work); - return 0; - } - - buf[0] = 'W'; - memcpy(buf + 1, work->midstate, 32); - memcpy(buf + 33, work->data + 64, 12); - - /* New results may spill out from the latest work, making us drop out - * too early so read whatever we get for the first half nonce and then - * look for the results to prev work. */ - cgtime(&tv_now); - ms_diff = 600 - ms_tdiff(&tv_now, &info->tv_start); - if (ms_diff > 0) { - usb_read_timeout_cancellable(bitfury, info->buf, 512, &amount, ms_diff, C_BF1_GETRES); - info->tot += amount; - } - - if (unlikely(thr->work_restart)) - goto cascade; - - /* Now look for the bulk of the previous work results, they will come - * in a batch following the first data. */ - cgtime(&tv_now); - ms_diff = BF1WAIT - ms_tdiff(&tv_now, &info->tv_start); - if (unlikely(ms_diff < 10)) - ms_diff = 10; - usb_read_once_timeout_cancellable(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); - info->tot += amount; - }; - - if (unlikely(thr->work_restart)) - goto cascade; - - /* Send work */ - usb_write(bitfury, buf, 45, &amount, C_BF1_REQWORK); - cgtime(&info->tv_start); - /* Get response acknowledging work */ - usb_read(bitfury, buf, BF1MSGSIZE, &amount, C_BF1_GETWORK); - - /* Only happens on startup */ - if (unlikely(!info->prevwork[BF1ARRAY_SIZE])) - goto cascade; - - /* Search for what work the nonce matches in order of likelihood. Last - * entry is end of result marker. */ - for (i = 0; i < info->tot - BF1MSGSIZE; i += BF1MSGSIZE) { - uint32_t nonce; - int j; - - /* Ignore state & switched data in results for now. */ - memcpy(&nonce, info->buf + i + 3, 4); - nonce = decnonce(nonce); - for (j = 0; j < BF1ARRAY_SIZE; j++) { - if (bitfury_checkresults(thr, info->prevwork[j], nonce)) { - info->nonces++; - break; - } - } - } - - info->tot = 0; - free_work(info->prevwork[BF1ARRAY_SIZE]); -cascade: - for (i = BF1ARRAY_SIZE; i > 0; i--) - info->prevwork[i] = info->prevwork[i - 1]; - info->prevwork[0] = work; - - 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); - ret = -1; - } - 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; - - version = info->version; - root = api_add_int(root, "Version", &version, true); - 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; -} - -static void bitfury_init(struct cgpu_info *bitfury) -{ - bitfury_close(bitfury); - bitfury_open(bitfury); - bitfury_reset(bitfury); -} - -static void bitfury_shutdown(struct thr_info *thr) -{ - struct cgpu_info *bitfury = thr->cgpu; - - bitfury_close(bitfury); -} - -/* Currently hardcoded to BF1 devices */ -struct device_drv bitfury_drv = { - .drv_id = DRIVER_bitfury, - .dname = "bitfury", - .name = "BF1", - .drv_detect = bitfury_detect, - .hash_work = &hash_driver_work, - .scanwork = bitfury_scanwork, - .get_api_stats = bitfury_api_stats, - .reinit_device = bitfury_init, - .thread_shutdown = bitfury_shutdown, - .identify_device = bitfury_identify -}; diff --git a/driver-bitfury.h b/driver-bitfury.h deleted file mode 100644 index 07e795f5..00000000 --- a/driver-bitfury.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013 Con Kolivas - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. See COPYING for more details. - */ - -#ifndef BITFURY_H -#define BITFURY_H - -#include "miner.h" -#include "usbutils.h" - -#define BF1ARRAY_SIZE 2 - -struct bitfury_info { - struct cgpu_info *base_cgpu; - uint8_t version; - char product[8]; - uint32_t serial; - struct work *prevwork[BF1ARRAY_SIZE + 1]; - char buf[512]; - int tot; - int nonces; - int total_nonces; - double saved_nonces; - int cycles; - struct timeval tv_start; -}; - -#endif /* BITFURY_H */ diff --git a/driver-hashfast.c b/driver-hashfast.c deleted file mode 100644 index 7549a839..00000000 --- a/driver-hashfast.c +++ /dev/null @@ -1,937 +0,0 @@ -/* - * Copyright 2013 Con Kolivas - * Copyright 2013 Hashfast Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. See COPYING for more details. - */ - -#include "config.h" - -#include - -#include "miner.h" -#include "usbutils.h" - -#include "driver-hashfast.h" - -//////////////////////////////////////////////////////////////////////////////// -// Support for the CRC's used in header (CRC-8) and packet body (CRC-32) -//////////////////////////////////////////////////////////////////////////////// - -#define GP8 0x107 /* x^8 + x^2 + x + 1 */ -#define DI8 0x07 - -static unsigned char crc8_table[256]; /* CRC-8 table */ - -static void hfa_init_crc8(void) -{ - int i,j; - unsigned char crc; - - for (i = 0; i < 256; i++) { - crc = i; - for (j = 0; j < 8; j++) - crc = (crc << 1) ^ ((crc & 0x80) ? DI8 : 0); - crc8_table[i] = crc & 0xFF; - } -} - -static unsigned char hfa_crc8(unsigned char *h) -{ - int i; - unsigned char crc; - - h++; // Preamble not included - for (i = 1, crc = 0xff; i < 7; i++) - crc = crc8_table[crc ^ *h++]; - - return crc; -} - -struct hfa_cmd { - uint8_t cmd; - char *cmd_name; - enum usb_cmds usb_cmd; -}; - -/* Entries in this array need to align with the actual op values specified - * in hf_protocol.h */ -#define C_NULL C_MAX -static const struct hfa_cmd hfa_cmds[] = { - {OP_NULL, "OP_NULL", C_NULL}, // 0 - {OP_ROOT, "OP_ROOT", C_NULL}, - {OP_RESET, "OP_RESET", C_HF_RESET}, - {OP_PLL_CONFIG, "OP_PLL_CONFIG", C_HF_PLL_CONFIG}, - {OP_ADDRESS, "OP_ADDRESS", C_HF_ADDRESS}, - {OP_READDRESS, "OP_READDRESS", C_NULL}, - {OP_HIGHEST, "OP_HIGHEST", C_NULL}, - {OP_BAUD, "OP_BAUD", C_HF_BAUD}, - {OP_UNROOT, "OP_UNROOT", C_NULL}, // 8 - {OP_HASH, "OP_HASH", C_HF_HASH}, - {OP_NONCE, "OP_NONCE", C_HF_NONCE}, - {OP_ABORT, "OP_ABORT", C_HF_ABORT}, - {OP_STATUS, "OP_STATUS", C_HF_STATUS}, - {OP_GPIO, "OP_GPIO", C_NULL}, - {OP_CONFIG, "OP_CONFIG", C_HF_CONFIG}, - {OP_STATISTICS, "OP_STATISTICS", C_HF_STATISTICS}, - {OP_GROUP, "OP_GROUP", C_NULL}, // 16 - {OP_CLOCKGATE, "OP_CLOCKGATE", C_HF_CLOCKGATE}, - - {OP_USB_INIT, "OP_USB_INIT", C_HF_USB_INIT}, // 18 - {OP_GET_TRACE, "OP_GET_TRACE", C_NULL}, - {OP_LOOPBACK_USB, "OP_LOOPBACK_USB", C_NULL}, - {OP_LOOPBACK_UART, "OP_LOOPBACK_UART", C_NULL}, - {OP_DFU, "OP_DFU", C_NULL}, - {OP_USB_SHUTDOWN, "OP_USB_SHUTDOWN", C_NULL}, - {OP_DIE_STATUS, "OP_DIE_STATUS", C_HF_DIE_STATUS}, // 24 - {OP_GWQ_STATUS, "OP_GWQ_STATUS", C_HF_GWQ_STATUS}, - {OP_WORK_RESTART, "OP_WORK_RESTART", C_HF_WORK_RESTART}, - {OP_USB_STATS1, "OP_USB_STATS1", C_NULL}, - {OP_USB_GWQSTATS, "OP_USB_GWQSTATS", C_HF_GWQSTATS} -}; - -#define HF_USB_CMD_OFFSET (128 - 18) -#define HF_USB_CMD(X) (X - HF_USB_CMD_OFFSET) - -/* Send an arbitrary frame, consisting of an 8 byte header and an optional - * packet body. */ - -static bool hfa_send_frame(struct cgpu_info *hashfast, uint8_t opcode, uint16_t hdata, - uint8_t *data, int len) -{ - int tx_length, ret, amount, id = hashfast->device_id; - uint8_t packet[256]; - struct hf_header *p = (struct hf_header *)packet; - - p->preamble = HF_PREAMBLE; - p->operation_code = hfa_cmds[opcode].cmd; - p->chip_address = HF_GWQ_ADDRESS; - p->core_address = 0; - p->hdata = htole16(hdata); - p->data_length = len / 4; - p->crc8 = hfa_crc8(packet); - - if (len) - memcpy(&packet[sizeof(struct hf_header)], data, len); - tx_length = sizeof(struct hf_header) + len; - - ret = usb_write(hashfast, (char *)packet, tx_length, &amount, - hfa_cmds[opcode].usb_cmd); - if (unlikely(ret < 0 || amount != tx_length)) { - applog(LOG_ERR, "HFA %d: hfa_send_frame: USB Send error, ret %d amount %d vs. tx_length %d", - id, ret, amount, tx_length); - return false; - } - return true; -} - -static bool hfa_send_header(struct cgpu_info *hashfast, struct hf_header *h, int cmd) -{ - int amount, ret, len; - - len = sizeof(*h); - ret = usb_write(hashfast, (char *)h, len, &amount, hfa_cmds[cmd].usb_cmd); - if (ret < 0 || amount != len) { - applog(LOG_WARNING, "HFA%d: send_header: %s USB Send error, ret %d amount %d vs. length %d", - hashfast->device_id, hfa_cmds[cmd].cmd_name, ret, amount, len); - return false; - } - return true; -} - -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, reads = 0; - char buf[512]; - char *header; - - /* 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. */ - orig_len = len = sizeof(*h); - do { - - if (++reads > 20) - return false; - - ret = usb_read_timeout(hashfast, buf + ofs, len, &amount, 10, 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 hfa_get_data(struct cgpu_info *hashfast, char *buf, int len4) -{ - int amount, ret, len = len4 * 4; - - ret = usb_read(hashfast, buf, len, &amount, C_HF_GETDATA); - if (ret) - return false; - if (amount != len) { - applog(LOG_WARNING, "HFA %d: get_data: Strange amount returned %d vs. expected %d", - hashfast->device_id, amount, len); - return false; - } - return true; -} - -static bool hfa_reset(struct cgpu_info *hashfast, struct hashfast_info *info) -{ - struct hf_usb_init_header usb_init, *hu = &usb_init; - struct hf_usb_init_base *db; - char buf[1024]; - struct hf_header *h = (struct hf_header *)buf; - uint8_t hcrc; - bool ret; - int i; - - info->hash_clock_rate = 550; // Hash clock rate in Mhz - // Assemble the USB_INIT request - memset(hu, 0, sizeof(*hu)); - hu->preamble = HF_PREAMBLE; - hu->operation_code = OP_USB_INIT; - hu->protocol = PROTOCOL_GLOBAL_WORK_QUEUE; // Protocol to use - hu->hash_clock = info->hash_clock_rate; // Hash clock rate in Mhz - hu->crc8 = hfa_crc8((uint8_t *)hu); - applog(LOG_INFO, "HFA%d: Sending OP_USB_INIT with GWQ protocol specified", - hashfast->device_id); - - if (!hfa_send_header(hashfast, (struct hf_header *)hu, HF_USB_CMD(OP_USB_INIT))) - return false; - - // Check for the correct response. - // We extend the normal timeout - a complete device initialization, including - // bringing power supplies up from standby, etc., can take over a second. - for (i = 0; i < 30; i++) { - ret = hfa_get_header(hashfast, h, &hcrc); - if (ret) - break; - } - if (!ret) { - applog(LOG_WARNING, "HFA %d: OP_USB_INIT failed!", hashfast->device_id); - return false; - } - if (h->crc8 != hcrc) { - applog(LOG_WARNING, "HFA %d: OP_USB_INIT failed! CRC mismatch", hashfast->device_id); - return false; - } - if (h->operation_code != OP_USB_INIT) { - applog(LOG_WARNING, "HFA %d: OP_USB_INIT: Tossing packet, valid but unexpected type", hashfast->device_id); - hfa_get_data(hashfast, buf, h->data_length); - return false; - } - - applog(LOG_DEBUG, "HFA %d: Good reply to OP_USB_INIT", hashfast->device_id); - applog(LOG_DEBUG, "HFA %d: OP_USB_INIT: %d die in chain, %d cores, device_type %d, refclk %d Mhz", - hashfast->device_id, h->chip_address, h->core_address, h->hdata & 0xff, (h->hdata >> 8) & 0xff); - - // Save device configuration - info->asic_count = h->chip_address; - info->core_count = h->core_address; - info->device_type = (uint8_t)h->hdata; - info->ref_frequency = (uint8_t)(h->hdata>>8); - info->hash_sequence_head = 0; - info->hash_sequence_tail = 0; - info->device_sequence_tail = 0; - - // Size in bytes of the core bitmap in bytes - info->core_bitmap_size = (((info->asic_count * info->core_count) + 31) / 32) * 4; - - // Get the usb_init_base structure - if (!hfa_get_data(hashfast, (char *)&info->usb_init_base, U32SIZE(info->usb_init_base))) { - applog(LOG_WARNING, "HFA %d: OP_USB_INIT failed! Failure to get usb_init_base data", - hashfast->device_id); - return false; - } - db = &info->usb_init_base; - applog(LOG_INFO, "HFA %d: firmware_rev: %d.%d", hashfast->device_id, - (db->firmware_rev >> 8) & 0xff, db->firmware_rev & 0xff); - applog(LOG_INFO, "HFA %d: hardware_rev: %d.%d", hashfast->device_id, - (db->hardware_rev >> 8) & 0xff, db->hardware_rev & 0xff); - applog(LOG_INFO, "HFA %d: serial number: %d", hashfast->device_id, - db->serial_number); - applog(LOG_INFO, "HFA %d: hash clockrate: %d Mhz", hashfast->device_id, - db->hash_clockrate); - applog(LOG_INFO, "HFA %d: inflight_target: %d", hashfast->device_id, - db->inflight_target); - applog(LOG_INFO, "HFA %d: sequence_modulus: %d", hashfast->device_id, - db->sequence_modulus); - info->num_sequence = db->sequence_modulus; - - // Now a copy of the config data used - if (!hfa_get_data(hashfast, (char *)&info->config_data, U32SIZE(info->config_data))) { - applog(LOG_WARNING, "HFA %d: OP_USB_INIT failed! Failure to get config_data", - hashfast->device_id); - return false; - } - - // Now the core bitmap - info->core_bitmap = malloc(info->core_bitmap_size); - if (!info->core_bitmap) - quit(1, "Failed to malloc info core bitmap in hfa_reset"); - if (!hfa_get_data(hashfast, (char *)info->core_bitmap, info->core_bitmap_size / 4)) { - applog(LOG_WARNING, "HFA %d: OP_USB_INIT failed! Failure to get core_bitmap", hashfast->device_id); - return false; - } - - return true; -} - -static void hfa_send_shutdown(struct cgpu_info *hashfast) -{ - hfa_send_frame(hashfast, HF_USB_CMD(OP_USB_SHUTDOWN), 0, NULL, 0); -} - -static void hfa_clear_readbuf(struct cgpu_info *hashfast) -{ - int amount, ret; - char buf[512]; - - do { - ret = usb_read(hashfast, buf, 512, &amount, C_HF_CLEAR_READ); - } while (!ret || amount); -} - -static bool hfa_detect_common(struct cgpu_info *hashfast) -{ - struct hashfast_info *info; - bool ret; - - info = calloc(sizeof(struct hashfast_info), 1); - if (!info) - quit(1, "Failed to calloc hashfast_info in hfa_detect_common"); - hashfast->device_data = info; - /* hashfast_reset should fill in details for info */ - ret = hfa_reset(hashfast, info); - if (!ret) { - hfa_send_shutdown(hashfast); - hfa_clear_readbuf(hashfast); - free(info); - hashfast->device_data = NULL; - return false; - } - - // The per-die status array - info->die_status = calloc(info->asic_count, sizeof(struct hf_g1_die_data)); - if (unlikely(!(info->die_status))) - quit(1, "Failed to calloc die_status"); - - // The per-die statistics array - info->die_statistics = calloc(info->asic_count, sizeof(struct hf_long_statistics)); - if (unlikely(!(info->die_statistics))) - quit(1, "Failed to calloc die_statistics"); - - info->works = calloc(sizeof(struct work *), info->num_sequence); - if (!info->works) - quit(1, "Failed to calloc info works in hfa_detect_common"); - - return true; -} - -static bool hfa_initialise(struct cgpu_info *hashfast) -{ - int err; - - if (hashfast->usbinfo.nodev) - return false; - - hfa_clear_readbuf(hashfast); - - err = usb_transfer(hashfast, 0, 9, 1, 0, C_ATMEL_RESET); - if (!err) - err = usb_transfer(hashfast, 0x21, 0x22, 0, 0, C_ATMEL_OPEN); - if (!err) { - uint32_t buf[2]; - - /* Magic sequence to reset device only really needed for windows - * but harmless on linux. */ - buf[0] = 0x80250000; - buf[1] = 0x00000800; - err = usb_transfer_data(hashfast, 0x21, 0x20, 0x0000, 0, buf, - 7, C_ATMEL_INIT); - } - if (err < 0) { - applog(LOG_INFO, "HFA %d: Failed to open with error %s", - hashfast->device_id, libusb_error_name(err)); - } - /* Must have transmitted init sequence sized buffer */ - return (err == 7); -} - -static bool hfa_detect_one_usb(libusb_device *dev, struct usb_find_devices *found) -{ - struct cgpu_info *hashfast; - - hashfast = usb_alloc_cgpu(&hashfast_drv, HASHFAST_MINER_THREADS); - if (!hashfast) - quit(1, "Failed to usb_alloc_cgpu hashfast"); - - if (!usb_init(hashfast, dev, found)) { - hashfast = usb_free_cgpu(hashfast); - return false; - } - - hashfast->usbdev->usb_type = USB_TYPE_STD; - - if (!hfa_initialise(hashfast)) { - hashfast = usb_free_cgpu(hashfast); - return false; - } - - add_cgpu(hashfast); - - return hfa_detect_common(hashfast); -} - -static void hfa_detect(bool hotplug) -{ - /* Set up the CRC tables only once. */ - if (!hotplug) - hfa_init_crc8(); - usb_detect(&hashfast_drv, hfa_detect_one_usb); -} - -static bool hfa_get_packet(struct cgpu_info *hashfast, struct hf_header *h) -{ - uint8_t hcrc; - bool ret; - - ret = hfa_get_header(hashfast, h, &hcrc); - if (unlikely(!ret)) - goto out; - if (unlikely(h->crc8 != hcrc)) { - applog(LOG_WARNING, "HFA %d: Bad CRC %d vs %d, attempting to process anyway", - hashfast->device_id, h->crc8, hcrc); - } - if (h->data_length > 0) - ret = hfa_get_data(hashfast, (char *)(h + 1), h->data_length); - if (unlikely(!ret)) { - applog(LOG_WARNING, "HFA %d: Failed to get data associated with header", - hashfast->device_id); - } - -out: - return ret; -} - -static void hfa_parse_gwq_status(struct cgpu_info *hashfast, struct hashfast_info *info, - struct hf_header *h) -{ - struct hf_gwq_data *g = (struct hf_gwq_data *)(h + 1); - struct work *work; - - applog(LOG_DEBUG, "HFA %d: OP_GWQ_STATUS, device_head %4d tail %4d my tail %4d shed %3d inflight %4d", - hashfast->device_id, g->sequence_head, g->sequence_tail, info->hash_sequence_tail, - g->shed_count, HF_SEQUENCE_DISTANCE(info->hash_sequence_head,g->sequence_tail)); - - mutex_lock(&info->lock); - info->hash_count += g->hash_count; - info->device_sequence_head = g->sequence_head; - info->device_sequence_tail = g->sequence_tail; - info->shed_count = g->shed_count; - /* Free any work that is no longer required */ - while (info->device_sequence_tail != info->hash_sequence_tail) { - if (++info->hash_sequence_tail >= info->num_sequence) - info->hash_sequence_tail = 0; - if (unlikely(!(work = info->works[info->hash_sequence_tail]))) { - applog(LOG_ERR, "HFA %d: Bad work sequence tail", - hashfast->device_id); - hashfast->shutdown = true; - break; - } - applog(LOG_DEBUG, "HFA %d: Completing work on hash_sequence_tail %d", - hashfast->device_id, info->hash_sequence_tail); - free_work(work); - info->works[info->hash_sequence_tail] = NULL; - } - mutex_unlock(&info->lock); -} - -static void hfa_update_die_status(struct cgpu_info *hashfast, struct hashfast_info *info, - struct hf_header *h) -{ - struct hf_g1_die_data *d = (struct hf_g1_die_data *)(h + 1), *ds; - int num_included = (h->data_length * 4) / sizeof(struct hf_g1_die_data); - int i, j; - - float die_temperature; - float core_voltage[6]; - - if (info->device_type == HFD_G1) { - // Copy in the data. They're numbered sequentially from the starting point - ds = info->die_status + h->chip_address; - for (i = 0; i < num_included; i++) - memcpy(ds++, d++, sizeof(struct hf_g1_die_data)); - - for (i = 0, d = &info->die_status[h->chip_address]; i < num_included; i++, d++) { - die_temperature = GN_DIE_TEMPERATURE(d->die.die_temperature); - for (j = 0; j < 6; j++) - core_voltage[j] = GN_CORE_VOLTAGE(d->die.core_voltage[j]); - - applog(LOG_DEBUG, "HFA %d: die %2d: OP_DIE_STATUS Die temp %.2fC vdd's %.2f %.2f %.2f %.2f %.2f %.2f", - hashfast->device_id, h->chip_address + i, die_temperature, - core_voltage[0], core_voltage[1], core_voltage[2], - core_voltage[3], core_voltage[4], core_voltage[5]); - // XXX Convert board phase currents, voltage, temperature - } - } -} - -static void search_for_extra_nonce(struct thr_info *thr, struct work *work, - struct hf_candidate_nonce *n) -{ - uint32_t nonce = n->nonce; - int i; - - /* No function to test with ntime offsets yet */ - if (n->ntime & HF_NTIME_MASK) - return; - for (i = 0; i < 128; i++, nonce++) { - /* We could break out of this early if nonce wraps or if we - * find one correct nonce since the chance of more is extremely - * low but this function will be hit so infrequently we may as - * well test the entire range with the least code. */ - if (test_nonce(work, nonce)) - submit_tested_work(thr, work); - } -} - -static void hfa_parse_nonce(struct thr_info *thr, struct cgpu_info *hashfast, - struct hashfast_info *info, struct hf_header *h) -{ - struct hf_candidate_nonce *n = (struct hf_candidate_nonce *)(h + 1); - int i, num_nonces = h->data_length / U32SIZE(sizeof(struct hf_candidate_nonce)); - - applog(LOG_DEBUG, "HFA %d: OP_NONCE: %2d:, num_nonces %d hdata 0x%04x", - hashfast->device_id, h->chip_address, num_nonces, h->hdata); - for (i = 0; i < num_nonces; i++, n++) { - struct work *work; - - applog(LOG_DEBUG, "HFA %d: OP_NONCE: %2d: %2d: ntime %2d sequence %4d nonce 0x%08x", - hashfast->device_id, h->chip_address, i, n->ntime & HF_NTIME_MASK, n->sequence, n->nonce); - - // Find the job from the sequence number - mutex_lock(&info->lock); - work = info->works[n->sequence]; - mutex_unlock(&info->lock); - - if (unlikely(!work)) { - info->no_matching_work++; - applog(LOG_INFO, "HFA %d: No matching work!", hashfast->device_id); - } else { - applog(LOG_DEBUG, "HFA %d: OP_NONCE: sequence %d: submitting nonce 0x%08x ntime %d", - hashfast->device_id, n->sequence, n->nonce, n->ntime & HF_NTIME_MASK); - if ((n->nonce & 0xffff0000) == 0x42420000) // XXX REMOVE THIS - break; // XXX PHONEY EMULATOR NONCE - submit_noffset_nonce(thr, work, n->nonce, n->ntime & HF_NTIME_MASK); // XXX Return value from submit_nonce is error if set - if (unlikely(n->ntime & HF_NONCE_SEARCH)) { - /* This tells us there is another share in the - * next 128 nonces */ - applog(LOG_DEBUG, "HFA %d: OP_NONCE: SEARCH PROXIMITY EVENT FOUND", - hashfast->device_id); - search_for_extra_nonce(thr, work, n); - } - } - } -} - -static void hfa_update_die_statistics(struct hashfast_info *info, struct hf_header *h) -{ - struct hf_statistics *s = (struct hf_statistics *)(h + 1); - struct hf_long_statistics *l; - - // Accumulate the data - l = info->die_statistics + h->chip_address; - - l->rx_header_crc += s->rx_header_crc; - l->rx_body_crc += s->rx_body_crc; - l->rx_header_timeouts += s->rx_header_timeouts; - l->rx_body_timeouts += s->rx_body_timeouts; - l->core_nonce_fifo_full += s->core_nonce_fifo_full; - l->array_nonce_fifo_full += s->array_nonce_fifo_full; - l->stats_overrun += s->stats_overrun; -} - -static void hfa_update_stats1(struct cgpu_info *hashfast, struct hashfast_info *info, - struct hf_header *h) -{ - struct hf_long_usb_stats1 *s1 = &info->stats1; - struct hf_usb_stats1 *sd = (struct hf_usb_stats1 *)(h + 1); - - s1->usb_rx_preambles += sd->usb_rx_preambles; - s1->usb_rx_receive_byte_errors += sd->usb_rx_receive_byte_errors; - s1->usb_rx_bad_hcrc += sd->usb_rx_bad_hcrc; - - s1->usb_tx_attempts += sd->usb_tx_attempts; - s1->usb_tx_packets += sd->usb_tx_packets; - s1->usb_tx_timeouts += sd->usb_tx_timeouts; - s1->usb_tx_incompletes += sd->usb_tx_incompletes; - s1->usb_tx_endpointstalled += sd->usb_tx_endpointstalled; - s1->usb_tx_disconnected += sd->usb_tx_disconnected; - s1->usb_tx_suspended += sd->usb_tx_suspended; -#if 0 - /* We don't care about UART stats so they're not in our struct */ - s1->uart_tx_queue_dma += sd->uart_tx_queue_dma; - s1->uart_tx_interrupts += sd->uart_tx_interrupts; - - s1->uart_rx_preamble_ints += sd->uart_rx_preamble_ints; - s1->uart_rx_missed_preamble_ints += sd->uart_rx_missed_preamble_ints; - s1->uart_rx_header_done += sd->uart_rx_header_done; - s1->uart_rx_data_done += sd->uart_rx_data_done; - s1->uart_rx_bad_hcrc += sd->uart_rx_bad_hcrc; - s1->uart_rx_bad_dma += sd->uart_rx_bad_dma; - s1->uart_rx_short_dma += sd->uart_rx_short_dma; - s1->uart_rx_buffers_full += sd->uart_rx_buffers_full; -#endif - if (sd->max_tx_buffers > s1->max_tx_buffers) - s1->max_tx_buffers = sd->max_tx_buffers; - if (sd->max_rx_buffers > s1->max_rx_buffers) - s1->max_rx_buffers = sd->max_rx_buffers; - - applog(LOG_DEBUG, "HFA %d: OP_USB_STATS1:", hashfast->device_id); - applog(LOG_DEBUG, " usb_rx_preambles: %6d", sd->usb_rx_preambles); - applog(LOG_DEBUG, " usb_rx_receive_byte_errors: %6d", sd->usb_rx_receive_byte_errors); - applog(LOG_DEBUG, " usb_rx_bad_hcrc: %6d", sd->usb_rx_bad_hcrc); - - applog(LOG_DEBUG, " usb_tx_attempts: %6d", sd->usb_tx_attempts); - applog(LOG_DEBUG, " usb_tx_packets: %6d", sd->usb_tx_packets); - applog(LOG_DEBUG, " usb_tx_timeouts: %6d", sd->usb_tx_timeouts); - applog(LOG_DEBUG, " usb_tx_incompletes: %6d", sd->usb_tx_incompletes); - applog(LOG_DEBUG, " usb_tx_endpointstalled: %6d", sd->usb_tx_endpointstalled); - applog(LOG_DEBUG, " usb_tx_disconnected: %6d", sd->usb_tx_disconnected); - applog(LOG_DEBUG, " usb_tx_suspended: %6d", sd->usb_tx_suspended); -#if 0 - applog(LOG_DEBUG, " uart_tx_queue_dma: %6d", sd->uart_tx_queue_dma); - applog(LOG_DEBUG, " uart_tx_interrupts: %6d", sd->uart_tx_interrupts); - - applog(LOG_DEBUG, " uart_rx_preamble_ints: %6d", sd->uart_rx_preamble_ints); - applog(LOG_DEBUG, " uart_rx_missed_preamble_ints: %6d", sd->uart_rx_missed_preamble_ints); - applog(LOG_DEBUG, " uart_rx_header_done: %6d", sd->uart_rx_header_done); - applog(LOG_DEBUG, " uart_rx_data_done: %6d", sd->uart_rx_data_done); - applog(LOG_DEBUG, " uart_rx_bad_hcrc: %6d", sd->uart_rx_bad_hcrc); - applog(LOG_DEBUG, " uart_rx_bad_dma: %6d", sd->uart_rx_bad_dma); - applog(LOG_DEBUG, " uart_rx_short_dma: %6d", sd->uart_rx_short_dma); - applog(LOG_DEBUG, " uart_rx_buffers_full: %6d", sd->uart_rx_buffers_full); -#endif - applog(LOG_DEBUG, " max_tx_buffers: %6d", sd->max_tx_buffers); - applog(LOG_DEBUG, " max_rx_buffers: %6d", sd->max_rx_buffers); - - } - -static void *hfa_read(void *arg) -{ - struct thr_info *thr = (struct thr_info *)arg; - struct cgpu_info *hashfast = thr->cgpu; - struct hashfast_info *info = hashfast->device_data; - char threadname[24]; - - snprintf(threadname, 24, "hfa_read/%d", hashfast->device_id); - RenameThread(threadname); - - while (likely(!hashfast->shutdown)) { - char buf[512]; - struct hf_header *h = (struct hf_header *)buf; - bool ret = hfa_get_packet(hashfast, h); - - if (unlikely(!ret)) - continue; - - switch (h->operation_code) { - case OP_GWQ_STATUS: - hfa_parse_gwq_status(hashfast, info, h); - break; - case OP_DIE_STATUS: - hfa_update_die_status(hashfast, info, h); - break; - case OP_NONCE: - hfa_parse_nonce(thr, hashfast, info, h); - break; - case OP_STATISTICS: - hfa_update_die_statistics(info, h); - break; - case OP_USB_STATS1: - hfa_update_stats1(hashfast, info, h); - break; - default: - applog(LOG_WARNING, "HFA %d: Unhandled operation code %d", - hashfast->device_id, h->operation_code); - break; - } - } - - return NULL; -} - -static bool hfa_prepare(struct thr_info *thr) -{ - struct cgpu_info *hashfast = thr->cgpu; - struct hashfast_info *info = hashfast->device_data; - struct timeval now; - - mutex_init(&info->lock); - if (pthread_create(&info->read_thr, NULL, hfa_read, (void *)thr)) - quit(1, "Failed to pthread_create read thr in hfa_prepare"); - - cgtime(&now); - get_datestamp(hashfast->init, sizeof(hashfast->init), &now); - - return true; -} - -/* Figure out how many jobs to send. */ -static int hfa_jobs(struct hashfast_info *info) -{ - int ret; - - mutex_lock(&info->lock); - ret = info->usb_init_base.inflight_target - HF_SEQUENCE_DISTANCE(info->hash_sequence_head, info->device_sequence_tail); - /* Place an upper limit on how many jobs to queue to prevent sending - * more work than the device can use after a period of outage. */ - if (ret > info->usb_init_base.inflight_target) - ret = info->usb_init_base.inflight_target; - mutex_unlock(&info->lock); - - return ret; -} - -static int64_t hfa_scanwork(struct thr_info *thr) -{ - struct cgpu_info *hashfast = thr->cgpu; - struct hashfast_info *info = hashfast->device_data; - int64_t hashes; - int jobs, ret; - - if (unlikely(hashfast->usbinfo.nodev)) { - applog(LOG_WARNING, "HFA %d: device disappeared, disabling", - hashfast->device_id); - return -1; - } - - if (unlikely(thr->work_restart)) { -restart: - ret = hfa_send_frame(hashfast, HF_USB_CMD(OP_WORK_RESTART), 0, (uint8_t *)NULL, 0); - if (unlikely(!ret)) { - ret = hfa_reset(hashfast, info); - if (unlikely(!ret)) { - applog(LOG_ERR, "HFA %d: Failed to reset after write failure, disabling", - hashfast->device_id); - return -1; - } - } - } - - jobs = hfa_jobs(info); - - if (!jobs) { - ret = restart_wait(thr, 100); - if (unlikely(!ret)) - goto restart; - jobs = hfa_jobs(info); - } - - while (jobs-- > 0) { - struct hf_hash_usb op_hash_data; - struct work *work; - uint64_t intdiff; - int i, sequence; - uint32_t *p; - - /* This is a blocking function if there's no work */ - work = get_work(thr, thr->id); - - /* Assemble the data frame and send the OP_HASH packet */ - memcpy(op_hash_data.midstate, work->midstate, sizeof(op_hash_data.midstate)); - memcpy(op_hash_data.merkle_residual, work->data + 64, 4); - p = (uint32_t *)(work->data + 64 + 4); - op_hash_data.timestamp = *p++; - op_hash_data.bits = *p++; - op_hash_data.nonce_loops = 0; - - /* Set the number of leading zeroes to look for based on diff. - * Diff 1 = 32, Diff 2 = 33, Diff 4 = 34 etc. */ - intdiff = (uint64_t)work->device_diff; - for (i = 31; intdiff; i++, intdiff >>= 1); - op_hash_data.search_difficulty = i; - if ((sequence = info->hash_sequence_head + 1) >= info->num_sequence) - sequence = 0; - ret = hfa_send_frame(hashfast, OP_HASH, sequence, (uint8_t *)&op_hash_data, sizeof(op_hash_data)); - if (unlikely(!ret)) { - ret = hfa_reset(hashfast, info); - if (unlikely(!ret)) { - applog(LOG_ERR, "HFA %d: Failed to reset after write failure, disabling", - hashfast->device_id); - return -1; - } - } - - mutex_lock(&info->lock); - info->hash_sequence_head = sequence; - info->works[info->hash_sequence_head] = work; - mutex_unlock(&info->lock); - - applog(LOG_DEBUG, "HFA %d: OP_HASH sequence %d search_difficulty %d work_difficulty %g", - hashfast->device_id, info->hash_sequence_head, op_hash_data.search_difficulty, work->work_difficulty); - } - - mutex_lock(&info->lock); - hashes = info->hash_count; - info->hash_count = 0; - mutex_unlock(&info->lock); - - return hashes; -} - -static struct api_data *hfa_api_stats(struct cgpu_info *cgpu) -{ - struct hashfast_info *info = cgpu->device_data; - struct hf_long_usb_stats1 *s1; - struct api_data *root = NULL; - struct hf_usb_init_base *db; - int varint, i; - char buf[64]; - - root = api_add_int(root, "asic count", &info->asic_count, false); - root = api_add_int(root, "core count", &info->core_count, false); - - db = &info->usb_init_base; - sprintf(buf, "%d.%d", (db->firmware_rev >> 8) & 0xff, db->firmware_rev & 0xff); - root = api_add_string(root, "firmware rev", buf, true); - sprintf(buf, "%d.%d", (db->hardware_rev >> 8) & 0xff, db->hardware_rev & 0xff); - root = api_add_string(root, "hardware rev", buf, true); - varint = db->serial_number; - root = api_add_int(root, "serial number", &varint, true); - varint = db->hash_clockrate; - root = api_add_int(root, "hash clockrate", &varint, true); - varint = db->inflight_target; - root = api_add_int(root, "inflight target", &varint, true); - varint = db->sequence_modulus; - root = api_add_int(root, "sequence modules", &varint, true); - - s1 = &info->stats1; - root = api_add_uint64(root, "rx preambles", &s1->usb_rx_preambles, false); - root = api_add_uint64(root, "rx rcv byte err", &s1->usb_rx_receive_byte_errors, false); - root = api_add_uint64(root, "rx bad hcrc", &s1->usb_rx_bad_hcrc, false); - root = api_add_uint64(root, "tx attempts", &s1->usb_tx_attempts, false); - root = api_add_uint64(root, "tx packets", &s1->usb_tx_packets, false); - root = api_add_uint64(root, "tx incompletes", &s1->usb_tx_incompletes, false); - root = api_add_uint64(root, "tx ep stalled", &s1->usb_tx_endpointstalled, false); - root = api_add_uint64(root, "tx disconnect", &s1->usb_tx_disconnected, false); - root = api_add_uint64(root, "tx suspend", &s1->usb_tx_suspended, false); - varint = s1->max_tx_buffers; - root = api_add_int(root, "max tx buf", &varint, true); - varint = s1->max_rx_buffers; - root = api_add_int(root, "max rx buf", &varint, true); - - for (i = 0; i < info->asic_count; i++) { - struct hf_long_statistics *l = &info->die_statistics[i]; - struct hf_g1_die_data *d = &info->die_status[i]; - double die_temp, core_voltage; - int j; - - root = api_add_int(root, "Core", &i, true); - die_temp = GN_DIE_TEMPERATURE(d->die.die_temperature); - root = api_add_double(root, "die temperature", &die_temp, true); - for (j = 0; j < 6; j++) { - core_voltage = GN_CORE_VOLTAGE(d->die.core_voltage[j]); - sprintf(buf, "%d: %.2f", j, core_voltage); - root = api_add_string(root, "core voltage", buf, true); - } - root = api_add_uint64(root, "rx header crc", &l->rx_header_crc, false); - root = api_add_uint64(root, "rx body crc", &l->rx_body_crc, false); - root = api_add_uint64(root, "rx header to", &l->rx_header_timeouts, false); - root = api_add_uint64(root, "rx body to", &l->rx_body_timeouts, false); - root = api_add_uint64(root, "cn fifo full", &l->core_nonce_fifo_full, false); - root = api_add_uint64(root, "an fifo full", &l->array_nonce_fifo_full, false); - root = api_add_uint64(root, "stats overrun", &l->stats_overrun, false); - } - - return root; -} - -static void hfa_statline_before(char *buf, size_t bufsiz, struct cgpu_info *hashfast) -{ - struct hashfast_info *info = hashfast->device_data; - double max_temp, max_volt; - struct hf_g1_die_data *d; - int i; - - max_temp = max_volt = 0.0; - - for (i = 0; i < info->asic_count; i++) { - double temp; - int j; - - d = &info->die_status[i]; - temp = GN_DIE_TEMPERATURE(d->die.die_temperature); - if (temp > max_temp) - max_temp = temp; - for (j = 0; j < 6; j++) { - double volt = GN_CORE_VOLTAGE(d->die.core_voltage[j]); - - if (volt > max_volt) - max_volt = volt; - } - } - - tailsprintf(buf, bufsiz, " max%3.0fC %3.2fV | ", max_temp, max_volt); -} - -static void hfa_init(struct cgpu_info __maybe_unused *hashfast) -{ -} - -static void hfa_free_all_work(struct hashfast_info *info) -{ - while (info->device_sequence_tail != info->hash_sequence_head) { - struct work *work; - - if (++info->hash_sequence_tail >= info->num_sequence) - info->hash_sequence_tail = 0; - if (unlikely(!(work = info->works[info->hash_sequence_tail]))) - break; - free_work(work); - info->works[info->hash_sequence_tail] = NULL; - } -} - -static void hfa_shutdown(struct thr_info *thr) -{ - struct cgpu_info *hashfast = thr->cgpu; - struct hashfast_info *info = hashfast->device_data; - - hfa_send_shutdown(hashfast); - pthread_join(info->read_thr, NULL); - hfa_free_all_work(info); - hfa_clear_readbuf(hashfast); - free(info->works); - free(info->die_statistics); - free(info->die_status); - free(info); -} - -struct device_drv hashfast_drv = { - .drv_id = DRIVER_hashfast, - .dname = "Hashfast", - .name = "HFA", - .max_diff = 256.0, // Limit max diff to get some nonces back regardless - .drv_detect = hfa_detect, - .thread_prepare = hfa_prepare, - .hash_work = &hash_driver_work, - .scanwork = hfa_scanwork, - .get_api_stats = hfa_api_stats, - .get_statline_before = hfa_statline_before, - .reinit_device = hfa_init, - .thread_shutdown = hfa_shutdown, -}; diff --git a/driver-hashfast.h b/driver-hashfast.h deleted file mode 100644 index 6c8efb25..00000000 --- a/driver-hashfast.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2013 Con Kolivas - * Copyright 2013 Hashfast - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. See COPYING for more details. - */ - -#ifndef HASHFAST_H -#define HASHFAST_H - -#ifdef USE_HASHFAST -#include "miner.h" -#include "elist.h" -#include "hf_protocol.h" - -#define HASHFAST_MINER_THREADS 1 - -// Matching fields for hf_statistics, but large #s for local accumulation, per-die -struct hf_long_statistics { - uint64_t rx_header_crc; // Header CRCs - uint64_t rx_body_crc; // Data CRCs - uint64_t rx_header_timeouts; // Header timeouts - uint64_t rx_body_timeouts; // Data timeouts - uint64_t core_nonce_fifo_full; // Core nonce Q overrun events - uint64_t array_nonce_fifo_full; // System nonce Q overrun events - uint64_t stats_overrun; // Overrun in statistics reporting -}; - -// Matching fields for hf_usb_stats1, but large #s for local accumulation, per device -struct hf_long_usb_stats1 { - // USB incoming - uint64_t usb_rx_preambles; - uint64_t usb_rx_receive_byte_errors; - uint64_t usb_rx_bad_hcrc; - - // USB outgoing - uint64_t usb_tx_attempts; - uint64_t usb_tx_packets; - uint64_t usb_tx_timeouts; - uint64_t usb_tx_incompletes; - uint64_t usb_tx_endpointstalled; - uint64_t usb_tx_disconnected; - uint64_t usb_tx_suspended; -#if 0 - /* We don't care about UART stats */ - // UART transmit - uint64_t uart_tx_queue_dma; - uint64_t uart_tx_interrupts; - - // UART receive - uint64_t uart_rx_preamble_ints; - uint64_t uart_rx_missed_preamble_ints; - uint64_t uart_rx_header_done; - uint64_t uart_rx_data_done; - uint64_t uart_rx_bad_hcrc; - uint64_t uart_rx_bad_dma; - uint64_t uart_rx_short_dma; - uint64_t uart_rx_buffers_full; -#endif - - uint8_t max_tx_buffers; - uint8_t max_rx_buffers; -}; - -struct hashfast_info { - int asic_count; // # of chips in the chain - int core_count; // # of cores per chip - int device_type; // What sort of device this is - int num_sequence; // A power of 2. What the sequence number range is. - int ref_frequency; // Reference clock rate - struct hf_g1_die_data *die_status; // Array of per-die voltage, current, temperature sensor data - struct hf_long_statistics *die_statistics; // Array of per-die error counters - struct hf_long_usb_stats1 stats1; - int hash_clock_rate; // Hash clock rate to use, in Mhz - struct hf_usb_init_base usb_init_base; // USB Base information from USB_INIT - struct hf_config_data config_data; // Configuration data used from USB_INIT - int core_bitmap_size; // in bytes - uint32_t *core_bitmap; // Core OK bitmap test results, run with PLL Bypassed - - pthread_mutex_t lock; - struct work **works; - uint16_t hash_sequence_head; // HOST: The next hash sequence # to be sent - uint16_t hash_sequence_tail; // HOST: Follows device_sequence_tail around to free work - uint16_t device_sequence_head; // DEVICE: The most recent sequence number the device dispatched - uint16_t device_sequence_tail; // DEVICE: The most recently completed job in the device - int64_t hash_count; - uint16_t shed_count; // Dynamic copy of #cores device has shed for thermal control - int no_matching_work; - - pthread_t read_thr; -}; - -#endif /* USE_HASHFAST */ -#endif /* HASHFAST_H */ diff --git a/driver-icarus.c b/driver-icarus.c deleted file mode 100644 index 2e268368..00000000 --- a/driver-icarus.c +++ /dev/null @@ -1,1421 +0,0 @@ -/* - * Copyright 2012-2013 Andrew Smith - * Copyright 2012 Xiangfu - * Copyright 2013 Con Kolivas - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. See COPYING for more details. - */ - -/* - * Those code should be works fine with V2 and V3 bitstream of Icarus. - * Operation: - * No detection implement. - * Input: 64B = 32B midstate + 20B fill bytes + last 12 bytes of block head. - * Return: send back 32bits immediately when Icarus found a valid nonce. - * no query protocol implemented here, if no data send back in ~11.3 - * seconds (full cover time on 32bit nonce range by 380MH/s speed) - * just send another work. - * Notice: - * 1. Icarus will start calculate when you push a work to them, even they - * are busy. - * 2. The 2 FPGAs on Icarus will distribute the job, one will calculate the - * 0 ~ 7FFFFFFF, another one will cover the 80000000 ~ FFFFFFFF. - * 3. It's possible for 2 FPGAs both find valid nonce in the meantime, the 2 - * valid nonce will all be send back. - * 4. Icarus will stop work when: a valid nonce has been found or 32 bits - * nonce range is completely calculated. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" - -#ifdef WIN32 -#include -#endif - -#include "compat.h" -#include "miner.h" -#include "usbutils.h" - -// The serial I/O speed - Linux uses a define 'B115200' in bits/termios.h -#define ICARUS_IO_SPEED 115200 - -// The size of a successful nonce read -#define ICARUS_READ_SIZE 4 - -// Ensure the sizes are correct for the Serial read -#if (ICARUS_READ_SIZE != 4) -#error ICARUS_READ_SIZE must be 4 -#endif -#define ASSERT1(condition) __maybe_unused static char sizeof_uint32_t_must_be_4[(condition)?1:-1] -ASSERT1(sizeof(uint32_t) == 4); - -// TODO: USB? Different calculation? - see usbstats to work it out e.g. 1/2 of normal send time -// or even use that number? 1/2 -// #define ICARUS_READ_TIME(baud) ((double)ICARUS_READ_SIZE * (double)8.0 / (double)(baud)) -// maybe 1ms? -#define ICARUS_READ_TIME(baud) (0.001) - -// USB ms timeout to wait - user specified timeouts are multiples of this -#define ICARUS_WAIT_TIMEOUT 100 -#define ICARUS_CMR2_TIMEOUT 1 - -// Defined in multiples of ICARUS_WAIT_TIMEOUT -// Must of course be greater than ICARUS_READ_COUNT_TIMING/ICARUS_WAIT_TIMEOUT -// There's no need to have this bigger, since the overhead/latency of extra work -// is pretty small once you get beyond a 10s nonce range time and 10s also -// means that nothing slower than 429MH/s can go idle so most icarus devices -// will always mine without idling -#define ICARUS_READ_TIME_LIMIT_MAX 100 - -// In timing mode: Default starting value until an estimate can be obtained -// 5000 ms allows for up to a ~840MH/s device -#define ICARUS_READ_COUNT_TIMING 5000 -#define ICARUS_READ_COUNT_MIN ICARUS_WAIT_TIMEOUT -#define SECTOMS(s) ((int)((s) * 1000)) -// How many ms below the expected completion time to abort work -// extra in case the last read is delayed -#define ICARUS_READ_REDUCE ((int)(ICARUS_WAIT_TIMEOUT * 1.5)) - -// For a standard Icarus REV3 (to 5 places) -// Since this rounds up a the last digit - it is a slight overestimate -// Thus the hash rate will be a VERY slight underestimate -// (by a lot less than the displayed accuracy) -// Minor inaccuracy of these numbers doesn't affect the work done, -// only the displayed MH/s -#define ICARUS_REV3_HASH_TIME 0.0000000026316 -#define LANCELOT_HASH_TIME 0.0000000025000 -#define ASICMINERUSB_HASH_TIME 0.0000000029761 -// TODO: What is it? -#define CAIRNSMORE1_HASH_TIME 0.0000000027000 -// Per FPGA -#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 -// -// Thus we need to estimate 2 things: -// 1) How many hashes were done if the work was aborted -// 2) How high can the timeout be before the Icarus is idle, -// to minimise the number of work items started -// We set 2) to 'the calculated estimate' - ICARUS_READ_REDUCE -// to ensure the estimate ends before idle -// -// The simple calculation used is: -// Tn = Total time in seconds to calculate n hashes -// Hs = seconds per hash -// Xn = number of hashes -// W = code/usb overhead per work -// -// Rough but reasonable estimate: -// Tn = Hs * Xn + W (of the form y = mx + b) -// -// Thus: -// Line of best fit (using least squares) -// -// Hs = (n*Sum(XiTi)-Sum(Xi)*Sum(Ti))/(n*Sum(Xi^2)-Sum(Xi)^2) -// W = Sum(Ti)/n - (Hs*Sum(Xi))/n -// -// N.B. W is less when aborting work since we aren't waiting for the reply -// to be transferred back (ICARUS_READ_TIME) -// Calculating the hashes aborted at n seconds is thus just n/Hs -// (though this is still a slight overestimate due to code delays) -// - -// Both below must be exceeded to complete a set of data -// Minimum how long after the first, the last data point must be -#define HISTORY_SEC 60 -// Minimum how many points a single ICARUS_HISTORY should have -#define MIN_DATA_COUNT 5 -// The value MIN_DATA_COUNT used is doubled each history until it exceeds: -#define MAX_MIN_DATA_COUNT 100 - -static struct timeval history_sec = { HISTORY_SEC, 0 }; - -// Store the last INFO_HISTORY data sets -// [0] = current data, not yet ready to be included as an estimate -// Each new data set throws the last old set off the end thus -// keeping a ongoing average of recent data -#define INFO_HISTORY 10 - -struct ICARUS_HISTORY { - struct timeval finish; - double sumXiTi; - double sumXi; - double sumTi; - double sumXi2; - uint32_t values; - uint32_t hash_count_min; - uint32_t hash_count_max; -}; - -enum timing_mode { MODE_DEFAULT, MODE_SHORT, MODE_LONG, MODE_VALUE }; - -static const char *MODE_DEFAULT_STR = "default"; -static const char *MODE_SHORT_STR = "short"; -static const char *MODE_SHORT_STREQ = "short="; -static const char *MODE_LONG_STR = "long"; -static const char *MODE_LONG_STREQ = "long="; -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 - uint64_t golden_hashes; - struct timeval golden_tv; - - struct ICARUS_HISTORY history[INFO_HISTORY+1]; - uint32_t min_data_count; - - int timeout; - - // seconds per Hash - double Hs; - // ms til we abort - int read_time; - // ms limit for (short=/long=) read_time - int read_time_limit; - - enum timing_mode timing_mode; - bool do_icarus_timing; - - double fullnonce; - int count; - double W; - uint32_t values; - uint64_t hash_count_range; - - // Determine the cost of history processing - // (which will only affect W) - uint64_t history_count; - struct timeval history_time; - - // icarus-options - int baud; - int work_division; - int fpga_count; - uint32_t nonce_mask; - - uint8_t cmr2_speed; - bool speed_next_work; - bool flash_next_work; -}; - -#define ICARUS_MIDSTATE_SIZE 32 -#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]; -}; - -#define END_CONDITION 0x0000ffff - -// Looking for options in --icarus-timing and --icarus-options: -// -// Code increments this each time we start to look at a device -// However, this means that if other devices are checked by -// the Icarus code (e.g. Avalon only as at 20130517) -// they will count in the option offset -// -// This, however, is deterministic so that's OK -// -// If we were to increment after successfully finding an Icarus -// that would be random since an Icarus may fail and thus we'd -// not be able to predict the option order -// -// Devices are checked in the order libusb finds them which is ? -// -static int option_offset = -1; - -/* -#define ICA_BUFSIZ (0x200) - -static void transfer_read(struct cgpu_info *icarus, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, char *buf, int bufsiz, int *amount, enum usb_cmds cmd) -{ - int err; - - err = usb_transfer_read(icarus, request_type, bRequest, wValue, wIndex, buf, bufsiz, amount, cmd); - - applog(LOG_DEBUG, "%s: cgid %d %s got err %d", - icarus->drv->name, icarus->cgminer_id, - usb_cmdname(cmd), err); -} -*/ - -static void _transfer(struct cgpu_info *icarus, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint32_t *data, int siz, enum usb_cmds cmd) -{ - int err; - - err = usb_transfer_data(icarus, request_type, bRequest, wValue, wIndex, data, siz, cmd); - - applog(LOG_DEBUG, "%s: cgid %d %s got err %d", - icarus->drv->name, icarus->cgminer_id, - usb_cmdname(cmd), err); -} - -#define transfer(icarus, request_type, bRequest, wValue, wIndex, cmd) \ - _transfer(icarus, request_type, bRequest, wValue, wIndex, NULL, 0, cmd) - -static void icarus_initialise(struct cgpu_info *icarus, int baud) -{ - struct ICARUS_INFO *info = (struct ICARUS_INFO *)(icarus->device_data); - uint16_t wValue, wIndex; - enum sub_ident ident; - int interface; - - if (icarus->usbinfo.nodev) - return; - - usb_set_cps(icarus, baud / 10); - usb_enable_cps(icarus); - - interface = _usb_interface(icarus, info->intinfo); - ident = usb_ident(icarus); - - switch (ident) { - case IDENT_BLT: - case IDENT_LLT: - case IDENT_CMR1: - case IDENT_CMR2: - // Reset - transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_RESET, - interface, C_RESET); - - if (icarus->usbinfo.nodev) - return; - - // Latency - _usb_ftdi_set_latency(icarus, info->intinfo); - - if (icarus->usbinfo.nodev) - return; - - // Set data control - transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_DATA, FTDI_VALUE_DATA_BLT, - interface, C_SETDATA); - - if (icarus->usbinfo.nodev) - return; - - // default to BLT/LLT 115200 - wValue = FTDI_VALUE_BAUD_BLT; - wIndex = FTDI_INDEX_BAUD_BLT; - - if (ident == IDENT_CMR1 || ident == IDENT_CMR2) { - switch (baud) { - case 115200: - wValue = FTDI_VALUE_BAUD_CMR_115; - wIndex = FTDI_INDEX_BAUD_CMR_115; - break; - case 57600: - wValue = FTDI_VALUE_BAUD_CMR_57; - wIndex = FTDI_INDEX_BAUD_CMR_57; - break; - default: - quit(1, "icarus_intialise() invalid baud (%d) for Cairnsmore1", baud); - break; - } - } - - // Set the baud - transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, wValue, - (wIndex & 0xff00) | interface, C_SETBAUD); - - if (icarus->usbinfo.nodev) - return; - - // Set Modem Control - transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_MODEM, FTDI_VALUE_MODEM, - interface, C_SETMODEM); - - if (icarus->usbinfo.nodev) - return; - - // Set Flow Control - transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_FLOW, FTDI_VALUE_FLOW, - interface, C_SETFLOW); - - if (icarus->usbinfo.nodev) - return; - - // Clear any sent data - transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_PURGE_TX, - interface, C_PURGETX); - - if (icarus->usbinfo.nodev) - return; - - // Clear any received data - transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_PURGE_RX, - interface, C_PURGERX); - break; - case IDENT_ICA: - // Set Data Control - transfer(icarus, PL2303_CTRL_OUT, PL2303_REQUEST_CTRL, PL2303_VALUE_CTRL, - interface, C_SETDATA); - - if (icarus->usbinfo.nodev) - return; - - // Set Line Control - uint32_t ica_data[2] = { PL2303_VALUE_LINE0, PL2303_VALUE_LINE1 }; - _transfer(icarus, PL2303_CTRL_OUT, PL2303_REQUEST_LINE, PL2303_VALUE_LINE, - interface, &ica_data[0], PL2303_VALUE_LINE_SIZE, C_SETLINE); - - if (icarus->usbinfo.nodev) - return; - - // Vendor - transfer(icarus, PL2303_VENDOR_OUT, PL2303_REQUEST_VENDOR, PL2303_VALUE_VENDOR, - interface, C_VENDOR); - break; - case IDENT_AMU: - // Enable the UART - transfer(icarus, CP210X_TYPE_OUT, CP210X_REQUEST_IFC_ENABLE, - CP210X_VALUE_UART_ENABLE, - interface, C_ENABLE_UART); - - if (icarus->usbinfo.nodev) - return; - - // Set data control - transfer(icarus, CP210X_TYPE_OUT, CP210X_REQUEST_DATA, CP210X_VALUE_DATA, - interface, C_SETDATA); - - if (icarus->usbinfo.nodev) - return; - - // Set the baud - uint32_t data = CP210X_DATA_BAUD; - _transfer(icarus, CP210X_TYPE_OUT, CP210X_REQUEST_BAUD, 0, - interface, &data, sizeof(data), C_SETBAUD); - break; - default: - quit(1, "icarus_intialise() called with invalid %s cgid %i ident=%d", - icarus->drv->name, icarus->cgminer_id, ident); - } -} - -static void rev(unsigned char *s, size_t l) -{ - size_t i, j; - unsigned char t; - - for (i = 0, j = l - 1; i < j; i++, j--) { - t = s[i]; - s[i] = s[j]; - s[j] = t; - } -} - -#define ICA_NONCE_ERROR -1 -#define ICA_NONCE_OK 0 -#define ICA_NONCE_RESTART 1 -#define ICA_NONCE_TIMEOUT 2 - -static int icarus_get_nonce(struct cgpu_info *icarus, unsigned char *buf, struct timeval *tv_start, - struct timeval *tv_finish, struct thr_info *thr, int read_time) -{ - struct ICARUS_INFO *info = (struct ICARUS_INFO *)(icarus->device_data); - int err, amt, rc; - - if (icarus->usbinfo.nodev) - return ICA_NONCE_ERROR; - - cgtime(tv_start); - err = usb_read_ii_timeout_cancellable(icarus, info->intinfo, (char *)buf, - ICARUS_READ_SIZE, &amt, read_time, - C_GETRESULTS); - cgtime(tv_finish); - - if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) { - applog(LOG_ERR, "%s%i: Comms error (rerr=%d amt=%d)", icarus->drv->name, - icarus->device_id, err, amt); - dev_error(icarus, REASON_DEV_COMMS_ERROR); - return ICA_NONCE_ERROR; - } - - if (amt >= ICARUS_READ_SIZE) - return ICA_NONCE_OK; - - rc = SECTOMS(tdiff(tv_finish, tv_start)); - if (thr && thr->work_restart) { - applog(LOG_DEBUG, "Icarus Read: Work restart at %d ms", rc); - return ICA_NONCE_RESTART; - } - - if (amt > 0) - applog(LOG_DEBUG, "Icarus Read: Timeout reading for %d ms", rc); - else - applog(LOG_DEBUG, "Icarus Read: No data for %d ms", rc); - return ICA_NONCE_TIMEOUT; -} - -static const char *timing_mode_str(enum timing_mode timing_mode) -{ - switch(timing_mode) { - case MODE_DEFAULT: - return MODE_DEFAULT_STR; - case MODE_SHORT: - return MODE_SHORT_STR; - case MODE_LONG: - return MODE_LONG_STR; - case MODE_VALUE: - return MODE_VALUE_STR; - default: - return MODE_UNKNOWN_STR; - } -} - -static void set_timing_mode(int this_option_offset, struct cgpu_info *icarus) -{ - struct ICARUS_INFO *info = (struct ICARUS_INFO *)(icarus->device_data); - enum sub_ident ident; - double Hs; - char buf[BUFSIZ+1]; - char *ptr, *comma, *eq; - size_t max; - int i; - - if (opt_icarus_timing == NULL) - buf[0] = '\0'; - else { - ptr = opt_icarus_timing; - for (i = 0; i < this_option_offset; i++) { - comma = strchr(ptr, ','); - if (comma == NULL) - break; - ptr = comma + 1; - } - - comma = strchr(ptr, ','); - if (comma == NULL) - max = strlen(ptr); - else - max = comma - ptr; - - if (max > BUFSIZ) - max = BUFSIZ; - strncpy(buf, ptr, max); - buf[max] = '\0'; - } - - ident = usb_ident(icarus); - switch (ident) { - case IDENT_ICA: - info->Hs = ICARUS_REV3_HASH_TIME; - break; - case IDENT_BLT: - case IDENT_LLT: - info->Hs = LANCELOT_HASH_TIME; - break; - case IDENT_AMU: - info->Hs = ASICMINERUSB_HASH_TIME; - break; - case IDENT_CMR1: - info->Hs = CAIRNSMORE1_HASH_TIME; - break; - case IDENT_CMR2: - info->Hs = CAIRNSMORE2_HASH_TIME; - break; - default: - quit(1, "Icarus get_options() called with invalid %s ident=%d", - icarus->drv->name, ident); - } - - info->read_time = 0; - info->read_time_limit = 0; // 0 = no limit - - if (strcasecmp(buf, MODE_SHORT_STR) == 0) { - // short - info->read_time = ICARUS_READ_COUNT_TIMING; - - info->timing_mode = MODE_SHORT; - info->do_icarus_timing = true; - } else if (strncasecmp(buf, MODE_SHORT_STREQ, strlen(MODE_SHORT_STREQ)) == 0) { - // short=limit - info->read_time = ICARUS_READ_COUNT_TIMING; - - info->timing_mode = MODE_SHORT; - info->do_icarus_timing = true; - - info->read_time_limit = atoi(&buf[strlen(MODE_SHORT_STREQ)]); - if (info->read_time_limit < 0) - info->read_time_limit = 0; - if (info->read_time_limit > ICARUS_READ_TIME_LIMIT_MAX) - info->read_time_limit = ICARUS_READ_TIME_LIMIT_MAX; - } else if (strcasecmp(buf, MODE_LONG_STR) == 0) { - // long - info->read_time = ICARUS_READ_COUNT_TIMING; - - info->timing_mode = MODE_LONG; - info->do_icarus_timing = true; - } else if (strncasecmp(buf, MODE_LONG_STREQ, strlen(MODE_LONG_STREQ)) == 0) { - // long=limit - info->read_time = ICARUS_READ_COUNT_TIMING; - - info->timing_mode = MODE_LONG; - info->do_icarus_timing = true; - - info->read_time_limit = atoi(&buf[strlen(MODE_LONG_STREQ)]); - if (info->read_time_limit < 0) - info->read_time_limit = 0; - if (info->read_time_limit > ICARUS_READ_TIME_LIMIT_MAX) - info->read_time_limit = ICARUS_READ_TIME_LIMIT_MAX; - } else if ((Hs = atof(buf)) != 0) { - // ns[=read_time] - info->Hs = Hs / NANOSEC; - info->fullnonce = info->Hs * (((double)0xffffffff) + 1); - - if ((eq = strchr(buf, '=')) != NULL) - info->read_time = atoi(eq+1) * ICARUS_WAIT_TIMEOUT; - - if (info->read_time < ICARUS_READ_COUNT_MIN) - info->read_time = SECTOMS(info->fullnonce) - ICARUS_READ_REDUCE; - - if (unlikely(info->read_time < ICARUS_READ_COUNT_MIN)) - info->read_time = ICARUS_READ_COUNT_MIN; - - info->timing_mode = MODE_VALUE; - info->do_icarus_timing = false; - } else { - // Anything else in buf just uses DEFAULT mode - - info->fullnonce = info->Hs * (((double)0xffffffff) + 1); - - if ((eq = strchr(buf, '=')) != NULL) - info->read_time = atoi(eq+1) * ICARUS_WAIT_TIMEOUT; - - if (info->read_time < ICARUS_READ_COUNT_MIN) - info->read_time = SECTOMS(info->fullnonce) - ICARUS_READ_REDUCE; - - if (unlikely(info->read_time < ICARUS_READ_COUNT_MIN)) - info->read_time = ICARUS_READ_COUNT_MIN; - - info->timing_mode = MODE_DEFAULT; - info->do_icarus_timing = false; - } - - info->min_data_count = MIN_DATA_COUNT; - - // All values are in multiples of ICARUS_WAIT_TIMEOUT - info->read_time_limit *= ICARUS_WAIT_TIMEOUT; - - applog(LOG_DEBUG, "%s: cgid %d Init: mode=%s read_time=%dms limit=%dms Hs=%e", - icarus->drv->name, icarus->cgminer_id, - timing_mode_str(info->timing_mode), - info->read_time, info->read_time_limit, info->Hs); -} - -static uint32_t mask(int work_division) -{ - uint32_t nonce_mask = 0x7fffffff; - - // yes we can calculate these, but this way it's easy to see what they are - switch (work_division) { - case 1: - nonce_mask = 0xffffffff; - break; - case 2: - nonce_mask = 0x7fffffff; - break; - case 4: - nonce_mask = 0x3fffffff; - break; - case 8: - nonce_mask = 0x1fffffff; - break; - default: - quit(1, "Invalid2 icarus-options for work_division (%d) must be 1, 2, 4 or 8", work_division); - } - - return nonce_mask; -} - -static void get_options(int this_option_offset, struct cgpu_info *icarus, int *baud, int *work_division, int *fpga_count) -{ - char buf[BUFSIZ+1]; - char *ptr, *comma, *colon, *colon2; - enum sub_ident ident; - size_t max; - int i, tmp; - - if (opt_icarus_options == NULL) - buf[0] = '\0'; - else { - ptr = opt_icarus_options; - for (i = 0; i < this_option_offset; i++) { - comma = strchr(ptr, ','); - if (comma == NULL) - break; - ptr = comma + 1; - } - - comma = strchr(ptr, ','); - if (comma == NULL) - max = strlen(ptr); - else - max = comma - ptr; - - if (max > BUFSIZ) - max = BUFSIZ; - strncpy(buf, ptr, max); - buf[max] = '\0'; - } - - ident = usb_ident(icarus); - switch (ident) { - case IDENT_ICA: - case IDENT_BLT: - case IDENT_LLT: - *baud = ICARUS_IO_SPEED; - *work_division = 2; - *fpga_count = 2; - break; - case IDENT_AMU: - *baud = ICARUS_IO_SPEED; - *work_division = 1; - *fpga_count = 1; - break; - case IDENT_CMR1: - *baud = ICARUS_IO_SPEED; - *work_division = 2; - *fpga_count = 2; - break; - case IDENT_CMR2: - *baud = ICARUS_IO_SPEED; - *work_division = 1; - *fpga_count = 1; - break; - default: - quit(1, "Icarus get_options() called with invalid %s ident=%d", - icarus->drv->name, ident); - } - - if (*buf) { - colon = strchr(buf, ':'); - if (colon) - *(colon++) = '\0'; - - if (*buf) { - tmp = atoi(buf); - switch (tmp) { - case 115200: - *baud = 115200; - break; - case 57600: - *baud = 57600; - break; - default: - quit(1, "Invalid icarus-options for baud (%s) must be 115200 or 57600", buf); - } - } - - if (colon && *colon) { - colon2 = strchr(colon, ':'); - if (colon2) - *(colon2++) = '\0'; - - if (*colon) { - tmp = atoi(colon); - if (tmp == 1 || tmp == 2 || tmp == 4 || tmp == 8) { - *work_division = tmp; - *fpga_count = tmp; // default to the same - } else { - quit(1, "Invalid icarus-options for work_division (%s) must be 1, 2, 4 or 8", colon); - } - } - - if (colon2 && *colon2) { - tmp = atoi(colon2); - if (tmp > 0 && tmp <= *work_division) - *fpga_count = tmp; - else { - quit(1, "Invalid icarus-options for fpga_count (%s) must be >0 and <=work_division (%d)", colon2, *work_division); - } - } - } - } -} - -static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices *found) -{ - int this_option_offset = ++option_offset; - struct ICARUS_INFO *info; - struct timeval tv_start, tv_finish; - - // Block 171874 nonce = (0xa2870100) = 0x000187a2 - // N.B. golden_ob MUST take less time to calculate - // than the timeout set in icarus_open() - // This one takes ~0.53ms on Rev3 Icarus - const char golden_ob[] = - "4679ba4ec99876bf4bfe086082b40025" - "4df6c356451471139a3afa71e48f544a" - "00000000000000000000000000000000" - "0000000087320b1a1426674f2fa722ce"; - - const char golden_nonce[] = "000187a2"; - const uint32_t golden_nonce_val = 0x000187a2; - unsigned char nonce_bin[ICARUS_READ_SIZE]; - struct ICARUS_WORK workdata; - char *nonce_hex; - int baud, uninitialised_var(work_division), uninitialised_var(fpga_count); - struct cgpu_info *icarus; - 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"); - - icarus = usb_alloc_cgpu(&icarus_drv, 1); - - if (!usb_init(icarus, dev, found)) - goto shin; - - get_options(this_option_offset, icarus, &baud, &work_division, &fpga_count); - - hex2bin((void *)(&workdata), golden_ob, sizeof(workdata)); - - info = (struct ICARUS_INFO *)calloc(1, sizeof(struct ICARUS_INFO)); - if (unlikely(!info)) - quit(1, "Failed to malloc ICARUS_INFO"); - icarus->device_data = (void *)info; - - info->ident = usb_ident(icarus); - switch (info->ident) { - case IDENT_ICA: - case IDENT_BLT: - case IDENT_LLT: - case IDENT_AMU: - case IDENT_CMR1: - 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, 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_ii(icarus, info->intinfo, - (char *)(&workdata), sizeof(workdata), &amount, C_SENDWORK); - - if (err != LIBUSB_SUCCESS || amount != sizeof(workdata)) - continue; - - memset(nonce_bin, 0, sizeof(nonce_bin)); - ret = icarus_get_nonce(icarus, nonce_bin, &tv_start, &tv_finish, NULL, 100); - if (ret != ICA_NONCE_OK) - continue; - - nonce_hex = bin2hex(nonce_bin, sizeof(nonce_bin)); - if (strncmp(nonce_hex, golden_nonce, 8) == 0) - ok = true; - else { - if (tries < 0 && info->ident != IDENT_CMR2) { - applog(LOG_ERR, - "Icarus Detect: " - "Test failed at %s: get %s, should: %s", - icarus->device_path, nonce_hex, golden_nonce); - } - } - free(nonce_hex); - } - - 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; - } - } - } - - 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)) - goto unshin; - - update_usb_stats(icarus); - - 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); - - info->baud = baud; - info->work_division = work_division; - info->fpga_count = fpga_count; - info->nonce_mask = mask(work_division); - - info->golden_hashes = (golden_nonce_val & info->nonce_mask) * fpga_count; - timersub(&tv_finish, &tv_start, &(info->golden_tv)); - - set_timing_mode(this_option_offset, icarus); - - if (info->ident == IDENT_CMR2) { - int 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", - icarus->drv->name, icarus->device_id, i); - continue; - } - - cgtmp->usbinfo.usbstat = USB_NOSTAT; - - intmp = (struct ICARUS_INFO *)malloc(sizeof(struct ICARUS_INFO)); - if (unlikely(!intmp)) - quit(1, "Failed2 to malloc ICARUS_INFO"); - - cgtmp->device_data = (void *)intmp; - - // Initialise everything to match - memcpy(intmp, info, sizeof(struct ICARUS_INFO)); - - intmp->intinfo = i; - - icarus_initialise(cgtmp, baud); - - if (!add_cgpu(cgtmp)) { - usb_uninit(cgtmp); - free(intmp); - continue; - } - - update_usb_stats(cgtmp); - } - } - - return true; - -unshin: - - usb_uninit(icarus); - free(info); - icarus->device_data = NULL; - -shin: - - icarus = usb_free_cgpu(icarus); - - return false; -} - -static void icarus_detect(bool __maybe_unused hotplug) -{ - usb_detect(&icarus_drv, icarus_detect_one); -} - -static bool icarus_prepare(__maybe_unused struct thr_info *thr) -{ -// struct cgpu_info *icarus = thr->cgpu; - - 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_scanwork(struct thr_info *thr) -{ - struct cgpu_info *icarus = thr->cgpu; - struct ICARUS_INFO *info = (struct ICARUS_INFO *)(icarus->device_data); - int ret, err, amount; - unsigned char nonce_bin[ICARUS_READ_SIZE]; - struct ICARUS_WORK workdata; - char *ob_hex; - uint32_t nonce; - int64_t hash_count = 0; - struct timeval tv_start, tv_finish, elapsed; - struct timeval tv_history_start, tv_history_finish; - double Ti, Xi; - int curr_hw_errors, i; - bool was_hw_error; - struct work *work; - - struct ICARUS_HISTORY *history0, *history; - int count; - double Hs, W, fullnonce; - int read_time; - bool limited; - int64_t estimate_hashes; - uint32_t values; - int64_t hash_count_range; - - // Device is gone - if (icarus->usbinfo.nodev) - return -1; - - elapsed.tv_sec = elapsed.tv_usec = 0; - - work = get_work(thr, thr->id); - memset((void *)(&workdata), 0, sizeof(workdata)); - memcpy(&(workdata.midstate), work->midstate, ICARUS_MIDSTATE_SIZE); - memcpy(&(workdata.work), work->data + ICARUS_WORK_DATA_OFFSET, ICARUS_WORK_SIZE); - 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); - - err = usb_write_ii(icarus, info->intinfo, (char *)(&workdata), sizeof(workdata), &amount, C_SENDWORK); - if (err < 0 || amount != sizeof(workdata)) { - applog(LOG_ERR, "%s%i: Comms error (werr=%d amt=%d)", - icarus->drv->name, icarus->device_id, err, amount); - dev_error(icarus, REASON_DEV_COMMS_ERROR); - icarus_initialise(icarus, info->baud); - goto out; - } - - if (opt_debug) { - ob_hex = bin2hex((void *)(&workdata), sizeof(workdata)); - applog(LOG_DEBUG, "%s%d: sent %s", - icarus->drv->name, icarus->device_id, ob_hex); - free(ob_hex); - } - - /* Icarus will return 4 bytes (ICARUS_READ_SIZE) nonces or nothing */ - memset(nonce_bin, 0, sizeof(nonce_bin)); - ret = icarus_get_nonce(icarus, nonce_bin, &tv_start, &tv_finish, thr, info->read_time); - if (ret == ICA_NONCE_ERROR) - goto out; - - work->blk.nonce = 0xffffffff; - - // aborted before becoming idle, get new work - if (ret == ICA_NONCE_TIMEOUT || ret == ICA_NONCE_RESTART) { - timersub(&tv_finish, &tv_start, &elapsed); - - // ONLY up to just when it aborted - // We didn't read a reply so we don't subtract ICARUS_READ_TIME - estimate_hashes = ((double)(elapsed.tv_sec) - + ((double)(elapsed.tv_usec))/((double)1000000)) / info->Hs; - - // If some Serial-USB delay allowed the full nonce range to - // complete it can't have done more than a full nonce - if (unlikely(estimate_hashes > 0xffffffff)) - estimate_hashes = 0xffffffff; - - applog(LOG_DEBUG, "%s%d: no nonce = 0x%08lX hashes (%ld.%06lds)", - icarus->drv->name, icarus->device_id, - (long unsigned int)estimate_hashes, - elapsed.tv_sec, elapsed.tv_usec); - - hash_count = estimate_hashes; - goto out; - } - - memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin)); - nonce = htobe32(nonce); - curr_hw_errors = icarus->hw_errors; - submit_nonce(thr, work, nonce); - was_hw_error = (curr_hw_errors > icarus->hw_errors); - - hash_count = (nonce & info->nonce_mask); - hash_count++; - hash_count *= info->fpga_count; - -#if 0 - // This appears to only return zero nonce values - if (usb_buffer_size(icarus) > 3) { - memcpy((char *)&nonce, icarus->usbdev->buffer, sizeof(nonce_bin)); - nonce = htobe32(nonce); - applog(LOG_WARNING, "%s%d: attempting to submit 2nd nonce = 0x%08lX", - icarus->drv->name, icarus->device_id, - (long unsigned int)nonce); - curr_hw_errors = icarus->hw_errors; - submit_nonce(thr, work, nonce); - was_hw_error = (curr_hw_errors > icarus->hw_errors); - } -#endif - - if (opt_debug || info->do_icarus_timing) - timersub(&tv_finish, &tv_start, &elapsed); - - applog(LOG_DEBUG, "%s%d: nonce = 0x%08x = 0x%08lX hashes (%ld.%06lds)", - icarus->drv->name, icarus->device_id, - nonce, (long unsigned int)hash_count, - elapsed.tv_sec, elapsed.tv_usec); - - // Ignore possible end condition values ... and hw errors - // TODO: set limitations on calculated values depending on the device - // to avoid crap values caused by CPU/Task Switching/Swapping/etc - if (info->do_icarus_timing - && !was_hw_error - && ((nonce & info->nonce_mask) > END_CONDITION) - && ((nonce & info->nonce_mask) < (info->nonce_mask & ~END_CONDITION))) { - cgtime(&tv_history_start); - - history0 = &(info->history[0]); - - if (history0->values == 0) - timeradd(&tv_start, &history_sec, &(history0->finish)); - - Ti = (double)(elapsed.tv_sec) - + ((double)(elapsed.tv_usec))/((double)1000000) - - ((double)ICARUS_READ_TIME(info->baud)); - Xi = (double)hash_count; - history0->sumXiTi += Xi * Ti; - history0->sumXi += Xi; - history0->sumTi += Ti; - history0->sumXi2 += Xi * Xi; - - history0->values++; - - if (history0->hash_count_max < hash_count) - history0->hash_count_max = hash_count; - if (history0->hash_count_min > hash_count || history0->hash_count_min == 0) - history0->hash_count_min = hash_count; - - if (history0->values >= info->min_data_count - && timercmp(&tv_start, &(history0->finish), >)) { - for (i = INFO_HISTORY; i > 0; i--) - memcpy(&(info->history[i]), - &(info->history[i-1]), - sizeof(struct ICARUS_HISTORY)); - - // Initialise history0 to zero for summary calculation - memset(history0, 0, sizeof(struct ICARUS_HISTORY)); - - // We just completed a history data set - // So now recalc read_time based on the whole history thus we will - // initially get more accurate until it completes INFO_HISTORY - // total data sets - count = 0; - for (i = 1 ; i <= INFO_HISTORY; i++) { - history = &(info->history[i]); - if (history->values >= MIN_DATA_COUNT) { - count++; - - history0->sumXiTi += history->sumXiTi; - history0->sumXi += history->sumXi; - history0->sumTi += history->sumTi; - history0->sumXi2 += history->sumXi2; - history0->values += history->values; - - if (history0->hash_count_max < history->hash_count_max) - history0->hash_count_max = history->hash_count_max; - if (history0->hash_count_min > history->hash_count_min || history0->hash_count_min == 0) - history0->hash_count_min = history->hash_count_min; - } - } - - // All history data - Hs = (history0->values*history0->sumXiTi - history0->sumXi*history0->sumTi) - / (history0->values*history0->sumXi2 - history0->sumXi*history0->sumXi); - W = history0->sumTi/history0->values - Hs*history0->sumXi/history0->values; - hash_count_range = history0->hash_count_max - history0->hash_count_min; - values = history0->values; - - // Initialise history0 to zero for next data set - memset(history0, 0, sizeof(struct ICARUS_HISTORY)); - - fullnonce = W + Hs * (((double)0xffffffff) + 1); - read_time = SECTOMS(fullnonce) - ICARUS_READ_REDUCE; - if (info->read_time_limit > 0 && read_time > info->read_time_limit) { - read_time = info->read_time_limit; - limited = true; - } else - limited = false; - - info->Hs = Hs; - info->read_time = read_time; - - info->fullnonce = fullnonce; - info->count = count; - info->W = W; - info->values = values; - info->hash_count_range = hash_count_range; - - if (info->min_data_count < MAX_MIN_DATA_COUNT) - info->min_data_count *= 2; - else if (info->timing_mode == MODE_SHORT) - info->do_icarus_timing = false; - - applog(LOG_WARNING, "%s%d Re-estimate: Hs=%e W=%e read_time=%dms%s fullnonce=%.3fs", - icarus->drv->name, icarus->device_id, Hs, W, read_time, - limited ? " (limited)" : "", fullnonce); - } - info->history_count++; - cgtime(&tv_history_finish); - - timersub(&tv_history_finish, &tv_history_start, &tv_history_finish); - timeradd(&tv_history_finish, &(info->history_time), &(info->history_time)); - } -out: - free_work(work); - return hash_count; -} - -static struct api_data *icarus_api_stats(struct cgpu_info *cgpu) -{ - struct api_data *root = NULL; - struct ICARUS_INFO *info = (struct ICARUS_INFO *)(cgpu->device_data); - - // Warning, access to these is not locked - but we don't really - // care since hashing performance is way more important than - // locking access to displaying API debug 'stats' - // If locking becomes an issue for any of them, use copy_data=true also - root = api_add_int(root, "read_time", &(info->read_time), false); - root = api_add_int(root, "read_time_limit", &(info->read_time_limit), false); - root = api_add_double(root, "fullnonce", &(info->fullnonce), false); - root = api_add_int(root, "count", &(info->count), false); - root = api_add_hs(root, "Hs", &(info->Hs), false); - root = api_add_double(root, "W", &(info->W), false); - root = api_add_uint(root, "total_values", &(info->values), false); - root = api_add_uint64(root, "range", &(info->hash_count_range), false); - root = api_add_uint64(root, "history_count", &(info->history_count), false); - root = api_add_timeval(root, "history_time", &(info->history_time), false); - root = api_add_uint(root, "min_data_count", &(info->min_data_count), false); - root = api_add_uint(root, "timing_values", &(info->history[0].values), false); - root = api_add_const(root, "timing_mode", timing_mode_str(info->timing_mode), false); - root = api_add_bool(root, "is_timing", &(info->do_icarus_timing), false); - root = api_add_int(root, "baud", &(info->baud), false); - root = api_add_int(root, "work_division", &(info->work_division), false); - root = api_add_int(root, "fpga_count", &(info->fpga_count), false); - - 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, - .hash_work = &hash_driver_work, - .get_api_stats = icarus_api_stats, - .get_statline_before = icarus_statline_before, - .set_device = icarus_set, - .identify_device = icarus_identify, - .thread_prepare = icarus_prepare, - .scanwork = icarus_scanwork, - .thread_shutdown = icarus_shutdown, -}; diff --git a/driver-klondike.c b/driver-klondike.c deleted file mode 100644 index a445bf4e..00000000 --- a/driver-klondike.c +++ /dev/null @@ -1,1557 +0,0 @@ -/* - * Copyright 2013 Andrew Smith - * Copyright 2013 Con Kolivas - * Copyright 2013 Chris Savery - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. See COPYING for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" - -#ifdef WIN32 -#include -#endif - -#include "compat.h" -#include "miner.h" -#include "usbutils.h" - -#define K1 "K1" -#define K16 "K16" -#define K64 "K64" - -static const char *msg_detect_send = "DSend"; -static const char *msg_detect_reply = "DReply"; -static const char *msg_send = "Send"; -static const char *msg_reply = "Reply"; - -#define KLN_CMD_ABORT 'A' -#define KLN_CMD_CONFIG 'C' -#define KLN_CMD_ENABLE 'E' -#define KLN_CMD_IDENT 'I' -#define KLN_CMD_NONCE '=' -#define KLN_CMD_STATUS 'S' -#define KLN_CMD_WORK 'W' - -#define KLN_CMD_ENABLE_OFF '0' -#define KLN_CMD_ENABLE_ON '1' - -#define MIDSTATE_BYTES 32 -#define MERKLE_OFFSET 64 -#define MERKLE_BYTES 12 - -#define REPLY_SIZE 15 // adequate for all types of replies -#define MAX_KLINES 1024 // unhandled reply limit -#define REPLY_WAIT_TIME 100 // poll interval for a cmd waiting it's reply -#define CMD_REPLY_RETRIES 8 // how many retries for cmds -#define MAX_WORK_COUNT 4 // for now, must be binary multiple and match firmware -#define TACH_FACTOR 87890 // fan rpm divisor - -#define KLN_KILLWORK_TEMP 53.5 -#define KLN_COOLED_DOWN 45.5 - -/* - * Work older than 5s will already be completed - * FYI it must not be possible to complete 256 work - * items this quickly on a single device - - * thus limited to 219.9GH/s per device - */ -#define OLD_WORK_MS ((int)(5 * 1000)) - -/* - * How many incorrect slave counts to ignore in a row - * 2 means it allows random grabage returned twice - * Until slaves are implemented, this should never occur - * so allowing 2 in a row should ignore random errros - */ -#define KLN_ISS_IGNORE 2 - -/* - * If the queue status hasn't been updated for this long then do it now - * 5GH/s = 859ms per full nonce range - */ -#define LATE_UPDATE_MS ((int)(2.5 * 1000)) - -// If 5 late updates in a row, try to reset the device -#define LATE_UPDATE_LIMIT 5 - -// If the reset fails sleep for 1s -#define LATE_UPDATE_SLEEP_MS 1000 - -// However give up after 8s -#define LATE_UPDATE_NODEV_MS ((int)(8.0 * 1000)) - -struct device_drv klondike_drv; - -typedef struct klondike_header { - uint8_t cmd; - uint8_t dev; - uint8_t buf[REPLY_SIZE-2]; -} HEADER; - -#define K_2(_bytes) ((int)(_bytes[0]) + \ - ((int)(_bytes[1]) << 8)) - -#define K_4(_bytes) ((uint64_t)(_bytes[0]) + \ - ((uint64_t)(_bytes[1]) << 8) + \ - ((uint64_t)(_bytes[2]) << 16) + \ - ((uint64_t)(_bytes[3]) << 24)) - -#define K_SERIAL(_serial) K_4(_serial) -#define K_HASHCOUNT(_hashcount) K_2(_hashcount) -#define K_MAXCOUNT(_maxcount) K_2(_maxcount) -#define K_NONCE(_nonce) K_4(_nonce) -#define K_HASHCLOCK(_hashclock) K_2(_hashclock) - -#define SET_HASHCLOCK(_hashclock, _value) do { \ - (_hashclock)[0] = (uint8_t)((_value) & 0xff); \ - (_hashclock)[1] = (uint8_t)(((_value) >> 8) & 0xff); \ - } while(0) - -#define KSENDHD(_add) (sizeof(uint8_t) + sizeof(uint8_t) + _add) - -typedef struct klondike_id { - uint8_t cmd; - uint8_t dev; - uint8_t version; - uint8_t product[7]; - uint8_t serial[4]; -} IDENTITY; - -typedef struct klondike_status { - uint8_t cmd; - uint8_t dev; - uint8_t state; - uint8_t chipcount; - uint8_t slavecount; - uint8_t workqc; - uint8_t workid; - uint8_t temp; - uint8_t fanspeed; - uint8_t errorcount; - uint8_t hashcount[2]; - uint8_t maxcount[2]; - uint8_t noise; -} WORKSTATUS; - -typedef struct _worktask { - uint8_t cmd; - uint8_t dev; - uint8_t workid; - uint8_t midstate[32]; - uint8_t merkle[12]; -} WORKTASK; - -typedef struct _workresult { - uint8_t cmd; - uint8_t dev; - uint8_t workid; - uint8_t nonce[4]; -} WORKRESULT; - -typedef struct klondike_cfg { - uint8_t cmd; - uint8_t dev; - uint8_t hashclock[2]; - uint8_t temptarget; - uint8_t tempcritical; - uint8_t fantarget; - uint8_t pad2; -} WORKCFG; - -typedef struct kline { - union { - HEADER hd; - IDENTITY id; - WORKSTATUS ws; - WORKTASK wt; - WORKRESULT wr; - WORKCFG cfg; - }; -} KLINE; - -#define zero_kline(_kline) memset((void *)(_kline), 0, sizeof(KLINE)); - -typedef struct device_info { - uint32_t noncecount; - uint32_t nextworkid; - uint16_t lasthashcount; - uint64_t totalhashcount; - uint32_t rangesize; - uint32_t *chipstats; -} DEVINFO; - -typedef struct klist { - struct klist *prev; - struct klist *next; - KLINE kline; - struct timeval tv_when; - int block_seq; - bool ready; - bool working; -} KLIST; - -typedef struct jobque { - int workqc; - struct timeval last_update; - bool overheat; - bool flushed; - int late_update_count; - int late_update_sequential; -} JOBQUE; - -struct klondike_info { - pthread_rwlock_t stat_lock; - struct thr_info replies_thr; - cglock_t klist_lock; - KLIST *used; - KLIST *free; - int kline_count; - int used_count; - int block_seq; - KLIST *status; - DEVINFO *devinfo; - KLIST *cfg; - JOBQUE *jobque; - int noncecount; - uint64_t hashcount; - uint64_t errorcount; - uint64_t noisecount; - int incorrect_slave_sequential; - - // us Delay from USB reply to being processed - double delay_count; - double delay_total; - double delay_min; - double delay_max; - - struct timeval tv_last_nonce_received; - - // Time from recieving one nonce to the next - double nonce_count; - double nonce_total; - double nonce_min; - double nonce_max; - - int wque_size; - int wque_cleared; - - bool initialised; -}; - -static KLIST *new_klist_set(struct cgpu_info *klncgpu) -{ - struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data); - KLIST *klist = NULL; - int i; - - klist = calloc(MAX_KLINES, sizeof(*klist)); - if (!klist) - quit(1, "Failed to calloc klist - when old count=%d", klninfo->kline_count); - - klninfo->kline_count += MAX_KLINES; - - klist[0].prev = NULL; - klist[0].next = &(klist[1]); - for (i = 1; i < MAX_KLINES-1; i++) { - klist[i].prev = &klist[i-1]; - klist[i].next = &klist[i+1]; - } - klist[MAX_KLINES-1].prev = &(klist[MAX_KLINES-2]); - klist[MAX_KLINES-1].next = NULL; - - return klist; -} - -static KLIST *allocate_kitem(struct cgpu_info *klncgpu) -{ - struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data); - KLIST *kitem = NULL; - int ran_out = 0; - char errbuf[1024]; - - cg_wlock(&klninfo->klist_lock); - - if (klninfo->free == NULL) { - ran_out = klninfo->kline_count; - klninfo->free = new_klist_set(klncgpu); - snprintf(errbuf, sizeof(errbuf), - "%s%i: KLINE count exceeded %d, now %d", - klncgpu->drv->name, klncgpu->device_id, - ran_out, klninfo->kline_count); - } - - kitem = klninfo->free; - - klninfo->free = klninfo->free->next; - if (klninfo->free) - klninfo->free->prev = NULL; - - kitem->next = klninfo->used; - kitem->prev = NULL; - if (kitem->next) - kitem->next->prev = kitem; - klninfo->used = kitem; - - kitem->ready = false; - kitem->working = false; - - memset((void *)&(kitem->kline), 0, sizeof(kitem->kline)); - - klninfo->used_count++; - - cg_wunlock(&klninfo->klist_lock); - - if (ran_out > 0) - applog(LOG_WARNING, "%s", errbuf); - - return kitem; -} - -static KLIST *release_kitem(struct cgpu_info *klncgpu, KLIST *kitem) -{ - struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data); - - cg_wlock(&klninfo->klist_lock); - - if (kitem == klninfo->used) - klninfo->used = kitem->next; - - if (kitem->next) - kitem->next->prev = kitem->prev; - if (kitem->prev) - kitem->prev->next = kitem->next; - - kitem->next = klninfo->free; - if (klninfo->free) - klninfo->free->prev = kitem; - - kitem->prev = NULL; - - klninfo->free = kitem; - - klninfo->used_count--; - - cg_wunlock(&klninfo->klist_lock); - - return NULL; -} - -static double cvtKlnToC(uint8_t temp) -{ - double Rt, stein, celsius; - - if (temp == 0) - return 0.0; - - Rt = 1000.0 * 255.0 / (double)temp - 1000.0; - - stein = log(Rt / 2200.0) / 3987.0; - - stein += 1.0 / (double)(25.0 + 273.15); - - celsius = (1.0 / stein) - 273.15; - - // For display of bad data - if (celsius < 0.0) - celsius = 0.0; - if (celsius > 200.0) - celsius = 200.0; - - return celsius; -} - -static int cvtCToKln(double deg) -{ - double Rt, stein, temp; - - if (deg < 0.0) - deg = 0.0; - - stein = 1.0 / (deg + 273.15); - - stein -= 1.0 / (double)(25.0 + 273.15); - - Rt = exp(stein * 3987.0) * 2200.0; - - if (Rt == -1000.0) - Rt++; - - temp = 1000.0 * 256.0 / (Rt + 1000.0); - - if (temp > 255) - temp = 255; - if (temp < 0) - temp = 0; - - return (int)temp; -} - -// Change this to LOG_WARNING if you wish to always see the replies -#define READ_DEBUG LOG_DEBUG - -static void display_kline(struct cgpu_info *klncgpu, KLINE *kline, const char *msg) -{ - char *hexdata; - - switch (kline->hd.cmd) { - case KLN_CMD_NONCE: - applog(READ_DEBUG, - "%s%i:%d %s work [%c] dev=%d workid=%d" - " nonce=0x%08x", - klncgpu->drv->name, klncgpu->device_id, - (int)(kline->wr.dev), msg, kline->wr.cmd, - (int)(kline->wr.dev), - (int)(kline->wr.workid), - (unsigned int)K_NONCE(kline->wr.nonce) - 0xC0); - break; - case KLN_CMD_STATUS: - case KLN_CMD_WORK: - case KLN_CMD_ENABLE: - case KLN_CMD_ABORT: - applog(READ_DEBUG, - "%s%i:%d %s status [%c] dev=%d chips=%d" - " slaves=%d workcq=%d workid=%d temp=%d fan=%d" - " errors=%d hashes=%d max=%d noise=%d", - klncgpu->drv->name, klncgpu->device_id, - (int)(kline->ws.dev), msg, kline->ws.cmd, - (int)(kline->ws.dev), - (int)(kline->ws.chipcount), - (int)(kline->ws.slavecount), - (int)(kline->ws.workqc), - (int)(kline->ws.workid), - (int)(kline->ws.temp), - (int)(kline->ws.fanspeed), - (int)(kline->ws.errorcount), - K_HASHCOUNT(kline->ws.hashcount), - K_MAXCOUNT(kline->ws.maxcount), - (int)(kline->ws.noise)); - break; - case KLN_CMD_CONFIG: - applog(READ_DEBUG, - "%s%i:%d %s config [%c] dev=%d clock=%d" - " temptarget=%d tempcrit=%d fan=%d", - klncgpu->drv->name, klncgpu->device_id, - (int)(kline->cfg.dev), msg, kline->cfg.cmd, - (int)(kline->cfg.dev), - K_HASHCLOCK(kline->cfg.hashclock), - (int)(kline->cfg.temptarget), - (int)(kline->cfg.tempcritical), - (int)(kline->cfg.fantarget)); - break; - case KLN_CMD_IDENT: - applog(READ_DEBUG, - "%s%i:%d %s info [%c] version=0x%02x prod=%.7s" - " serial=0x%08x", - klncgpu->drv->name, klncgpu->device_id, - (int)(kline->hd.dev), msg, kline->hd.cmd, - (int)(kline->id.version), - kline->id.product, - (unsigned int)K_SERIAL(kline->id.serial)); - break; - default: - hexdata = bin2hex((unsigned char *)&(kline->hd.dev), REPLY_SIZE - 1); - applog(LOG_ERR, - "%s%i:%d %s [%c:%s] unknown and ignored", - klncgpu->drv->name, klncgpu->device_id, - (int)(kline->hd.dev), msg, kline->hd.cmd, - hexdata); - free(hexdata); - break; - } -} - -static void display_send_kline(struct cgpu_info *klncgpu, KLINE *kline, const char *msg) -{ - char *hexdata; - - switch (kline->hd.cmd) { - case KLN_CMD_WORK: - applog(READ_DEBUG, - "%s%i:%d %s work [%c] dev=%d workid=0x%02x ...", - klncgpu->drv->name, klncgpu->device_id, - (int)(kline->wt.dev), msg, kline->ws.cmd, - (int)(kline->wt.dev), - (int)(kline->wt.workid)); - break; - case KLN_CMD_CONFIG: - applog(READ_DEBUG, - "%s%i:%d %s config [%c] dev=%d clock=%d" - " temptarget=%d tempcrit=%d fan=%d", - klncgpu->drv->name, klncgpu->device_id, - (int)(kline->cfg.dev), msg, kline->cfg.cmd, - (int)(kline->cfg.dev), - K_HASHCLOCK(kline->cfg.hashclock), - (int)(kline->cfg.temptarget), - (int)(kline->cfg.tempcritical), - (int)(kline->cfg.fantarget)); - break; - case KLN_CMD_IDENT: - case KLN_CMD_STATUS: - case KLN_CMD_ABORT: - applog(READ_DEBUG, - "%s%i:%d %s cmd [%c]", - klncgpu->drv->name, klncgpu->device_id, - (int)(kline->hd.dev), msg, kline->hd.cmd); - break; - case KLN_CMD_ENABLE: - applog(READ_DEBUG, - "%s%i:%d %s enable [%c] enable=%c", - klncgpu->drv->name, klncgpu->device_id, - (int)(kline->hd.dev), msg, kline->hd.cmd, - (char)(kline->hd.buf[0])); - break; - case KLN_CMD_NONCE: - default: - hexdata = bin2hex((unsigned char *)&(kline->hd.dev), REPLY_SIZE - 1); - applog(LOG_ERR, - "%s%i:%d %s [%c:%s] unknown/unexpected and ignored", - klncgpu->drv->name, klncgpu->device_id, - (int)(kline->hd.dev), msg, kline->hd.cmd, - hexdata); - free(hexdata); - break; - } -} - -static bool SendCmd(struct cgpu_info *klncgpu, KLINE *kline, int datalen) -{ - int err, amt, writ; - - if (klncgpu->usbinfo.nodev) - return false; - - display_send_kline(klncgpu, kline, msg_send); - writ = KSENDHD(datalen); - err = usb_write(klncgpu, (char *)kline, writ, &amt, C_REQUESTRESULTS); - if (err < 0 || amt != writ) { - applog(LOG_ERR, "%s%i:%d Cmd:%c Dev:%d, write failed (%d:%d:%d)", - klncgpu->drv->name, klncgpu->device_id, - (int)(kline->hd.dev), - kline->hd.cmd, (int)(kline->hd.dev), - writ, amt, err); - return false; - } - - return true; -} - -static KLIST *GetReply(struct cgpu_info *klncgpu, uint8_t cmd, uint8_t dev) -{ - struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data); - KLIST *kitem; - int retries = CMD_REPLY_RETRIES; - - while (retries-- > 0 && klncgpu->shutdown == false) { - cgsleep_ms(REPLY_WAIT_TIME); - cg_rlock(&klninfo->klist_lock); - kitem = klninfo->used; - while (kitem) { - if (kitem->kline.hd.cmd == cmd && - kitem->kline.hd.dev == dev && - kitem->ready == true && kitem->working == false) { - kitem->working = true; - cg_runlock(&klninfo->klist_lock); - return kitem; - } - kitem = kitem->next; - } - cg_runlock(&klninfo->klist_lock); - } - return NULL; -} - -static KLIST *SendCmdGetReply(struct cgpu_info *klncgpu, KLINE *kline, int datalen) -{ - if (!SendCmd(klncgpu, kline, datalen)) - return NULL; - - return GetReply(klncgpu, kline->hd.cmd, kline->hd.dev); -} - -static bool klondike_get_stats(struct cgpu_info *klncgpu) -{ - struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data); - KLIST *kitem; - KLINE kline; - int slaves, dev; - - if (klncgpu->usbinfo.nodev || klninfo->status == NULL) - return false; - - applog(LOG_DEBUG, "%s%i: getting status", - klncgpu->drv->name, klncgpu->device_id); - - rd_lock(&(klninfo->stat_lock)); - slaves = klninfo->status[0].kline.ws.slavecount; - rd_unlock(&(klninfo->stat_lock)); - - // loop thru devices and get status for each - for (dev = 0; dev <= slaves; dev++) { - zero_kline(&kline); - kline.hd.cmd = KLN_CMD_STATUS; - kline.hd.dev = dev; - kitem = SendCmdGetReply(klncgpu, &kline, 0); - if (kitem != NULL) { - wr_lock(&(klninfo->stat_lock)); - memcpy((void *)(&(klninfo->status[dev])), - (void *)kitem, - sizeof(klninfo->status[dev])); - wr_unlock(&(klninfo->stat_lock)); - kitem = release_kitem(klncgpu, kitem); - } else { - applog(LOG_ERR, "%s%i:%d failed to update stats", - klncgpu->drv->name, klncgpu->device_id, dev); - } - } - return true; -} - -// TODO: this only enables the master (no slaves) -static bool kln_enable(struct cgpu_info *klncgpu) -{ - KLIST *kitem; - KLINE kline; - int tries = 2; - bool ok = false; - - zero_kline(&kline); - kline.hd.cmd = KLN_CMD_ENABLE; - kline.hd.dev = 0; - kline.hd.buf[0] = KLN_CMD_ENABLE_ON; - - while (tries-- > 0) { - kitem = SendCmdGetReply(klncgpu, &kline, 1); - if (kitem) { - kitem = release_kitem(klncgpu, kitem); - ok = true; - break; - } - cgsleep_ms(50); - } - - if (ok) - cgsleep_ms(50); - - return ok; -} - -static void kln_disable(struct cgpu_info *klncgpu, int dev, bool all) -{ - KLINE kline; - int i; - - zero_kline(&kline); - kline.hd.cmd = KLN_CMD_ENABLE; - kline.hd.buf[0] = KLN_CMD_ENABLE_OFF; - for (i = (all ? 0 : dev); i <= dev; i++) { - kline.hd.dev = i; - SendCmd(klncgpu, &kline, KSENDHD(1)); - } -} - -static bool klondike_init(struct cgpu_info *klncgpu) -{ - struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data); - KLIST *kitem; - KLINE kline; - int slaves, dev; - - klninfo->initialised = false; - - zero_kline(&kline); - kline.hd.cmd = KLN_CMD_STATUS; - kline.hd.dev = 0; - kitem = SendCmdGetReply(klncgpu, &kline, 0); - if (kitem == NULL) - return false; - - slaves = kitem->kline.ws.slavecount; - if (klninfo->status == NULL) { - applog(LOG_DEBUG, "%s%i: initializing data", - klncgpu->drv->name, klncgpu->device_id); - - // alloc space for status, devinfo, cfg and jobque for master and slaves - klninfo->status = calloc(slaves+1, sizeof(*(klninfo->status))); - if (unlikely(!klninfo->status)) - quit(1, "Failed to calloc status array in klondke_get_stats"); - klninfo->devinfo = calloc(slaves+1, sizeof(*(klninfo->devinfo))); - if (unlikely(!klninfo->devinfo)) - quit(1, "Failed to calloc devinfo array in klondke_get_stats"); - klninfo->cfg = calloc(slaves+1, sizeof(*(klninfo->cfg))); - if (unlikely(!klninfo->cfg)) - quit(1, "Failed to calloc cfg array in klondke_get_stats"); - klninfo->jobque = calloc(slaves+1, sizeof(*(klninfo->jobque))); - if (unlikely(!klninfo->jobque)) - quit(1, "Failed to calloc jobque array in klondke_get_stats"); - } - - memcpy((void *)(&(klninfo->status[0])), (void *)kitem, sizeof(klninfo->status[0])); - kitem = release_kitem(klncgpu, kitem); - - // zero init triggers read back only - zero_kline(&kline); - kline.cfg.cmd = KLN_CMD_CONFIG; - - int size = 2; - - // boundaries are checked by device, with valid values returned - if (opt_klondike_options != NULL) { - int hashclock; - double temptarget; - - sscanf(opt_klondike_options, "%d:%lf", &hashclock, &temptarget); - SET_HASHCLOCK(kline.cfg.hashclock, hashclock); - kline.cfg.temptarget = cvtCToKln(temptarget); - kline.cfg.tempcritical = 0; // hard code for old firmware - kline.cfg.fantarget = 0xff; // hard code for old firmware - size = sizeof(kline.cfg) - 2; - } - - for (dev = 0; dev <= slaves; dev++) { - kline.cfg.dev = dev; - kitem = SendCmdGetReply(klncgpu, &kline, size); - if (kitem != NULL) { - memcpy((void *)&(klninfo->cfg[dev]), kitem, sizeof(klninfo->cfg[dev])); - applog(LOG_WARNING, "%s%i:%d config (%d: Clk: %d, T:%.0lf, C:%.0lf, F:%d)", - klncgpu->drv->name, klncgpu->device_id, dev, - dev, K_HASHCLOCK(klninfo->cfg[dev].kline.cfg.hashclock), - cvtKlnToC(klninfo->cfg[dev].kline.cfg.temptarget), - cvtKlnToC(klninfo->cfg[dev].kline.cfg.tempcritical), - (int)100*klninfo->cfg[dev].kline.cfg.fantarget/256); - kitem = release_kitem(klncgpu, kitem); - } - } - klondike_get_stats(klncgpu); - klninfo->initialised = true; - for (dev = 0; dev <= slaves; dev++) { - klninfo->devinfo[dev].rangesize = ((uint64_t)1<<32) / klninfo->status[dev].kline.ws.chipcount; - klninfo->devinfo[dev].chipstats = calloc(klninfo->status[dev].kline.ws.chipcount*2 , sizeof(uint32_t)); - } - - bool ok = kln_enable(klncgpu); - - if (!ok) - applog(LOG_ERR, "%s%i: failed to enable", klncgpu->drv->name, klncgpu->device_id); - - return ok; -} - -static void control_init(struct cgpu_info *klncgpu) -{ - int err, interface; - - if (klncgpu->usbinfo.nodev) - return; - - interface = usb_interface(klncgpu); - - err = usb_transfer(klncgpu, 0, 9, 1, interface, C_RESET); - - applog(LOG_DEBUG, "%s%i: reset got err %d", - klncgpu->drv->name, klncgpu->device_id, err); -} - -static bool klondike_detect_one(struct libusb_device *dev, struct usb_find_devices *found) -{ - struct cgpu_info *klncgpu = usb_alloc_cgpu(&klondike_drv, 1); - struct klondike_info *klninfo = NULL; - KLINE kline; - - if (unlikely(!klncgpu)) - quit(1, "Failed to calloc klncgpu in klondike_detect_one"); - - klninfo = calloc(1, sizeof(*klninfo)); - if (unlikely(!klninfo)) - quit(1, "Failed to calloc klninfo in klondke_detect_one"); - klncgpu->device_data = (void *)klninfo; - - klninfo->free = new_klist_set(klncgpu); - - if (usb_init(klncgpu, dev, found)) { - int sent, recd, err; - KLIST kitem; - int attempts = 0; - - control_init(klncgpu); - - while (attempts++ < 3) { - kline.hd.cmd = KLN_CMD_IDENT; - kline.hd.dev = 0; - display_send_kline(klncgpu, &kline, msg_detect_send); - err = usb_write(klncgpu, (char *)&(kline.hd), 2, &sent, C_REQUESTRESULTS); - if (err < 0 || sent != 2) { - applog(LOG_ERR, "%s (%s) detect write failed (%d:%d)", - klncgpu->drv->dname, - klncgpu->device_path, - sent, err); - } - cgsleep_ms(REPLY_WAIT_TIME*10); - err = usb_read(klncgpu, (char *)&(kitem.kline), REPLY_SIZE, &recd, C_GETRESULTS); - if (err < 0) { - applog(LOG_ERR, "%s (%s) detect read failed (%d:%d)", - klncgpu->drv->dname, - klncgpu->device_path, - recd, err); - } else if (recd < 1) { - applog(LOG_ERR, "%s (%s) detect empty reply (%d)", - klncgpu->drv->dname, - klncgpu->device_path, - recd); - } else if (kitem.kline.hd.cmd == KLN_CMD_IDENT && kitem.kline.hd.dev == 0) { - display_kline(klncgpu, &kitem.kline, msg_detect_reply); - applog(LOG_DEBUG, "%s (%s) detect successful (%d attempt%s)", - klncgpu->drv->dname, - klncgpu->device_path, - attempts, attempts == 1 ? "" : "s"); - if (!add_cgpu(klncgpu)) - break; - update_usb_stats(klncgpu); - applog(LOG_DEBUG, "Klondike cgpu added"); - rwlock_init(&klninfo->stat_lock); - cglock_init(&klninfo->klist_lock); - return true; - } - } - usb_uninit(klncgpu); - } - free(klninfo->free); - free(klninfo); - free(klncgpu); - return false; -} - -static void klondike_detect(bool __maybe_unused hotplug) -{ - usb_detect(&klondike_drv, klondike_detect_one); -} - -static void klondike_identify(__maybe_unused struct cgpu_info *klncgpu) -{ -/* - KLINE kline; - - zero_kline(&kline); - kline.hd.cmd = KLN_CMD_IDENT; - kline.hd.dev = 0; - SendCmdGetReply(klncgpu, &kline, KSENDHD(0)); -*/ -} - -static void klondike_check_nonce(struct cgpu_info *klncgpu, KLIST *kitem) -{ - struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data); - struct work *work, *look, *tmp; - KLINE *kline = &(kitem->kline); - struct timeval tv_now; - double us_diff; - uint32_t nonce = K_NONCE(kline->wr.nonce) - 0xC0; - - applog(LOG_DEBUG, "%s%i:%d FOUND NONCE (%02x:%08x)", - klncgpu->drv->name, klncgpu->device_id, (int)(kline->wr.dev), - kline->wr.workid, (unsigned int)nonce); - - work = NULL; - cgtime(&tv_now); - rd_lock(&(klncgpu->qlock)); - HASH_ITER(hh, klncgpu->queued_work, look, tmp) { - if (ms_tdiff(&tv_now, &(look->tv_stamp)) < OLD_WORK_MS && - (look->subid == (kline->wr.dev*256 + kline->wr.workid))) { - work = look; - break; - } - } - rd_unlock(&(klncgpu->qlock)); - - if (work) { - wr_lock(&(klninfo->stat_lock)); - klninfo->devinfo[kline->wr.dev].noncecount++; - klninfo->noncecount++; - wr_unlock(&(klninfo->stat_lock)); - - applog(LOG_DEBUG, "%s%i:%d SUBMIT NONCE (%02x:%08x)", - klncgpu->drv->name, klncgpu->device_id, (int)(kline->wr.dev), - kline->wr.workid, (unsigned int)nonce); - - cgtime(&tv_now); - bool ok = submit_nonce(klncgpu->thr[0], work, nonce); - - applog(LOG_DEBUG, "%s%i:%d chip stats %d, %08x, %d, %d", - klncgpu->drv->name, klncgpu->device_id, (int)(kline->wr.dev), - kline->wr.dev, (unsigned int)nonce, - klninfo->devinfo[kline->wr.dev].rangesize, - klninfo->status[kline->wr.dev].kline.ws.chipcount); - - klninfo->devinfo[kline->wr.dev].chipstats[(nonce / klninfo->devinfo[kline->wr.dev].rangesize) + (ok ? 0 : klninfo->status[kline->wr.dev].kline.ws.chipcount)]++; - - us_diff = us_tdiff(&tv_now, &(kitem->tv_when)); - if (klninfo->delay_count == 0) { - klninfo->delay_min = us_diff; - klninfo->delay_max = us_diff; - } else { - if (klninfo->delay_min > us_diff) - klninfo->delay_min = us_diff; - if (klninfo->delay_max < us_diff) - klninfo->delay_max = us_diff; - } - klninfo->delay_count++; - klninfo->delay_total += us_diff; - - if (klninfo->nonce_count > 0) { - us_diff = us_tdiff(&(kitem->tv_when), &(klninfo->tv_last_nonce_received)); - if (klninfo->nonce_count == 1) { - klninfo->nonce_min = us_diff; - klninfo->nonce_max = us_diff; - } else { - if (klninfo->nonce_min > us_diff) - klninfo->nonce_min = us_diff; - if (klninfo->nonce_max < us_diff) - klninfo->nonce_max = us_diff; - } - klninfo->nonce_total += us_diff; - } - klninfo->nonce_count++; - - memcpy(&(klninfo->tv_last_nonce_received), &(kitem->tv_when), - sizeof(klninfo->tv_last_nonce_received)); - - return; - } - - applog(LOG_ERR, "%s%i:%d unknown work (%02x:%08x) - ignored", - klncgpu->drv->name, klncgpu->device_id, (int)(kline->wr.dev), - kline->wr.workid, (unsigned int)nonce); - - //inc_hw_errors(klncgpu->thr[0]); -} - -// thread to keep looking for replies -static void *klondike_get_replies(void *userdata) -{ - struct cgpu_info *klncgpu = (struct cgpu_info *)userdata; - struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data); - KLIST *kitem = NULL; - char *hexdata; - int err, recd, slaves, dev, isc; - bool overheat, sent; - - applog(LOG_DEBUG, "%s%i: listening for replies", - klncgpu->drv->name, klncgpu->device_id); - - while (klncgpu->shutdown == false) { - if (klncgpu->usbinfo.nodev) - return NULL; - - if (kitem == NULL) - kitem = allocate_kitem(klncgpu); - else - memset((void *)&(kitem->kline), 0, sizeof(kitem->kline)); - - err = usb_read(klncgpu, (char *)&(kitem->kline), REPLY_SIZE, &recd, C_GETRESULTS); - if (err || recd != REPLY_SIZE) { - if (err != -7) - applog(LOG_ERR, "%s%i: reply err=%d amt=%d", - klncgpu->drv->name, klncgpu->device_id, - err, recd); - } - if (!err && recd == REPLY_SIZE) { - cgtime(&(kitem->tv_when)); - rd_lock(&(klninfo->stat_lock)); - kitem->block_seq = klninfo->block_seq; - rd_unlock(&(klninfo->stat_lock)); - if (opt_log_level <= READ_DEBUG) { - hexdata = bin2hex((unsigned char *)&(kitem->kline.hd.dev), recd-1); - applog(READ_DEBUG, "%s%i:%d reply [%c:%s]", - klncgpu->drv->name, klncgpu->device_id, - (int)(kitem->kline.hd.dev), - kitem->kline.hd.cmd, hexdata); - free(hexdata); - } - - // We can't check this until it's initialised - if (klninfo->initialised) { - rd_lock(&(klninfo->stat_lock)); - slaves = klninfo->status[0].kline.ws.slavecount; - rd_unlock(&(klninfo->stat_lock)); - - if (kitem->kline.hd.dev > slaves) { - applog(LOG_ERR, "%s%i: reply [%c] has invalid dev=%d (max=%d) using 0", - klncgpu->drv->name, klncgpu->device_id, - (char)(kitem->kline.hd.cmd), - (int)(kitem->kline.hd.dev), - slaves); - /* TODO: this is rather problematic if there are slaves - * however without slaves - it should always be zero */ - kitem->kline.hd.dev = 0; - } else { - wr_lock(&(klninfo->stat_lock)); - klninfo->jobque[kitem->kline.hd.dev].late_update_sequential = 0; - wr_unlock(&(klninfo->stat_lock)); - } - } - - switch (kitem->kline.hd.cmd) { - case KLN_CMD_NONCE: - klondike_check_nonce(klncgpu, kitem); - display_kline(klncgpu, &kitem->kline, msg_reply); - break; - case KLN_CMD_WORK: - // We can't do/check this until it's initialised - if (klninfo->initialised) { - dev = kitem->kline.ws.dev; - if (kitem->kline.ws.workqc == 0) { - bool idle = false; - rd_lock(&(klninfo->stat_lock)); - if (klninfo->jobque[dev].flushed == false) - idle = true; - slaves = klninfo->status[0].kline.ws.slavecount; - rd_unlock(&(klninfo->stat_lock)); - if (idle) - applog(LOG_WARNING, "%s%i:%d went idle before work was sent", - klncgpu->drv->name, - klncgpu->device_id, - dev); - } - wr_lock(&(klninfo->stat_lock)); - klninfo->jobque[dev].flushed = false; - wr_unlock(&(klninfo->stat_lock)); - } - case KLN_CMD_STATUS: - case KLN_CMD_ABORT: - // We can't do/check this until it's initialised - if (klninfo->initialised) { - isc = 0; - dev = kitem->kline.ws.dev; - wr_lock(&(klninfo->stat_lock)); - klninfo->jobque[dev].workqc = (int)(kitem->kline.ws.workqc); - cgtime(&(klninfo->jobque[dev].last_update)); - slaves = klninfo->status[0].kline.ws.slavecount; - overheat = klninfo->jobque[dev].overheat; - if (dev == 0) { - if (kitem->kline.ws.slavecount != slaves) - isc = ++klninfo->incorrect_slave_sequential; - else - isc = klninfo->incorrect_slave_sequential = 0; - } - wr_unlock(&(klninfo->stat_lock)); - - if (isc) { - applog(LOG_ERR, "%s%i:%d reply [%c] has a diff" - " # of slaves=%d (curr=%d)%s", - klncgpu->drv->name, - klncgpu->device_id, - dev, - (char)(kitem->kline.ws.cmd), - (int)(kitem->kline.ws.slavecount), - slaves, - isc <= KLN_ISS_IGNORE ? "" : - " disabling device"); - if (isc > KLN_ISS_IGNORE) - usb_nodev(klncgpu); - break; - } - - if (!overheat) { - double temp = cvtKlnToC(kitem->kline.ws.temp); - if (temp >= KLN_KILLWORK_TEMP) { - KLINE kline; - - wr_lock(&(klninfo->stat_lock)); - klninfo->jobque[dev].overheat = true; - wr_unlock(&(klninfo->stat_lock)); - - applog(LOG_WARNING, "%s%i:%d Critical overheat (%.0fC)", - klncgpu->drv->name, - klncgpu->device_id, - dev, temp); - - zero_kline(&kline); - kline.hd.cmd = KLN_CMD_ABORT; - kline.hd.dev = dev; - sent = SendCmd(klncgpu, &kline, KSENDHD(0)); - kln_disable(klncgpu, dev, false); - if (!sent) { - applog(LOG_ERR, "%s%i:%d overheat failed to" - " abort work - disabling device", - klncgpu->drv->name, - klncgpu->device_id, - dev); - usb_nodev(klncgpu); - } - } - } - } - case KLN_CMD_ENABLE: - wr_lock(&(klninfo->stat_lock)); - klninfo->errorcount += kitem->kline.ws.errorcount; - klninfo->noisecount += kitem->kline.ws.noise; - wr_unlock(&(klninfo->stat_lock)); - display_kline(klncgpu, &kitem->kline, msg_reply); - kitem->ready = true; - kitem = NULL; - break; - case KLN_CMD_CONFIG: - display_kline(klncgpu, &kitem->kline, msg_reply); - kitem->ready = true; - kitem = NULL; - break; - case KLN_CMD_IDENT: - display_kline(klncgpu, &kitem->kline, msg_reply); - kitem->ready = true; - kitem = NULL; - break; - default: - display_kline(klncgpu, &kitem->kline, msg_reply); - break; - } - } - } - return NULL; -} - -static void klondike_flush_work(struct cgpu_info *klncgpu) -{ - struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data); - KLIST *kitem; - KLINE kline; - int slaves, dev; - - wr_lock(&(klninfo->stat_lock)); - klninfo->block_seq++; - slaves = klninfo->status[0].kline.ws.slavecount; - wr_unlock(&(klninfo->stat_lock)); - - applog(LOG_DEBUG, "%s%i: flushing work", - klncgpu->drv->name, klncgpu->device_id); - zero_kline(&kline); - kline.hd.cmd = KLN_CMD_ABORT; - for (dev = 0; dev <= slaves; dev++) { - kline.hd.dev = dev; - kitem = SendCmdGetReply(klncgpu, &kline, KSENDHD(0)); - if (kitem != NULL) { - wr_lock(&(klninfo->stat_lock)); - memcpy((void *)&(klninfo->status[dev]), - kitem, - sizeof(klninfo->status[dev])); - klninfo->jobque[dev].flushed = true; - wr_unlock(&(klninfo->stat_lock)); - kitem = release_kitem(klncgpu, kitem); - } - } -} - -static bool klondike_thread_prepare(struct thr_info *thr) -{ - struct cgpu_info *klncgpu = thr->cgpu; - struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data); - - if (thr_info_create(&(klninfo->replies_thr), NULL, klondike_get_replies, (void *)klncgpu)) { - applog(LOG_ERR, "%s%i: thread create failed", klncgpu->drv->name, klncgpu->device_id); - return false; - } - pthread_detach(klninfo->replies_thr.pth); - - // let the listening get started - cgsleep_ms(100); - - return klondike_init(klncgpu); -} - -static bool klondike_thread_init(struct thr_info *thr) -{ - struct cgpu_info *klncgpu = thr->cgpu; - - if (klncgpu->usbinfo.nodev) - return false; - - klondike_flush_work(klncgpu); - - return true; -} - -static void klondike_shutdown(struct thr_info *thr) -{ - struct cgpu_info *klncgpu = thr->cgpu; - struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data); - - applog(LOG_DEBUG, "%s%i: shutting down work", - klncgpu->drv->name, klncgpu->device_id); - - kln_disable(klncgpu, klninfo->status[0].kline.ws.slavecount, true); - - klncgpu->shutdown = true; -} - -static void klondike_thread_enable(struct thr_info *thr) -{ - struct cgpu_info *klncgpu = thr->cgpu; - - if (klncgpu->usbinfo.nodev) - return; - -/* - KLINE kline; - - zero_kline(&kline); - kline.hd.cmd = KLN_CMD_ENABLE; - kline.hd.dev = dev; - kline.hd.buf[0] = KLN_CMD_ENABLE_OFF; - kitem = SendCmdGetReply(klncgpu, &kline, KSENDHD(1)); -*/ - -} - -static bool klondike_send_work(struct cgpu_info *klncgpu, int dev, struct work *work) -{ - struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data); - struct work *look, *tmp; - KLINE kline; - struct timeval tv_old; - int wque_size, wque_cleared; - - if (klncgpu->usbinfo.nodev) - return false; - - zero_kline(&kline); - kline.wt.cmd = KLN_CMD_WORK; - kline.wt.dev = dev; - memcpy(kline.wt.midstate, work->midstate, MIDSTATE_BYTES); - memcpy(kline.wt.merkle, work->data + MERKLE_OFFSET, MERKLE_BYTES); - kline.wt.workid = (uint8_t)(klninfo->devinfo[dev].nextworkid++ & 0xFF); - work->subid = dev*256 + kline.wt.workid; - cgtime(&work->tv_stamp); - - if (opt_log_level <= LOG_DEBUG) { - char *hexdata = bin2hex((void *)&kline.wt, sizeof(kline.wt)); - applog(LOG_DEBUG, "WORKDATA: %s", hexdata); - free(hexdata); - } - - applog(LOG_DEBUG, "%s%i:%d sending work (%d:%02x)", - klncgpu->drv->name, klncgpu->device_id, dev, - dev, kline.wt.workid); - KLIST *kitem = SendCmdGetReply(klncgpu, &kline, sizeof(kline.wt)); - if (kitem != NULL) { - wr_lock(&(klninfo->stat_lock)); - memcpy((void *)&(klninfo->status[dev]), kitem, sizeof(klninfo->status[dev])); - wr_unlock(&(klninfo->stat_lock)); - kitem = release_kitem(klncgpu, kitem); - - // remove old work - wque_size = 0; - wque_cleared = 0; - cgtime(&tv_old); - wr_lock(&klncgpu->qlock); - HASH_ITER(hh, klncgpu->queued_work, look, tmp) { - if (ms_tdiff(&tv_old, &(look->tv_stamp)) > OLD_WORK_MS) { - __work_completed(klncgpu, look); - free_work(look); - wque_cleared++; - } else - wque_size++; - } - wr_unlock(&klncgpu->qlock); - - wr_lock(&(klninfo->stat_lock)); - klninfo->wque_size = wque_size; - klninfo->wque_cleared = wque_cleared; - wr_unlock(&(klninfo->stat_lock)); - return true; - } - return false; -} - -static bool klondike_queue_full(struct cgpu_info *klncgpu) -{ - struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data); - struct work *work = NULL; - int dev, queued, slaves, seq, howlong; - struct timeval now; - bool nowork; - - if (klncgpu->shutdown == true) - return true; - - cgtime(&now); - rd_lock(&(klninfo->stat_lock)); - slaves = klninfo->status[0].kline.ws.slavecount; - for (dev = 0; dev <= slaves; dev++) - if (ms_tdiff(&now, &(klninfo->jobque[dev].last_update)) > LATE_UPDATE_MS) { - klninfo->jobque[dev].late_update_count++; - seq = ++klninfo->jobque[dev].late_update_sequential; - rd_unlock(&(klninfo->stat_lock)); - if (seq < LATE_UPDATE_LIMIT) { - applog(LOG_DEBUG, "%s%i:%d late update", - klncgpu->drv->name, klncgpu->device_id, dev); - klondike_get_stats(klncgpu); - goto que; - } else { - applog(LOG_WARNING, "%s%i:%d late update (%d) reached - attempting reset", - klncgpu->drv->name, klncgpu->device_id, - dev, LATE_UPDATE_LIMIT); - control_init(klncgpu); - kln_enable(klncgpu); - klondike_get_stats(klncgpu); - rd_lock(&(klninfo->stat_lock)); - howlong = ms_tdiff(&now, &(klninfo->jobque[dev].last_update)); - if (howlong > LATE_UPDATE_MS) { - rd_unlock(&(klninfo->stat_lock)); - if (howlong > LATE_UPDATE_NODEV_MS) { - applog(LOG_ERR, "%s%i:%d reset failed - dropping device", - klncgpu->drv->name, klncgpu->device_id, dev); - usb_nodev(klncgpu); - } else - cgsleep_ms(LATE_UPDATE_SLEEP_MS); - - return true; - } - break; - } - } - rd_unlock(&(klninfo->stat_lock)); - -que: - - nowork = true; - for (queued = 0; queued < MAX_WORK_COUNT-1; queued++) - for (dev = 0; dev <= slaves; dev++) { -tryagain: - rd_lock(&(klninfo->stat_lock)); - if (klninfo->jobque[dev].overheat) { - double temp = cvtKlnToC(klninfo->status[0].kline.ws.temp); - if ((queued == MAX_WORK_COUNT-2) && - ms_tdiff(&now, &(klninfo->jobque[dev].last_update)) > (LATE_UPDATE_MS/2)) { - rd_unlock(&(klninfo->stat_lock)); - klondike_get_stats(klncgpu); - goto tryagain; - } - if (temp <= KLN_COOLED_DOWN) { - klninfo->jobque[dev].overheat = false; - rd_unlock(&(klninfo->stat_lock)); - applog(LOG_WARNING, "%s%i:%d Overheat recovered (%.0fC)", - klncgpu->drv->name, klncgpu->device_id, - dev, temp); - kln_enable(klncgpu); - goto tryagain; - } else { - rd_unlock(&(klninfo->stat_lock)); - continue; - } - } - - if (klninfo->jobque[dev].workqc <= queued) { - rd_unlock(&(klninfo->stat_lock)); - if (!work) - work = get_queued(klncgpu); - if (unlikely(!work)) - return false; - nowork = false; - if (klondike_send_work(klncgpu, dev, work)) - return false; - } else - rd_unlock(&(klninfo->stat_lock)); - } - - if (nowork) - cgsleep_ms(10); // avoid a hard loop in case we have nothing to do - - return true; -} - -static int64_t klondike_scanwork(struct thr_info *thr) -{ - struct cgpu_info *klncgpu = thr->cgpu; - struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data); - int64_t newhashcount = 0; - int dev, slaves; - - if (klncgpu->usbinfo.nodev) - return -1; - - restart_wait(thr, 200); - if (klninfo->status != NULL) { - rd_lock(&(klninfo->stat_lock)); - slaves = klninfo->status[0].kline.ws.slavecount; - for (dev = 0; dev <= slaves; dev++) { - uint64_t newhashdev = 0, hashcount; - int maxcount; - - hashcount = K_HASHCOUNT(klninfo->status[dev].kline.ws.hashcount); - maxcount = K_MAXCOUNT(klninfo->status[dev].kline.ws.maxcount); - // todo: chg this to check workid for wrapped instead - if (klninfo->devinfo[dev].lasthashcount > hashcount) - newhashdev += maxcount; // hash counter wrapped - newhashdev += hashcount - klninfo->devinfo[dev].lasthashcount; - klninfo->devinfo[dev].lasthashcount = hashcount; - if (maxcount != 0) - klninfo->hashcount += (newhashdev << 32) / maxcount; - } - newhashcount += 0xffffffffull * (uint64_t)klninfo->noncecount; - klninfo->noncecount = 0; - rd_unlock(&(klninfo->stat_lock)); - } - - return newhashcount; -} - - -static void get_klondike_statline_before(char *buf, size_t siz, struct cgpu_info *klncgpu) -{ - struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data); - uint8_t temp = 0xFF; - uint16_t fan = 0; - uint16_t clock = 0; - int dev, slaves; - char tmp[16]; - - if (klninfo->status == NULL) { - blank_get_statline_before(buf, siz, klncgpu); - return; - } - - rd_lock(&(klninfo->stat_lock)); - slaves = klninfo->status[0].kline.ws.slavecount; - for (dev = 0; dev <= slaves; dev++) { - if (klninfo->status[dev].kline.ws.temp < temp) - temp = klninfo->status[dev].kline.ws.temp; - fan += klninfo->cfg[dev].kline.cfg.fantarget; - clock += (uint16_t)K_HASHCLOCK(klninfo->cfg[dev].kline.cfg.hashclock); - } - rd_unlock(&(klninfo->stat_lock)); - fan /= slaves + 1; - fan *= 100/255; - if (fan > 99) // short on screen space - fan = 99; - clock /= slaves + 1; - if (clock > 999) // error - so truncate it - clock = 999; - - snprintf(tmp, sizeof(tmp), "%2.0fC", cvtKlnToC(temp)); - if (strlen(tmp) < 4) - strcat(tmp, " "); - - tailsprintf(buf, siz, "%3dMHz %2d%% %s| ", (int)clock, fan, tmp); -} - -static struct api_data *klondike_api_stats(struct cgpu_info *klncgpu) -{ - struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data); - struct api_data *root = NULL; - char buf[32]; - int dev, slaves; - - if (klninfo->status == NULL) - return NULL; - - rd_lock(&(klninfo->stat_lock)); - slaves = klninfo->status[0].kline.ws.slavecount; - for (dev = 0; dev <= slaves; dev++) { - - float fTemp = cvtKlnToC(klninfo->status[dev].kline.ws.temp); - sprintf(buf, "Temp %d", dev); - root = api_add_temp(root, buf, &fTemp, true); - - double dClk = (double)K_HASHCLOCK(klninfo->cfg[dev].kline.cfg.hashclock); - sprintf(buf, "Clock %d", dev); - root = api_add_freq(root, buf, &dClk, true); - - unsigned int iFan = (unsigned int)100 * klninfo->cfg[dev].kline.cfg.fantarget / 255; - sprintf(buf, "Fan Percent %d", dev); - root = api_add_int(root, buf, (int *)(&iFan), true); - - iFan = 0; - if (klninfo->status[dev].kline.ws.fanspeed > 0) - iFan = (unsigned int)TACH_FACTOR / klninfo->status[dev].kline.ws.fanspeed; - sprintf(buf, "Fan RPM %d", dev); - root = api_add_int(root, buf, (int *)(&iFan), true); - - if (klninfo->devinfo[dev].chipstats != NULL) { - char data[2048]; - char one[32]; - int n; - - sprintf(buf, "Nonces / Chip %d", dev); - data[0] = '\0'; - for (n = 0; n < klninfo->status[dev].kline.ws.chipcount; n++) { - snprintf(one, sizeof(one), "%07d ", klninfo->devinfo[dev].chipstats[n]); - strcat(data, one); - } - root = api_add_string(root, buf, data, true); - - sprintf(buf, "Errors / Chip %d", dev); - data[0] = '\0'; - for (n = 0; n < klninfo->status[dev].kline.ws.chipcount; n++) { - snprintf(one, sizeof(one), "%07d ", klninfo->devinfo[dev].chipstats[n + klninfo->status[dev].kline.ws.chipcount]); - strcat(data, one); - } - root = api_add_string(root, buf, data, true); - } - } - - root = api_add_uint64(root, "Hash Count", &(klninfo->hashcount), true); - root = api_add_uint64(root, "Error Count", &(klninfo->errorcount), true); - root = api_add_uint64(root, "Noise Count", &(klninfo->noisecount), true); - - root = api_add_int(root, "KLine Limit", &(klninfo->kline_count), true); - root = api_add_int(root, "KLine Used", &(klninfo->used_count), true); - - root = api_add_elapsed(root, "KQue Delay Count", &(klninfo->delay_count), true); - root = api_add_elapsed(root, "KQue Delay Total", &(klninfo->delay_total), true); - root = api_add_elapsed(root, "KQue Delay Min", &(klninfo->delay_min), true); - root = api_add_elapsed(root, "KQue Delay Max", &(klninfo->delay_max), true); - double avg; - if (klninfo->delay_count == 0) - avg = 0; - else - avg = klninfo->delay_total / klninfo->delay_count; - root = api_add_diff(root, "KQue Delay Avg", &avg, true); - - root = api_add_elapsed(root, "KQue Nonce Count", &(klninfo->nonce_count), true); - root = api_add_elapsed(root, "KQue Nonce Total", &(klninfo->nonce_total), true); - root = api_add_elapsed(root, "KQue Nonce Min", &(klninfo->nonce_min), true); - root = api_add_elapsed(root, "KQue Nonce Max", &(klninfo->nonce_max), true); - if (klninfo->nonce_count == 0) - avg = 0; - else - avg = klninfo->nonce_total / klninfo->nonce_count; - root = api_add_diff(root, "KQue Nonce Avg", &avg, true); - - root = api_add_int(root, "WQue Size", &(klninfo->wque_size), true); - root = api_add_int(root, "WQue Cleared", &(klninfo->wque_cleared), true); - - rd_unlock(&(klninfo->stat_lock)); - - return root; -} - -struct device_drv klondike_drv = { - .drv_id = DRIVER_klondike, - .dname = "Klondike", - .name = "KLN", - .drv_detect = klondike_detect, - .get_api_stats = klondike_api_stats, - .get_statline_before = get_klondike_statline_before, - .get_stats = klondike_get_stats, - .identify_device = klondike_identify, - .thread_prepare = klondike_thread_prepare, - .thread_init = klondike_thread_init, - .hash_work = hash_queued_work, - .scanwork = klondike_scanwork, - .queue_full = klondike_queue_full, - .flush_work = klondike_flush_work, - .thread_shutdown = klondike_shutdown, - .thread_enable = klondike_thread_enable -}; diff --git a/driver-knc-spi-fpga.c b/driver-knc-spi-fpga.c deleted file mode 100644 index f8488569..00000000 --- a/driver-knc-spi-fpga.c +++ /dev/null @@ -1,762 +0,0 @@ -/* - * cgminer driver for KnCminer devices - * - * Copyright 2013 Con Kolivas - * Copyright 2013 KnCminer - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. See COPYING for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "logging.h" -#include "miner.h" - -#define MAX_SPIS 1 -#define MAX_BYTES_IN_SPI_XSFER 4096 -/* /dev/spidevB.C, where B = bus, C = chipselect */ -#define SPI_DEVICE_TEMPLATE "/dev/spidev%d.%d" -#define SPI_MODE (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH) -#define SPI_BITS_PER_WORD 32 -#define SPI_MAX_SPEED 3000000 -#define SPI_DELAY_USECS 0 -/* Max number of ASICs permitted on one SPI device */ -#define MAX_ASICS 6 - -/* How many hardware errors in a row before disabling the core */ -#define HW_ERR_LIMIT 10 -#define DISA_ERR_LIMIT 3 - -#define MAX_ACTIVE_WORKS (192 * 2 * 6 * 2) - -#define WORK_MIDSTATE_WORDS 8 -#define WORK_DATA_WORDS 3 - -#define WORK_STALE_US 60000000 - -/* Keep core disabled for no longer than 15 minutes */ -#define CORE_DISA_PERIOD_US (15 * 60 * 1000000) - -struct spidev_context { - int fd; - uint32_t speed; - uint16_t delay; - uint8_t mode; - uint8_t bits; -}; - -struct spi_request { -#define CMD_NOP 0 -#define CMD_GET_VERSION 1 -#define CMD_SUBMIT_WORK 2 -#define CMD_FLUSH_QUEUE 3 - -#define WORK_ID_MASK 0x7FFF - -#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) - uint32_t cmd :4; - uint32_t rsvd :1; /* set to zero */ - uint32_t queue_id :12; - uint32_t work_id :15; -#else - uint32_t work_id :15; - uint32_t queue_id :12; - uint32_t rsvd :1; /* set to zero */ - uint32_t cmd :4; -#endif - uint32_t midstate[WORK_MIDSTATE_WORDS]; - uint32_t data[WORK_DATA_WORDS]; -}; - -struct spi_response { -#define RESPONSE_TYPE_NOP 0 -#define RESPONSE_TYPE_NONCE_FOUND 1 -#define RESPONSE_TYPE_WORK_DONE 2 -#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) - uint32_t type :2; - uint32_t asic :3; - uint32_t queue_id :12; - uint32_t work_id :15; -#else - uint32_t work_id :15; - uint32_t queue_id :12; - uint32_t asic :3; - uint32_t type :2; -#endif - uint32_t nonce; - uint32_t core; -}; - -#define MAX_REQUESTS_IN_BATCH ( MAX_BYTES_IN_SPI_XSFER / \ - sizeof(struct spi_request) \ - ) - -static struct spi_request spi_txbuf[MAX_REQUESTS_IN_BATCH]; - -#define MAX_RESPONSES_IN_BATCH ( (sizeof(spi_txbuf) - 12) / \ - sizeof(struct spi_response) \ - ) - -struct spi_rx_t { -#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) - uint32_t rsvd_1 :31; - uint32_t response_queue_full :1; -#else - uint32_t response_queue_full :1; - uint32_t rsvd_1 :31; -#endif -#if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) - uint32_t rsvd_2 :16; - uint32_t works_accepted :16; -#else - uint32_t works_accepted :16; - uint32_t rsvd_2 :16; -#endif - uint32_t rsvd_3; - struct spi_response responses[MAX_RESPONSES_IN_BATCH]; -}; - -static struct spi_rx_t spi_rxbuf; - -struct active_work { - struct work *work; - uint32_t work_id; - struct timeval begin; -}; - -struct core_disa_data { - struct timeval disa_begin; - uint8_t asic; - uint8_t core; -}; - -struct knc_state { - struct spidev_context *ctx; - int devices; - uint32_t salt; - uint32_t next_work_id; - - /* read - last read item, next is at (read + 1) mod BUFSIZE - * write - next write item, last written at (write - 1) mod BUFSIZE - * When buffer is empty, read + 1 == write - * Buffer full condition: read == write - */ - int read_q, write_q; -#define KNC_QUEUED_BUFFER_SIZE (MAX_REQUESTS_IN_BATCH + 1) - struct active_work queued_fifo[KNC_QUEUED_BUFFER_SIZE]; - - int read_a, write_a; -#define KNC_ACTIVE_BUFFER_SIZE (MAX_ACTIVE_WORKS + 1) - struct active_work active_fifo[KNC_ACTIVE_BUFFER_SIZE]; - - uint8_t hwerrs[MAX_ASICS * 256]; - uint8_t disa_cnt[MAX_ASICS * 256]; - uint32_t hwerr_work_id[MAX_ASICS * 256]; - int read_d, write_d; -#define KNC_DISA_CORES_SIZE (MAX_ASICS * 256) - struct core_disa_data disa_cores_fifo[KNC_DISA_CORES_SIZE]; - - pthread_mutex_t lock; -}; - -static inline bool knc_queued_fifo_full(struct knc_state *knc) -{ - return (knc->read_q == knc->write_q); -} - -static inline bool knc_active_fifo_full(struct knc_state *knc) -{ - return (knc->read_a == knc->write_a); -} - -static inline void knc_queued_fifo_inc_idx(int *idx) -{ - if (unlikely(*idx >= ((int)KNC_QUEUED_BUFFER_SIZE - 1))) - *idx = 0; - else - ++(*idx); -} - -static inline void knc_active_fifo_inc_idx(int *idx) -{ - if (unlikely(*idx >= (KNC_ACTIVE_BUFFER_SIZE - 1))) - *idx = 0; - else - ++(*idx); -} - -static inline void knc_disa_cores_fifo_inc_idx(int *idx) -{ - if (unlikely(*idx >= (KNC_DISA_CORES_SIZE - 1))) - *idx = 0; - else - ++(*idx); -} - -/* Find SPI device with index idx, init it */ -static struct spidev_context *spi_new(int idx) -{ - struct spidev_context *ctx; - char dev_fname[PATH_MAX]; - - if (NULL == (ctx = malloc(sizeof(struct spidev_context)))) { - applog(LOG_ERR, "KnC spi: Out of memory"); - goto l_exit_error; - } - ctx->mode = SPI_MODE; - ctx->bits = SPI_BITS_PER_WORD; - ctx->speed = SPI_MAX_SPEED; - ctx->delay = SPI_DELAY_USECS; - - ctx->fd = -1; - - sprintf(dev_fname, SPI_DEVICE_TEMPLATE, - idx, /* bus */ - 0 /* chipselect */ - ); - if (0 > (ctx->fd = open(dev_fname, O_RDWR))) { - applog(LOG_ERR, "KnC spi: Can not open SPI device %s: %m", - dev_fname); - goto l_free_exit_error; - } - - /* - * spi mode - */ - if (0 > ioctl(ctx->fd, SPI_IOC_WR_MODE, &ctx->mode)) - goto l_ioctl_error; - if (0 > ioctl(ctx->fd, SPI_IOC_RD_MODE, &ctx->mode)) - goto l_ioctl_error; - - /* - * bits per word - */ - if (0 > ioctl(ctx->fd, SPI_IOC_WR_BITS_PER_WORD, &ctx->bits)) - goto l_ioctl_error; - if (0 > ioctl(ctx->fd, SPI_IOC_RD_BITS_PER_WORD, &ctx->bits)) - goto l_ioctl_error; - - /* - * max speed hz - */ - if (0 > ioctl(ctx->fd, SPI_IOC_WR_MAX_SPEED_HZ, &ctx->speed)) - goto l_ioctl_error; - if (0 > ioctl(ctx->fd, SPI_IOC_RD_MAX_SPEED_HZ, &ctx->speed)) - goto l_ioctl_error; - - applog(LOG_INFO, "KnC spi: device %s uses mode %hhu, bits %hhu, speed %u", - dev_fname, ctx->mode, ctx->bits, ctx->speed); - - return ctx; - -l_ioctl_error: - applog(LOG_ERR, "KnC spi: ioctl error on SPI device %s: %m", dev_fname); - close(ctx->fd); -l_free_exit_error: - free(ctx); -l_exit_error: - return NULL; -} - -static void spi_free(struct spidev_context *ctx) -{ - if (NULL == ctx) - return; - - close(ctx->fd); - free(ctx); -} - -static int spi_transfer(struct spidev_context *ctx, uint8_t *txbuf, - uint8_t *rxbuf, int len) -{ - struct spi_ioc_transfer xfr; - int ret; - - memset(rxbuf, 0xff, len); - - ret = len; - - xfr.tx_buf = (unsigned long)txbuf; - xfr.rx_buf = (unsigned long)rxbuf; - xfr.len = len; - xfr.speed_hz = ctx->speed; - xfr.delay_usecs = ctx->delay; - xfr.bits_per_word = ctx->bits; - xfr.cs_change = 0; - xfr.pad = 0; - - if (1 > (ret = ioctl(ctx->fd, SPI_IOC_MESSAGE(1), &xfr))) - applog(LOG_ERR, "KnC spi xfer: ioctl error on SPI device: %m"); - - return ret; -} - -static void disable_core(uint8_t asic, uint8_t core) -{ - char str[256]; - - snprintf(str, sizeof(str), "i2cset -y 2 0x2%hhu %hhu 0", asic, core); - if (0 != WEXITSTATUS(system(str))) - applog(LOG_ERR, "KnC: system call failed"); -} - -static void enable_core(uint8_t asic, uint8_t core) -{ - char str[256]; - - snprintf(str, sizeof(str), "i2cset -y 2 0x2%hhu %hhu 1", asic, core); - if (0 != WEXITSTATUS(system(str))) - applog(LOG_ERR, "KnC: system call failed"); -} - -static int64_t timediff(const struct timeval *a, const struct timeval *b) -{ - struct timeval diff; - - timersub(a, b, &diff); - - return diff.tv_sec * 1000000 + diff.tv_usec; -} - -static void knc_check_disabled_cores(struct knc_state *knc) -{ - struct core_disa_data *core; - int next_read_d, cidx; - struct timeval now; - int64_t us; - - next_read_d = knc->read_d; - knc_disa_cores_fifo_inc_idx(&next_read_d); - if (next_read_d == knc->write_d) - return; /* queue empty */ - - core = &knc->disa_cores_fifo[next_read_d]; - gettimeofday(&now, NULL); - us = timediff(&now, &core->disa_begin); - if ((us >= 0) && (us < CORE_DISA_PERIOD_US)) - return; /* latest disabled core still not expired */ - - cidx = core->asic * 256 + core->core; - enable_core(core->asic, core->core); - knc->hwerrs[cidx] = 0; - applog(LOG_NOTICE, - "KnC: core %u-%u was enabled back from disabled state", - core->asic, core->core); - knc->read_d = next_read_d; -} - -static void knc_work_from_queue_to_spi(struct knc_state *knc, - struct active_work *q_work, - struct spi_request *spi_req) -{ - uint32_t *buf_from, *buf_to; - int i; - - spi_req->cmd = CMD_SUBMIT_WORK; - spi_req->queue_id = 0; /* at the moment we have one and only queue #0 */ - spi_req->work_id = (knc->next_work_id ^ knc->salt) & WORK_ID_MASK; - q_work->work_id = spi_req->work_id; - ++(knc->next_work_id); - buf_to = spi_req->midstate; - buf_from = (uint32_t *)q_work->work->midstate; - - for (i = 0; i < WORK_MIDSTATE_WORDS; ++i) - buf_to[i] = le32toh(buf_from[8 - i - 1]); - buf_to = spi_req->data; - buf_from = (uint32_t *)&(q_work->work->data[16 * 4]); - - for (i = 0; i < WORK_DATA_WORDS; ++i) - buf_to[i] = le32toh(buf_from[3 - i - 1]); -} - -static int64_t knc_process_response(struct thr_info *thr, struct cgpu_info *cgpu, - struct spi_rx_t *rxbuf) -{ - struct knc_state *knc = cgpu->device_data; - int submitted, successful, i, num_sent; - int next_read_q, next_read_a; - struct timeval now; - struct work *work; - int64_t us; - - num_sent = knc->write_q - knc->read_q - 1; - if (knc->write_q <= knc->read_q) - num_sent += KNC_QUEUED_BUFFER_SIZE; - - /* Actually process SPI response */ - if (rxbuf->works_accepted) { - applog(LOG_DEBUG, "KnC spi: raw response %08X %08X", - ((uint32_t *)rxbuf)[0], ((uint32_t *)rxbuf)[1]); - applog(LOG_DEBUG, - "KnC spi: response, accepted %u (from %u), full %u", - rxbuf->works_accepted, num_sent, - rxbuf->response_queue_full); - } - /* move works_accepted number of items from queued_fifo to active_fifo */ - gettimeofday(&now, NULL); - submitted = 0; - - for (i = 0; i < rxbuf->works_accepted; ++i) { - next_read_q = knc->read_q; - knc_queued_fifo_inc_idx(&next_read_q); - if ((next_read_q == knc->write_q) || knc_active_fifo_full(knc)) - break; - - memcpy(&knc->active_fifo[knc->write_a], - &knc->queued_fifo[next_read_q], - sizeof(struct active_work)); - knc->active_fifo[knc->write_a].begin = now; - knc->queued_fifo[next_read_q].work = NULL; - knc->read_q = next_read_q; - knc_active_fifo_inc_idx(&knc->write_a); - ++submitted; - } - if (submitted != rxbuf->works_accepted) { - applog(LOG_ERR, - "KnC: accepted by FPGA %u works, but only %d submitted", - rxbuf->works_accepted, submitted); - } - - /* check for completed works and calculated nonces */ - gettimeofday(&now, NULL); - successful = 0; - - for (i = 0; i < (int)MAX_RESPONSES_IN_BATCH; ++i) { - if ((rxbuf->responses[i].type != RESPONSE_TYPE_NONCE_FOUND) && - (rxbuf->responses[i].type != RESPONSE_TYPE_WORK_DONE)) - continue; - - applog(LOG_DEBUG, "KnC spi: raw response %08X %08X", - ((uint32_t *)&rxbuf->responses[i])[0], - ((uint32_t *)&rxbuf->responses[i])[1]); - applog(LOG_DEBUG, "KnC spi: response, T:%u C:%u-%u Q:%u W:%u", - rxbuf->responses[i].type, - rxbuf->responses[i].asic, rxbuf->responses[i].core, - rxbuf->responses[i].queue_id, - rxbuf->responses[i].work_id); - /* Find active work with matching ID */ - next_read_a = knc->read_a; - knc_active_fifo_inc_idx(&next_read_a); - - while (next_read_a != knc->write_a) { - if (knc->active_fifo[next_read_a].work_id == - rxbuf->responses[i].work_id) - break; - - /* check for stale works */ - us = timediff(&now, - &knc->active_fifo[next_read_a].begin); - if ((us < 0) || (us >= WORK_STALE_US)) { - applog(LOG_DEBUG, - "KnC spi: remove stale work %u", - knc->active_fifo[next_read_a].work_id); - work = knc->active_fifo[next_read_a].work; - knc_active_fifo_inc_idx(&knc->read_a); - work_completed(cgpu, work); - if (next_read_a != knc->read_a) { - memcpy(&(knc->active_fifo[next_read_a]), - &(knc->active_fifo[knc->read_a]), - sizeof(struct active_work)); - } - knc->active_fifo[knc->read_a].work = NULL; - } - - knc_active_fifo_inc_idx(&next_read_a); - } - if (next_read_a == knc->write_a) - continue; - - applog(LOG_DEBUG, "KnC spi: response work %u found", - rxbuf->responses[i].work_id); - work = knc->active_fifo[next_read_a].work; - - if (rxbuf->responses[i].type == RESPONSE_TYPE_NONCE_FOUND) { - if (NULL != thr) { - int cidx = rxbuf->responses[i].asic * 256 + - rxbuf->responses[i].core; - - if (submit_nonce(thr, work, - rxbuf->responses[i].nonce)) { - if (cidx < (int)sizeof(knc->hwerrs)) { - knc->hwerrs[cidx] = 0; - knc->disa_cnt[cidx] = 0; - knc->hwerr_work_id[cidx] = 0xFFFFFFFF; - } - successful++; - } else { - if ((cidx < (int)sizeof(knc->hwerrs)) && - (knc->hwerr_work_id[cidx] != rxbuf->responses[i].work_id)) { - knc->hwerr_work_id[cidx] = rxbuf->responses[i].work_id; - if (++(knc->hwerrs[cidx]) >= HW_ERR_LIMIT) { - struct core_disa_data *core; - - core = &knc->disa_cores_fifo[knc->write_d]; - core->disa_begin = now; - core->asic = rxbuf->responses[i].asic; - core->core = rxbuf->responses[i].core; - disable_core(core->asic, core->core); - if (++(knc->disa_cnt[cidx]) >= DISA_ERR_LIMIT) { - applog(LOG_WARNING, - "KnC: core %u-%u was disabled permanently", core->asic, core->core); - } else { - applog(LOG_WARNING, - "KnC: core %u-%u was disabled due to %u HW errors in a row", - core->asic, core->core, HW_ERR_LIMIT); - knc_disa_cores_fifo_inc_idx(&knc->write_d); - } - } - } - }; - } - continue; - } - - /* Work completed */ - knc_active_fifo_inc_idx(&knc->read_a); - work_completed(cgpu, work); - if (next_read_a != knc->read_a) { - memcpy(&(knc->active_fifo[next_read_a]), - &(knc->active_fifo[knc->read_a]), - sizeof(struct active_work)); - } - knc->active_fifo[knc->read_a].work = NULL; - } - - return ((uint64_t)successful) * 0x100000000UL; -} - -/* Send flush command via SPI */ -static int _internal_knc_flush_fpga(struct knc_state *knc) -{ - int len; - - spi_txbuf[0].cmd = CMD_FLUSH_QUEUE; - spi_txbuf[0].queue_id = 0; /* at the moment we have one and only queue #0 */ - len = spi_transfer(knc->ctx, (uint8_t *)spi_txbuf, - (uint8_t *)&spi_rxbuf, sizeof(struct spi_request)); - if (len != sizeof(struct spi_request)) - return -1; - - len /= sizeof(struct spi_response); - - return len; -} - -static bool knc_detect_one(struct spidev_context *ctx) -{ - /* Scan device for ASICs */ - int chip_id, devices = 0; - struct cgpu_info *cgpu; - struct knc_state *knc; - - for (chip_id = 0; chip_id < MAX_ASICS; ++chip_id) { - /* TODO: perform the ASIC test/detection */ - ++devices; - } - - if (!devices) { - applog(LOG_INFO, "SPI detected, but not KnCminer ASICs"); - return false; - } - - applog(LOG_INFO, "Found a KnC miner with %d ASICs", devices); - - cgpu = calloc(1, sizeof(*cgpu)); - knc = calloc(1, sizeof(*knc)); - if (!cgpu || !knc) { - applog(LOG_ERR, "KnC miner detected, but failed to allocate memory"); - return false; - } - - knc->ctx = ctx; - knc->devices = devices; - knc->read_q = 0; - knc->write_q = 1; - knc->read_a = 0; - knc->write_a = 1; - knc->read_d = 0; - knc->write_d = 1; - knc->salt = rand(); - mutex_init(&knc->lock); - - memset(knc->hwerr_work_id, 0xFF, sizeof(knc->hwerr_work_id)); - - _internal_knc_flush_fpga(knc); - - cgpu->drv = &knc_drv; - cgpu->name = "KnCminer"; - cgpu->threads = 1; // .. perhaps our number of devices? - - cgpu->device_data = knc; - add_cgpu(cgpu); - - return true; -} - -// http://www.concentric.net/~Ttwang/tech/inthash.htm -static unsigned long mix(unsigned long a, unsigned long b, unsigned long c) -{ - a = a - b; a = a - c; a = a ^ (c >> 13); - b = b - c; b = b - a; b = b ^ (a << 8); - c = c - a; c = c - b; c = c ^ (b >> 13); - a = a - b; a = a - c; a = a ^ (c >> 12); - b = b - c; b = b - a; b = b ^ (a << 16); - c = c - a; c = c - b; c = c ^ (b >> 5); - a = a - b; a = a - c; a = a ^ (c >> 3); - b = b - c; b = b - a; b = b ^ (a << 10); - c = c - a; c = c - b; c = c ^ (b >> 15); - - return c; -} - -/* Probe devices and register with add_cgpu */ -void knc_detect(bool __maybe_unused hotplug) -{ - int idx; - - srand(mix(clock(), time(NULL), getpid())); - - /* Loop through all possible SPI interfaces */ - for (idx = 0; idx < MAX_SPIS; ++idx) { - struct spidev_context *ctx = spi_new(idx + 1); - - if (ctx != NULL) { - if (!knc_detect_one(ctx)) - spi_free(ctx); - } - } -} - -/* return value is number of nonces that have been checked since - * previous call - */ -static int64_t knc_scanwork(struct thr_info *thr) -{ - struct cgpu_info *cgpu = thr->cgpu; - struct knc_state *knc = cgpu->device_data; - int len, num, next_read_q; - int64_t ret; - - applog(LOG_DEBUG, "KnC running scanwork"); - - knc_check_disabled_cores(knc); - - /* Prepare tx buffer */ - memset(spi_txbuf, 0, sizeof(spi_txbuf)); - num = 0; - - mutex_lock(&knc->lock); - next_read_q = knc->read_q; - knc_queued_fifo_inc_idx(&next_read_q); - - while (next_read_q != knc->write_q) { - knc_work_from_queue_to_spi(knc, &knc->queued_fifo[next_read_q], - &spi_txbuf[num]); - knc_queued_fifo_inc_idx(&next_read_q); - ++num; - } - /* knc->read_q is advanced in knc_process_response, not here */ - - len = spi_transfer(knc->ctx, (uint8_t *)spi_txbuf, - (uint8_t *)&spi_rxbuf, sizeof(spi_txbuf)); - if (len != sizeof(spi_rxbuf)) { - ret = -1; - goto out_unlock; - } - - applog(LOG_DEBUG, "KnC spi: %d works in request", num); - - ret = knc_process_response(thr, cgpu, &spi_rxbuf); -out_unlock: - mutex_unlock(&knc->lock); - - return ret; -} - -static bool knc_queue_full(struct cgpu_info *cgpu) -{ - struct knc_state *knc = cgpu->device_data; - int queue_full = false; - struct work *work; - - applog(LOG_DEBUG, "KnC running queue full"); - - mutex_lock(&knc->lock); - if (knc_queued_fifo_full(knc)) { - queue_full = true; - goto out_unlock; - } - work = get_queued(cgpu); - if (!work) - goto out_unlock; - knc->queued_fifo[knc->write_q].work = work; - knc_queued_fifo_inc_idx(&(knc->write_q)); - if (knc_queued_fifo_full(knc)) - queue_full = true; -out_unlock: - mutex_unlock(&knc->lock); - - return queue_full; -} - -static void knc_flush_work(struct cgpu_info *cgpu) -{ - struct knc_state *knc = cgpu->device_data; - int len, next_read_q, next_read_a; - struct work *work; - - applog(LOG_ERR, "KnC running flushwork"); - - mutex_lock(&knc->lock); - /* Drain queued works */ - next_read_q = knc->read_q; - knc_queued_fifo_inc_idx(&next_read_q); - - while (next_read_q != knc->write_q) { - work = knc->queued_fifo[next_read_q].work; - work_completed(cgpu, work); - knc->queued_fifo[next_read_q].work = NULL; - knc->read_q = next_read_q; - knc_queued_fifo_inc_idx(&next_read_q); - } - - /* Drain active works */ - next_read_a = knc->read_a; - knc_active_fifo_inc_idx(&next_read_a); - - while (next_read_a != knc->write_a) { - work = knc->active_fifo[next_read_a].work; - work_completed(cgpu, work); - knc->active_fifo[next_read_a].work = NULL; - knc->read_a = next_read_a; - knc_active_fifo_inc_idx(&next_read_a); - } - - len = _internal_knc_flush_fpga(knc); - if (len > 0) - knc_process_response(NULL, cgpu, &spi_rxbuf); - mutex_unlock(&knc->lock); -} - -struct device_drv knc_drv = { - .drv_id = DRIVER_knc, - .dname = "KnCminer", - .name = "KnC", - .drv_detect = knc_detect, // Probe for devices, add with add_cgpu - - .hash_work = hash_queued_work, - .scanwork = knc_scanwork, - .queue_full = knc_queue_full, - .flush_work = knc_flush_work, -}; diff --git a/driver-modminer.c b/driver-modminer.c deleted file mode 100644 index 44ee90cb..00000000 --- a/driver-modminer.c +++ /dev/null @@ -1,1144 +0,0 @@ -/* - * Copyright 2012-2013 Andrew Smith - * Copyright 2012 Luke Dashjr - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. See COPYING for more details. - */ - -#include "config.h" - -#include -#include -#include -#include - -#include "logging.h" -#include "miner.h" -#include "usbutils.h" -#include "fpgautils.h" -#include "util.h" - -#define BITSTREAM_FILENAME "fpgaminer_top_fixed7_197MHz.ncd" -#define BISTREAM_USER_ID "\2\4$B" - -#define BITSTREAM_MAGIC_0 0 -#define BITSTREAM_MAGIC_1 9 - -#define MODMINER_CUTOFF_TEMP 60.0 -#define MODMINER_OVERHEAT_TEMP 50.0 -#define MODMINER_RECOVER_TEMP 46.5 -#define MODMINER_TEMP_UP_LIMIT 47.0 - -#define MODMINER_HW_ERROR_PERCENT 0.75 - -// How many seconds of no nonces means there's something wrong -// First time - drop the clock and see if it revives -// Second time - (and it didn't revive) disable it -#define ITS_DEAD_JIM 300 - -// N.B. in the latest firmware the limit is 250 -// however the voltage/temperature risks preclude that -#define MODMINER_MAX_CLOCK 230 -#define MODMINER_DEF_CLOCK 200 -#define MODMINER_MIN_CLOCK 160 - -#define MODMINER_CLOCK_UP 2 -#define MODMINER_CLOCK_SET 0 -#define MODMINER_CLOCK_DOWN -2 -// = 0 means OVERHEAT doesn't affect the clock -#define MODMINER_CLOCK_OVERHEAT 0 -#define MODMINER_CLOCK_DEAD -6 -#define MODMINER_CLOCK_CUTOFF -10 - -// Commands -#define MODMINER_PING "\x00" -#define MODMINER_GET_VERSION "\x01" -#define MODMINER_FPGA_COUNT "\x02" -// Commands + require FPGAid -#define MODMINER_GET_IDCODE '\x03' -#define MODMINER_GET_USERCODE '\x04' -#define MODMINER_PROGRAM '\x05' -#define MODMINER_SET_CLOCK '\x06' -#define MODMINER_READ_CLOCK '\x07' -#define MODMINER_SEND_WORK '\x08' -#define MODMINER_CHECK_WORK '\x09' -// One byte temperature reply -#define MODMINER_TEMP1 '\x0a' -// Two byte temperature reply -#define MODMINER_TEMP2 '\x0d' - -// +6 bytes -#define MODMINER_SET_REG '\x0b' -// +2 bytes -#define MODMINER_GET_REG '\x0c' - -#define FPGAID_ALL 4 - -// Maximum how many good shares in a row means clock up -// 96 is ~34m22s at 200MH/s -#define MODMINER_TRY_UP 96 -// Initially how many good shares in a row means clock up -// This is doubled each down clock until it reaches MODMINER_TRY_UP -// 6 is ~2m9s at 200MH/s -#define MODMINER_EARLY_UP 6 -// Limit when reducing shares_to_good -#define MODMINER_MIN_BACK 12 - -// 45 noops sent when detecting, in case the device was left in "start job" reading -static const char NOOP[] = MODMINER_PING "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"; - -static void do_ping(struct cgpu_info *modminer) -{ - char buf[0x100+1]; - int err, amount; - - // Don't care if it fails - err = usb_write(modminer, (char *)NOOP, sizeof(NOOP)-1, &amount, C_PING); - applog(LOG_DEBUG, "%s%u: flush noop got %d err %d", - modminer->drv->name, modminer->fpgaid, amount, err); - - // Clear any outstanding data - while ((err = usb_read_once(modminer, buf, sizeof(buf)-1, &amount, C_CLEAR)) == 0 && amount > 0) - applog(LOG_DEBUG, "%s%u: clear got %d", - modminer->drv->name, modminer->fpgaid, amount); - - applog(LOG_DEBUG, "%s%u: final clear got %d err %d", - modminer->drv->name, modminer->fpgaid, amount, err); -} - -static bool modminer_detect_one(struct libusb_device *dev, struct usb_find_devices *found) -{ - char buf[0x100+1]; - char *devname = NULL; - char devpath[32]; - int err, i, amount; - bool added = false; - - struct cgpu_info *modminer = usb_alloc_cgpu(&modminer_drv, 1); - - modminer->modminer_mutex = calloc(1, sizeof(*(modminer->modminer_mutex))); - mutex_init(modminer->modminer_mutex); - modminer->fpgaid = (char)0; - - if (!usb_init(modminer, dev, found)) - goto shin; - - usb_set_cps(modminer, 11520); - usb_enable_cps(modminer); - - do_ping(modminer); - - if ((err = usb_write(modminer, MODMINER_GET_VERSION, 1, &amount, C_REQUESTVERSION)) < 0 || amount != 1) { - applog(LOG_ERR, "%s detect (%s) send version request failed (%d:%d)", - modminer->drv->dname, modminer->device_path, amount, err); - goto unshin; - } - - if ((err = usb_read_once(modminer, buf, sizeof(buf)-1, &amount, C_GETVERSION)) < 0 || amount < 1) { - if (err < 0) - applog(LOG_ERR, "%s detect (%s) no version reply (%d)", - modminer->drv->dname, modminer->device_path, err); - else - applog(LOG_ERR, "%s detect (%s) empty version reply (%d)", - modminer->drv->dname, modminer->device_path, amount); - - applog(LOG_DEBUG, "%s detect (%s) check the firmware", - modminer->drv->dname, modminer->device_path); - - goto unshin; - } - buf[amount] = '\0'; - devname = strdup(buf); - applog(LOG_DEBUG, "%s (%s) identified as: %s", modminer->drv->dname, modminer->device_path, devname); - - if ((err = usb_write(modminer, MODMINER_FPGA_COUNT, 1, &amount, C_REQUESTFPGACOUNT) < 0 || amount != 1)) { - applog(LOG_ERR, "%s detect (%s) FPGA count request failed (%d:%d)", - modminer->drv->dname, modminer->device_path, amount, err); - goto unshin; - } - - if ((err = usb_read(modminer, buf, 1, &amount, C_GETFPGACOUNT)) < 0 || amount != 1) { - applog(LOG_ERR, "%s detect (%s) no FPGA count reply (%d:%d)", - modminer->drv->dname, modminer->device_path, amount, err); - goto unshin; - } - - // TODO: flag it use 1 byte temp if it is an old firmware - // can detect with modminer->cgusb->serial ? - - if (buf[0] == 0) { - applog(LOG_ERR, "%s detect (%s) zero FPGA count from %s", - modminer->drv->dname, modminer->device_path, devname); - goto unshin; - } - - if (buf[0] < 1 || buf[0] > 4) { - applog(LOG_ERR, "%s detect (%s) invalid FPGA count (%u) from %s", - modminer->drv->dname, modminer->device_path, buf[0], devname); - goto unshin; - } - - applog(LOG_DEBUG, "%s (%s) %s has %u FPGAs", - modminer->drv->dname, modminer->device_path, devname, buf[0]); - - modminer->name = devname; - - // TODO: test with 1 board missing in the middle and each end - // to see how that affects the sequence numbers - for (i = 0; i < buf[0]; i++) { - struct cgpu_info *tmp = usb_copy_cgpu(modminer); - - sprintf(devpath, "%d:%d:%d", - (int)(modminer->usbinfo.bus_number), - (int)(modminer->usbinfo.device_address), - i); - - tmp->device_path = strdup(devpath); - - // Only the first copy gets the already used stats - if (added) - tmp->usbinfo.usbstat = USB_NOSTAT; - - tmp->fpgaid = (char)i; - tmp->modminer_mutex = modminer->modminer_mutex; - - if (!add_cgpu(tmp)) { - tmp = usb_free_cgpu(tmp); - goto unshin; - } - - update_usb_stats(tmp); - - added = true; - } - - modminer = usb_free_cgpu(modminer); - - return true; - -unshin: - if (!added) - usb_uninit(modminer); - -shin: - if (!added) { - free(modminer->modminer_mutex); - modminer->modminer_mutex = NULL; - } - - modminer = usb_free_cgpu(modminer); - - if (added) - return true; - else - return false; -} - -static void modminer_detect(bool __maybe_unused hotplug) -{ - usb_detect(&modminer_drv, modminer_detect_one); -} - -static bool get_expect(struct cgpu_info *modminer, FILE *f, char c) -{ - char buf; - - if (fread(&buf, 1, 1, f) != 1) { - applog(LOG_ERR, "%s%u: Error (%d) reading bitstream (%c)", - modminer->drv->name, modminer->device_id, errno, c); - return false; - } - - if (buf != c) { - applog(LOG_ERR, "%s%u: bitstream code mismatch (%c)", - modminer->drv->name, modminer->device_id, c); - return false; - } - - return true; -} - -static bool get_info(struct cgpu_info *modminer, FILE *f, char *buf, int bufsiz, const char *name) -{ - unsigned char siz[2]; - int len; - - if (fread(siz, 2, 1, f) != 1) { - applog(LOG_ERR, "%s%u: Error (%d) reading bitstream '%s' len", - modminer->drv->name, modminer->device_id, errno, name); - return false; - } - - len = siz[0] * 256 + siz[1]; - - if (len >= bufsiz) { - applog(LOG_ERR, "%s%u: Bitstream '%s' len too large (%d)", - modminer->drv->name, modminer->device_id, name, len); - return false; - } - - if (fread(buf, len, 1, f) != 1) { - applog(LOG_ERR, "%s%u: Error (%d) reading bitstream '%s'", - modminer->drv->name, modminer->device_id, errno, name); - return false; - } - - buf[len] = '\0'; - - return true; -} - -#define USE_DEFAULT_TIMEOUT 0 - -// mutex must always be locked before calling -static bool get_status_timeout(struct cgpu_info *modminer, char *msg, unsigned int timeout, enum usb_cmds cmd) -{ - int err, amount; - char buf[1]; - - if (timeout == USE_DEFAULT_TIMEOUT) - err = usb_read(modminer, buf, 1, &amount, cmd); - else - err = usb_read_timeout(modminer, buf, 1, &amount, timeout, cmd); - - if (err < 0 || amount != 1) { - mutex_unlock(modminer->modminer_mutex); - - applog(LOG_ERR, "%s%u: Error (%d:%d) getting %s reply", - modminer->drv->name, modminer->device_id, amount, err, msg); - - return false; - } - - if (buf[0] != 1) { - mutex_unlock(modminer->modminer_mutex); - - applog(LOG_ERR, "%s%u: Error, invalid %s reply (was %d should be 1)", - modminer->drv->name, modminer->device_id, msg, buf[0]); - - return false; - } - - return true; -} - -// mutex must always be locked before calling -static bool get_status(struct cgpu_info *modminer, char *msg, enum usb_cmds cmd) -{ - return get_status_timeout(modminer, msg, USE_DEFAULT_TIMEOUT, cmd); -} - -static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer) -{ - const char *bsfile = BITSTREAM_FILENAME; - char buf[0x100], *p; - char devmsg[64]; - unsigned char *ubuf = (unsigned char *)buf; - unsigned long totlen, len; - size_t buflen, remaining; - float nextmsg, upto; - char fpgaid = FPGAID_ALL; - int err, amount, tries; - char *ptr; - - FILE *f = open_bitstream("modminer", bsfile); - if (!f) { - mutex_unlock(modminer->modminer_mutex); - - applog(LOG_ERR, "%s%u: Error (%d) opening bitstream file %s", - modminer->drv->name, modminer->device_id, errno, bsfile); - - return false; - } - - if (fread(buf, 2, 1, f) != 1) { - mutex_unlock(modminer->modminer_mutex); - - applog(LOG_ERR, "%s%u: Error (%d) reading bitstream magic", - modminer->drv->name, modminer->device_id, errno); - - goto dame; - } - - if (buf[0] != BITSTREAM_MAGIC_0 || buf[1] != BITSTREAM_MAGIC_1) { - mutex_unlock(modminer->modminer_mutex); - - applog(LOG_ERR, "%s%u: bitstream has incorrect magic (%u,%u) instead of (%u,%u)", - modminer->drv->name, modminer->device_id, - buf[0], buf[1], - BITSTREAM_MAGIC_0, BITSTREAM_MAGIC_1); - - goto dame; - } - - if (fseek(f, 11L, SEEK_CUR)) { - mutex_unlock(modminer->modminer_mutex); - - applog(LOG_ERR, "%s%u: Error (%d) bitstream seek failed", - modminer->drv->name, modminer->device_id, errno); - - goto dame; - } - - if (!get_expect(modminer, f, 'a')) - goto undame; - - if (!get_info(modminer, f, buf, sizeof(buf), "Design name")) - goto undame; - - applog(LOG_DEBUG, "%s%u: bitstream file '%s' info:", - modminer->drv->name, modminer->device_id, bsfile); - - applog(LOG_DEBUG, " Design name: '%s'", buf); - - p = strrchr(buf, ';') ? : buf; - p = strrchr(buf, '=') ? : p; - if (p[0] == '=') - p++; - - unsigned long fwusercode = (unsigned long)strtoll(p, &p, 16); - - if (p[0] != '\0') { - mutex_unlock(modminer->modminer_mutex); - - applog(LOG_ERR, "%s%u: Bad usercode in bitstream file", - modminer->drv->name, modminer->device_id); - - goto dame; - } - - if (fwusercode == 0xffffffff) { - mutex_unlock(modminer->modminer_mutex); - - applog(LOG_ERR, "%s%u: bitstream doesn't support user code", - modminer->drv->name, modminer->device_id); - - goto dame; - } - - applog(LOG_DEBUG, " Version: %lu, build %lu", (fwusercode >> 8) & 0xff, fwusercode & 0xff); - - if (!get_expect(modminer, f, 'b')) - goto undame; - - if (!get_info(modminer, f, buf, sizeof(buf), "Part number")) - goto undame; - - applog(LOG_DEBUG, " Part number: '%s'", buf); - - if (!get_expect(modminer, f, 'c')) - goto undame; - - if (!get_info(modminer, f, buf, sizeof(buf), "Build date")) - goto undame; - - applog(LOG_DEBUG, " Build date: '%s'", buf); - - if (!get_expect(modminer, f, 'd')) - goto undame; - - if (!get_info(modminer, f, buf, sizeof(buf), "Build time")) - goto undame; - - applog(LOG_DEBUG, " Build time: '%s'", buf); - - if (!get_expect(modminer, f, 'e')) - goto undame; - - if (fread(buf, 4, 1, f) != 1) { - mutex_unlock(modminer->modminer_mutex); - - applog(LOG_ERR, "%s%u: Error (%d) reading bitstream data len", - modminer->drv->name, modminer->device_id, errno); - - goto dame; - } - - len = ((unsigned long)ubuf[0] << 24) | ((unsigned long)ubuf[1] << 16) | (ubuf[2] << 8) | ubuf[3]; - applog(LOG_DEBUG, " Bitstream size: %lu", len); - - strcpy(devmsg, modminer->device_path); - ptr = strrchr(devmsg, ':'); - if (ptr) - *ptr = '\0'; - - applog(LOG_WARNING, "%s%u: Programming all FPGA on %s ... Mining will not start until complete", - modminer->drv->name, modminer->device_id, devmsg); - - buf[0] = MODMINER_PROGRAM; - buf[1] = fpgaid; - buf[2] = (len >> 0) & 0xff; - buf[3] = (len >> 8) & 0xff; - buf[4] = (len >> 16) & 0xff; - buf[5] = (len >> 24) & 0xff; - - if ((err = usb_write(modminer, buf, 6, &amount, C_STARTPROGRAM)) < 0 || amount != 6) { - mutex_unlock(modminer->modminer_mutex); - - applog(LOG_ERR, "%s%u: Program init failed (%d:%d)", - modminer->drv->name, modminer->device_id, amount, err); - - goto dame; - } - - if (!get_status(modminer, "initialise", C_STARTPROGRAMSTATUS)) - goto undame; - -// It must be 32 bytes according to MCU legacy.c -#define WRITE_SIZE 32 - - totlen = len; - nextmsg = 0.1; - while (len > 0) { - buflen = len < WRITE_SIZE ? len : WRITE_SIZE; - if (fread(buf, buflen, 1, f) != 1) { - mutex_unlock(modminer->modminer_mutex); - - applog(LOG_ERR, "%s%u: bitstream file read error %d (%lu bytes left)", - modminer->drv->name, modminer->device_id, errno, len); - - goto dame; - } - - tries = 0; - ptr = buf; - remaining = buflen; - while ((err = usb_write(modminer, ptr, remaining, &amount, C_PROGRAM)) < 0 || amount != (int)remaining) { - if (err == LIBUSB_ERROR_TIMEOUT && amount > 0 && ++tries < 4) { - remaining -= amount; - ptr += amount; - - if (opt_debug) - applog(LOG_DEBUG, "%s%u: Program timeout (%d:%d) sent %d tries %d", - modminer->drv->name, modminer->device_id, - amount, err, (int)remaining, tries); - - if (!get_status(modminer, "write status", C_PROGRAMSTATUS2)) - goto dame; - - } else { - mutex_unlock(modminer->modminer_mutex); - - applog(LOG_ERR, "%s%u: Program failed (%d:%d) sent %d", - modminer->drv->name, modminer->device_id, amount, err, (int)remaining); - - goto dame; - } - } - - if (!get_status(modminer, "write status", C_PROGRAMSTATUS)) - goto dame; - - len -= buflen; - - upto = (float)(totlen - len) / (float)(totlen); - if (upto >= nextmsg) { - applog(LOG_WARNING, - "%s%u: Programming %.1f%% (%lu out of %lu)", - modminer->drv->name, modminer->device_id, upto*100, (totlen - len), totlen); - - nextmsg += 0.1; - } - } - - if (!get_status(modminer, "final status", C_FINALPROGRAMSTATUS)) - goto undame; - - applog(LOG_WARNING, "%s%u: Programming completed for all FPGA on %s", - modminer->drv->name, modminer->device_id, devmsg); - - // Give it a 2/3s delay after programming - cgsleep_ms(666); - - usb_set_dev_start(modminer); - - return true; -undame: - ; - mutex_unlock(modminer->modminer_mutex); - ; -dame: - fclose(f); - return false; -} - -static bool modminer_fpga_prepare(struct thr_info *thr) -{ -// struct cgpu_info *modminer = thr->cgpu; - struct modminer_fpga_state *state; - - state = thr->cgpu_data = calloc(1, sizeof(struct modminer_fpga_state)); - state->shares_to_good = MODMINER_EARLY_UP; - state->overheated = false; - - return true; -} - -/* - * Clocking rules: - * If device exceeds cutoff or overheat temp - stop sending work until it cools - * decrease the clock by MODMINER_CLOCK_CUTOFF/MODMINER_CLOCK_OVERHEAT - * for when it restarts - * with MODMINER_CLOCK_OVERHEAT=0 basically says that temp shouldn't - * affect the clock unless we reach CUTOFF - * - * If device overheats - * set shares_to_good back to MODMINER_MIN_BACK - * to speed up clock recovery if temp drop doesnt help - * - * When to clock down: - * If device gets MODMINER_HW_ERROR_PERCENT errors since last clock up or down - * if clock is <= default it requires 2 HW to do this test - * if clock is > default it only requires 1 HW to do this test - * also double shares_to_good - * - * When to clock up: - * If device gets shares_to_good good shares in a row - * and temp < MODMINER_TEMP_UP_LIMIT - * - * N.B. clock must always be a multiple of 2 - */ -static const char *clocknodev = "clock failed - no device"; -static const char *clockoldwork = "clock already changed for this work"; -static const char *clocktoolow = "clock too low"; -static const char *clocktoohi = "clock too high"; -static const char *clocksetfail = "clock set command failed"; -static const char *clockreplyfail = "clock reply failed"; - -static const char *modminer_delta_clock(struct thr_info *thr, int delta, bool temp, bool force) -{ - struct cgpu_info *modminer = thr->cgpu; - struct modminer_fpga_state *state = thr->cgpu_data; - unsigned char cmd[6], buf[1]; - int err, amount; - - // Device is gone - if (modminer->usbinfo.nodev) - return clocknodev; - - // Only do once if multiple shares per work or multiple reasons - if (!state->new_work && !force) - return clockoldwork; - - state->new_work = false; - - state->shares = 0; - state->shares_last_hw = 0; - state->hw_errors = 0; - - // FYI clock drop has little effect on temp - if (delta < 0 && (modminer->clock + delta) < MODMINER_MIN_CLOCK) - return clocktoolow; - - if (delta > 0 && (modminer->clock + delta) > MODMINER_MAX_CLOCK) - return clocktoohi; - - if (delta < 0) { - if (temp) - state->shares_to_good = MODMINER_MIN_BACK; - else { - if ((state->shares_to_good * 2) < MODMINER_TRY_UP) - state->shares_to_good *= 2; - else - state->shares_to_good = MODMINER_TRY_UP; - } - } - - modminer->clock += delta; - - cmd[0] = MODMINER_SET_CLOCK; - cmd[1] = modminer->fpgaid; - cmd[2] = modminer->clock; - cmd[3] = cmd[4] = cmd[5] = '\0'; - - mutex_lock(modminer->modminer_mutex); - - if ((err = usb_write(modminer, (char *)cmd, 6, &amount, C_SETCLOCK)) < 0 || amount != 6) { - mutex_unlock(modminer->modminer_mutex); - - applog(LOG_ERR, "%s%u: Error writing set clock speed (%d:%d)", - modminer->drv->name, modminer->device_id, amount, err); - - return clocksetfail; - } - - if ((err = usb_read(modminer, (char *)(&buf), 1, &amount, C_REPLYSETCLOCK)) < 0 || amount != 1) { - mutex_unlock(modminer->modminer_mutex); - - applog(LOG_ERR, "%s%u: Error reading set clock speed (%d:%d)", - modminer->drv->name, modminer->device_id, amount, err); - - return clockreplyfail; - } - - mutex_unlock(modminer->modminer_mutex); - - applog(LOG_WARNING, "%s%u: Set clock speed %sto %u", - modminer->drv->name, modminer->device_id, - (delta < 0) ? "down " : (delta > 0 ? "up " : ""), - modminer->clock); - - return NULL; -} - -static bool modminer_fpga_init(struct thr_info *thr) -{ - struct cgpu_info *modminer = thr->cgpu; - unsigned char cmd[2], buf[4]; - int err, amount; - - mutex_lock(modminer->modminer_mutex); - - cmd[0] = MODMINER_GET_USERCODE; - cmd[1] = modminer->fpgaid; - if ((err = usb_write(modminer, (char *)cmd, 2, &amount, C_REQUESTUSERCODE)) < 0 || amount != 2) { - mutex_unlock(modminer->modminer_mutex); - - applog(LOG_ERR, "%s%u: Error requesting USER code (%d:%d)", - modminer->drv->name, modminer->device_id, amount, err); - - return false; - } - - if ((err = usb_read(modminer, (char *)buf, 4, &amount, C_GETUSERCODE)) < 0 || amount != 4) { - mutex_unlock(modminer->modminer_mutex); - - applog(LOG_ERR, "%s%u: Error reading USER code (%d:%d)", - modminer->drv->name, modminer->device_id, amount, err); - - return false; - } - - if (memcmp(buf, BISTREAM_USER_ID, 4)) { - applog(LOG_ERR, "%s%u: FPGA not programmed", - modminer->drv->name, modminer->device_id); - - if (!modminer_fpga_upload_bitstream(modminer)) - return false; - - mutex_unlock(modminer->modminer_mutex); - } else { - mutex_unlock(modminer->modminer_mutex); - - applog(LOG_DEBUG, "%s%u: FPGA is already programmed :)", - modminer->drv->name, modminer->device_id); - } - - modminer->clock = MODMINER_DEF_CLOCK; - modminer_delta_clock(thr, MODMINER_CLOCK_SET, false, false); - - thr->primary_thread = true; - - return true; -} - -static void get_modminer_statline_before(char *buf, size_t bufsiz, struct cgpu_info *modminer) -{ - tailsprintf(buf, bufsiz, " %s%.1fC %3uMHz | ", - (modminer->temp < 10) ? " " : "", - modminer->temp, - (unsigned int)(modminer->clock)); -} - -static bool modminer_start_work(struct thr_info *thr, struct work *work) -{ - struct cgpu_info *modminer = thr->cgpu; - struct modminer_fpga_state *state = thr->cgpu_data; - int err, amount; - char cmd[48]; - bool sta; - - cmd[0] = MODMINER_SEND_WORK; - cmd[1] = modminer->fpgaid; - memcpy(&cmd[2], work->midstate, 32); - memcpy(&cmd[34], work->data + 64, 12); - - if (state->first_work.tv_sec == 0) - cgtime(&state->first_work); - - if (state->last_nonce.tv_sec == 0) - cgtime(&state->last_nonce); - - mutex_lock(modminer->modminer_mutex); - - if ((err = usb_write(modminer, cmd, 46, &amount, C_SENDWORK)) < 0 || amount != 46) { - mutex_unlock(modminer->modminer_mutex); - - applog(LOG_ERR, "%s%u: Start work failed (%d:%d)", - modminer->drv->name, modminer->device_id, amount, err); - - return false; - } - - cgtime(&state->tv_workstart); - - sta = get_status(modminer, "start work", C_SENDWORKSTATUS); - - if (sta) { - mutex_unlock(modminer->modminer_mutex); - state->new_work = true; - } - - return sta; -} - -static void check_temperature(struct thr_info *thr) -{ - struct cgpu_info *modminer = thr->cgpu; - struct modminer_fpga_state *state = thr->cgpu_data; - char cmd[2], temperature[2]; - int tbytes, tamount; - int amount; - - // Device is gone - if (modminer->usbinfo.nodev) - return; - - if (state->one_byte_temp) { - cmd[0] = MODMINER_TEMP1; - tbytes = 1; - } else { - cmd[0] = MODMINER_TEMP2; - tbytes = 2; - } - - cmd[1] = modminer->fpgaid; - - mutex_lock(modminer->modminer_mutex); - if (usb_write(modminer, (char *)cmd, 2, &amount, C_REQUESTTEMPERATURE) == 0 && amount == 2 && - usb_read(modminer, (char *)(&temperature), tbytes, &tamount, C_GETTEMPERATURE) == 0 && tamount == tbytes) { - mutex_unlock(modminer->modminer_mutex); - if (state->one_byte_temp) - modminer->temp = temperature[0]; - else { - // Only accurate to 2 and a bit places - modminer->temp = roundf((temperature[1] * 256.0 + temperature[0]) / 0.128) / 1000.0; - - state->tried_two_byte_temp = true; - } - - if (state->overheated) { - // Limit recovery to lower than OVERHEAT so it doesn't just go straight over again - if (modminer->temp < MODMINER_RECOVER_TEMP) { - state->overheated = false; - applog(LOG_WARNING, "%s%u: Recovered, temp less than (%.1f) now %.3f", - modminer->drv->name, modminer->device_id, - MODMINER_RECOVER_TEMP, modminer->temp); - } - } - else if (modminer->temp >= MODMINER_OVERHEAT_TEMP) { - if (modminer->temp >= MODMINER_CUTOFF_TEMP) { - applog(LOG_WARNING, "%s%u: Hit thermal cutoff limit! (%.1f) at %.3f", - modminer->drv->name, modminer->device_id, - MODMINER_CUTOFF_TEMP, modminer->temp); - - modminer_delta_clock(thr, MODMINER_CLOCK_CUTOFF, true, false); - state->overheated = true; - dev_error(modminer, REASON_DEV_THERMAL_CUTOFF); - } else { - applog(LOG_WARNING, "%s%u: Overheat limit (%.1f) reached %.3f", - modminer->drv->name, modminer->device_id, - MODMINER_OVERHEAT_TEMP, modminer->temp); - - // If it's defined to be 0 then don't call modminer_delta_clock() - if (MODMINER_CLOCK_OVERHEAT != 0) - modminer_delta_clock(thr, MODMINER_CLOCK_OVERHEAT, true, false); - state->overheated = true; - dev_error(modminer, REASON_DEV_OVER_HEAT); - } - } - } else { - mutex_unlock(modminer->modminer_mutex); - - if (!state->tried_two_byte_temp) { - state->tried_two_byte_temp = true; - state->one_byte_temp = true; - } - } -} - -#define work_restart(thr) thr->work_restart - -// 250Mhz is 17.17s - ensure we don't go idle -static const double processtime = 17.0; -// 160Mhz is 26.84 - when overheated ensure we don't throw away shares -static const double overheattime = 26.9; - -static uint64_t modminer_process_results(struct thr_info *thr, struct work *work) -{ - struct cgpu_info *modminer = thr->cgpu; - struct modminer_fpga_state *state = thr->cgpu_data; - struct timeval now; - char cmd[2]; - uint32_t nonce; - uint32_t curr_hw_errors; - int err, amount, amount2; - int timeoutloop; - double timeout; - int temploop; - - // Device is gone - if (modminer->usbinfo.nodev) - return -1; - - // If we are overheated it will just keep checking for results - // since we can't stop the work - // The next work will not start until the temp drops - check_temperature(thr); - - cmd[0] = MODMINER_CHECK_WORK; - cmd[1] = modminer->fpgaid; - - timeoutloop = 0; - temploop = 0; - while (0x80085) { - mutex_lock(modminer->modminer_mutex); - if ((err = usb_write(modminer, cmd, 2, &amount, C_REQUESTWORKSTATUS)) < 0 || amount != 2) { - mutex_unlock(modminer->modminer_mutex); - - // timeoutloop never resets so the timeouts can't - // accumulate much during a single item of work - if (err == LIBUSB_ERROR_TIMEOUT && ++timeoutloop < 5) { - state->timeout_fail++; - goto tryagain; - } - - applog(LOG_ERR, "%s%u: Error sending (get nonce) (%d:%d)", - modminer->drv->name, modminer->device_id, amount, err); - - return -1; - } - - err = usb_read(modminer, (char *)(&nonce), 4, &amount, C_GETWORKSTATUS); - while (err == LIBUSB_SUCCESS && amount < 4) { - size_t remain = 4 - amount; - char *pos = ((char *)(&nonce)) + amount; - - state->success_more++; - - err = usb_read(modminer, pos, remain, &amount2, C_GETWORKSTATUS); - - amount += amount2; - } - mutex_unlock(modminer->modminer_mutex); - - if (err < 0 || amount < 4) { - // timeoutloop never resets so the timeouts can't - // accumulate much during a single item of work - if (err == LIBUSB_ERROR_TIMEOUT && ++timeoutloop < 10) { - state->timeout_fail++; - goto tryagain; - } - - applog(LOG_ERR, "%s%u: Error reading (get nonce) (%d:%d)", - modminer->drv->name, modminer->device_id, amount+amount2, err); - } - - if (memcmp(&nonce, "\xff\xff\xff\xff", 4)) { - // found 'something' ... - state->shares++; - curr_hw_errors = state->hw_errors; - submit_nonce(thr, work, nonce); - if (state->hw_errors > curr_hw_errors) { - cgtime(&now); - // Ignore initial errors that often happen - if (tdiff(&now, &state->first_work) < 2.0) { - state->shares = 0; - state->shares_last_hw = 0; - state->hw_errors = 0; - } else { - state->shares_last_hw = state->shares; - if (modminer->clock > MODMINER_DEF_CLOCK || state->hw_errors > 1) { - float pct = (state->hw_errors * 100.0 / (state->shares ? : 1.0)); - if (pct >= MODMINER_HW_ERROR_PERCENT) - modminer_delta_clock(thr, MODMINER_CLOCK_DOWN, false, false); - } - } - } else { - cgtime(&state->last_nonce); - state->death_stage_one = false; - // If we've reached the required good shares in a row then clock up - if (((state->shares - state->shares_last_hw) >= state->shares_to_good) && - modminer->temp < MODMINER_TEMP_UP_LIMIT) - modminer_delta_clock(thr, MODMINER_CLOCK_UP, false, false); - } - } else { - // on rare occasions - the MMQ can just stop returning valid nonces - double death = ITS_DEAD_JIM * (state->death_stage_one ? 2.0 : 1.0); - cgtime(&now); - if (tdiff(&now, &state->last_nonce) >= death) { - if (state->death_stage_one) { - modminer_delta_clock(thr, MODMINER_CLOCK_DEAD, false, true); - applog(LOG_ERR, "%s%u: DEATH clock down", - modminer->drv->name, modminer->device_id); - - // reset the death info and DISABLE it - state->last_nonce.tv_sec = 0; - state->last_nonce.tv_usec = 0; - state->death_stage_one = false; - return -1; - } else { - modminer_delta_clock(thr, MODMINER_CLOCK_DEAD, false, true); - applog(LOG_ERR, "%s%u: death clock down", - modminer->drv->name, modminer->device_id); - - state->death_stage_one = true; - } - } - } - -tryagain: - - if (work_restart(thr)) - break; - - if (state->overheated == true) { - // don't check every time (every ~1/2 sec) - if (++temploop > 4) { - check_temperature(thr); - temploop = 0; - } - - } - - if (state->overheated == true) - timeout = overheattime; - else - timeout = processtime; - - cgtime(&now); - if (tdiff(&now, &state->tv_workstart) > timeout) - break; - - // 1/10th sec to lower CPU usage - cgsleep_ms(100); - if (work_restart(thr)) - break; - } - - struct timeval tv_workend, elapsed; - cgtime(&tv_workend); - timersub(&tv_workend, &state->tv_workstart, &elapsed); - - // Not exact since the clock may have changed ... but close enough I guess - uint64_t hashes = (uint64_t)modminer->clock * (((uint64_t)elapsed.tv_sec * 1000000) + elapsed.tv_usec); - // Overheat will complete the nonce range - if (hashes > 0xffffffff) - hashes = 0xffffffff; - - work->blk.nonce = 0xffffffff; - - return hashes; -} - -static int64_t modminer_scanhash(struct thr_info *thr, struct work *work, int64_t __maybe_unused max_nonce) -{ - struct modminer_fpga_state *state = thr->cgpu_data; - struct timeval tv1, tv2; - int64_t hashes; - - // Device is gone - if (thr->cgpu->usbinfo.nodev) - return -1; - - // Don't start new work if overheated - if (state->overheated == true) { - cgtime(&tv1); - - while (state->overheated == true) { - check_temperature(thr); - - // Device is gone - if (thr->cgpu->usbinfo.nodev) - return -1; - - if (state->overheated == true) { - cgtime(&tv2); - - // give up on this work item after 30s - if (work_restart(thr) || tdiff(&tv2, &tv1) > 30) - return 0; - - // Give it 1s rest then check again - cgsleep_ms(1000); - } - } - } - - if (!modminer_start_work(thr, work)) - return -1; - - hashes = modminer_process_results(thr, work); - if (hashes == -1) - return hashes; - - return hashes; -} - -static void modminer_hw_error(struct thr_info *thr) -{ - struct modminer_fpga_state *state = thr->cgpu_data; - - state->hw_errors++; -} - -static void modminer_fpga_shutdown(struct thr_info *thr) -{ - free(thr->cgpu_data); - thr->cgpu_data = NULL; -} - -static char *modminer_set_device(struct cgpu_info *modminer, char *option, char *setting, char *replybuf) -{ - const char *ret; - int val; - - if (strcasecmp(option, "help") == 0) { - sprintf(replybuf, "clock: range %d-%d and a multiple of 2", - MODMINER_MIN_CLOCK, MODMINER_MAX_CLOCK); - return replybuf; - } - - if (strcasecmp(option, "clock") == 0) { - if (!setting || !*setting) { - sprintf(replybuf, "missing clock setting"); - return replybuf; - } - - val = atoi(setting); - if (val < MODMINER_MIN_CLOCK || val > MODMINER_MAX_CLOCK || (val & 1) != 0) { - sprintf(replybuf, "invalid clock: '%s' valid range %d-%d and a multiple of 2", - setting, MODMINER_MIN_CLOCK, MODMINER_MAX_CLOCK); - return replybuf; - } - - val -= (int)(modminer->clock); - - ret = modminer_delta_clock(modminer->thr[0], val, false, true); - if (ret) { - sprintf(replybuf, "Set clock failed: %s", ret); - return replybuf; - } else - return NULL; - } - - sprintf(replybuf, "Unknown option: %s", option); - return replybuf; -} - -struct device_drv modminer_drv = { - .drv_id = DRIVER_modminer, - .dname = "ModMiner", - .name = "MMQ", - .drv_detect = modminer_detect, - .get_statline_before = get_modminer_statline_before, - .set_device = modminer_set_device, - .thread_prepare = modminer_fpga_prepare, - .thread_init = modminer_fpga_init, - .scanhash = modminer_scanhash, - .hw_error = modminer_hw_error, - .thread_shutdown = modminer_fpga_shutdown, -}; diff --git a/fpgautils.c b/fpgautils.c deleted file mode 100644 index 8c262e79..00000000 --- a/fpgautils.c +++ /dev/null @@ -1,610 +0,0 @@ -/* - * Copyright 2013 Con Kolivas - * Copyright 2012 Luke Dashjr - * Copyright 2012 Andrew Smith - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. See COPYING for more details. - */ - -#include "config.h" - -#include -#include -#include - -#include "miner.h" - -#ifndef WIN32 -#include -#include -#include -#include -#include -#include -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif -#else -#include -#include -#endif - -#ifdef HAVE_LIBUDEV -#include -#include -#endif - -#include "elist.h" -#include "logging.h" -#include "miner.h" -#include "fpgautils.h" - -#ifdef HAVE_LIBUDEV -int serial_autodetect_udev(detectone_func_t detectone, const char*prodname) -{ - struct udev *udev = udev_new(); - struct udev_enumerate *enumerate = udev_enumerate_new(udev); - struct udev_list_entry *list_entry; - char found = 0; - - udev_enumerate_add_match_subsystem(enumerate, "tty"); - udev_enumerate_add_match_property(enumerate, "ID_MODEL", prodname); - udev_enumerate_scan_devices(enumerate); - udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) { - struct udev_device *device = udev_device_new_from_syspath( - udev_enumerate_get_udev(enumerate), - udev_list_entry_get_name(list_entry) - ); - if (!device) - continue; - - const char *devpath = udev_device_get_devnode(device); - if (devpath && detectone(devpath)) - ++found; - - udev_device_unref(device); - } - udev_enumerate_unref(enumerate); - udev_unref(udev); - - return found; -} -#else -int serial_autodetect_udev(__maybe_unused detectone_func_t detectone, __maybe_unused const char*prodname) -{ - return 0; -} -#endif - -int serial_autodetect_devserial(__maybe_unused detectone_func_t detectone, __maybe_unused const char*prodname) -{ -#ifndef WIN32 - DIR *D; - struct dirent *de; - const char udevdir[] = "/dev/serial/by-id"; - char devpath[sizeof(udevdir) + 1 + NAME_MAX]; - char *devfile = devpath + sizeof(udevdir); - char found = 0; - - D = opendir(udevdir); - if (!D) - return 0; - memcpy(devpath, udevdir, sizeof(udevdir) - 1); - devpath[sizeof(udevdir) - 1] = '/'; - while ( (de = readdir(D)) ) { - if (!strstr(de->d_name, prodname)) - continue; - strcpy(devfile, de->d_name); - if (detectone(devpath)) - ++found; - } - closedir(D); - - return found; -#else - return 0; -#endif -} - -int _serial_detect(struct device_drv *drv, detectone_func_t detectone, autoscan_func_t autoscan, bool forceauto) -{ - struct string_elist *iter, *tmp; - const char *dev, *colon; - bool inhibitauto = false; - char found = 0; - size_t namel = strlen(drv->name); - size_t dnamel = strlen(drv->dname); - - list_for_each_entry_safe(iter, tmp, &scan_devices, list) { - dev = iter->string; - if ((colon = strchr(dev, ':')) && colon[1] != '\0') { - size_t idlen = colon - dev; - - // allow either name:device or dname:device - if ((idlen != namel || strncasecmp(dev, drv->name, idlen)) - && (idlen != dnamel || strncasecmp(dev, drv->dname, idlen))) - continue; - - dev = colon + 1; - } - if (!strcmp(dev, "auto")) - forceauto = true; - else if (!strcmp(dev, "noauto")) - inhibitauto = true; - else if (detectone(dev)) { - string_elist_del(iter); - inhibitauto = true; - ++found; - } - } - - if ((forceauto || !inhibitauto) && autoscan) - found += autoscan(); - - return found; -} - -// This code is purely for debugging but is very useful for that -// It also took quite a bit of effort so I left it in -// #define TERMIOS_DEBUG 1 -// Here to include it at compile time -// It's off by default -#ifndef WIN32 -#ifdef TERMIOS_DEBUG - -#define BITSSET "Y" -#define BITSNOTSET "N" - -int tiospeed(speed_t speed) -{ - switch (speed) { - case B0: - return 0; - case B50: - return 50; - case B75: - return 75; - case B110: - return 110; - case B134: - return 134; - case B150: - return 150; - case B200: - return 200; - case B300: - return 300; - case B600: - return 600; - case B1200: - return 1200; - case B1800: - return 1800; - case B2400: - return 2400; - case B4800: - return 4800; - case B9600: - return 9600; - case B19200: - return 19200; - case B38400: - return 38400; - case B57600: - return 57600; - case B115200: - return 115200; - case B230400: - return 230400; - case B460800: - return 460800; - case B500000: - return 500000; - case B576000: - return 576000; - case B921600: - return 921600; - case B1000000: - return 1000000; - case B1152000: - return 1152000; - case B1500000: - return 1500000; - case B2000000: - return 2000000; - case B2500000: - return 2500000; - case B3000000: - return 3000000; - case B3500000: - return 3500000; - case B4000000: - return 4000000; - default: - return -1; - } -} - -void termios_debug(const char *devpath, struct termios *my_termios, const char *msg) -{ - applog(LOG_DEBUG, "TIOS: Open %s attributes %s: ispeed=%d ospeed=%d", - devpath, msg, tiospeed(cfgetispeed(my_termios)), tiospeed(cfgetispeed(my_termios))); - -#define ISSETI(b) ((my_termios->c_iflag | (b)) ? BITSSET : BITSNOTSET) - - applog(LOG_DEBUG, "TIOS: c_iflag: IGNBRK=%s BRKINT=%s IGNPAR=%s PARMRK=%s INPCK=%s ISTRIP=%s INLCR=%s IGNCR=%s ICRNL=%s IUCLC=%s IXON=%s IXANY=%s IOFF=%s IMAXBEL=%s IUTF8=%s", - ISSETI(IGNBRK), ISSETI(BRKINT), ISSETI(IGNPAR), ISSETI(PARMRK), - ISSETI(INPCK), ISSETI(ISTRIP), ISSETI(INLCR), ISSETI(IGNCR), - ISSETI(ICRNL), ISSETI(IUCLC), ISSETI(IXON), ISSETI(IXANY), - ISSETI(IXOFF), ISSETI(IMAXBEL), ISSETI(IUTF8)); - -#define ISSETO(b) ((my_termios->c_oflag | (b)) ? BITSSET : BITSNOTSET) -#define VALO(b) (my_termios->c_oflag | (b)) - - applog(LOG_DEBUG, "TIOS: c_oflag: OPOST=%s OLCUC=%s ONLCR=%s OCRNL=%s ONOCR=%s ONLRET=%s OFILL=%s OFDEL=%s NLDLY=%d CRDLY=%d TABDLY=%d BSDLY=%d VTDLY=%d FFDLY=%d", - ISSETO(OPOST), ISSETO(OLCUC), ISSETO(ONLCR), ISSETO(OCRNL), - ISSETO(ONOCR), ISSETO(ONLRET), ISSETO(OFILL), ISSETO(OFDEL), - VALO(NLDLY), VALO(CRDLY), VALO(TABDLY), VALO(BSDLY), - VALO(VTDLY), VALO(FFDLY)); - -#define ISSETC(b) ((my_termios->c_cflag | (b)) ? BITSSET : BITSNOTSET) -#define VALC(b) (my_termios->c_cflag | (b)) - - applog(LOG_DEBUG, "TIOS: c_cflag: CBAUDEX=%s CSIZE=%d CSTOPB=%s CREAD=%s PARENB=%s PARODD=%s HUPCL=%s CLOCAL=%s" -#ifdef LOBLK - " LOBLK=%s" -#endif - " CMSPAR=%s CRTSCTS=%s", - ISSETC(CBAUDEX), VALC(CSIZE), ISSETC(CSTOPB), ISSETC(CREAD), - ISSETC(PARENB), ISSETC(PARODD), ISSETC(HUPCL), ISSETC(CLOCAL), -#ifdef LOBLK - ISSETC(LOBLK), -#endif - ISSETC(CMSPAR), ISSETC(CRTSCTS)); - -#define ISSETL(b) ((my_termios->c_lflag | (b)) ? BITSSET : BITSNOTSET) - - applog(LOG_DEBUG, "TIOS: c_lflag: ISIG=%s ICANON=%s XCASE=%s ECHO=%s ECHOE=%s ECHOK=%s ECHONL=%s ECHOCTL=%s ECHOPRT=%s ECHOKE=%s" -#ifdef DEFECHO - " DEFECHO=%s" -#endif - " FLUSHO=%s NOFLSH=%s TOSTOP=%s PENDIN=%s IEXTEN=%s", - ISSETL(ISIG), ISSETL(ICANON), ISSETL(XCASE), ISSETL(ECHO), - ISSETL(ECHOE), ISSETL(ECHOK), ISSETL(ECHONL), ISSETL(ECHOCTL), - ISSETL(ECHOPRT), ISSETL(ECHOKE), -#ifdef DEFECHO - ISSETL(DEFECHO), -#endif - ISSETL(FLUSHO), ISSETL(NOFLSH), ISSETL(TOSTOP), ISSETL(PENDIN), - ISSETL(IEXTEN)); - -#define VALCC(b) (my_termios->c_cc[b]) - applog(LOG_DEBUG, "TIOS: c_cc: VINTR=0x%02x VQUIT=0x%02x VERASE=0x%02x VKILL=0x%02x VEOF=0x%02x VMIN=%u VEOL=0x%02x VTIME=%u VEOL2=0x%02x" -#ifdef VSWTCH - " VSWTCH=0x%02x" -#endif - " VSTART=0x%02x VSTOP=0x%02x VSUSP=0x%02x" -#ifdef VDSUSP - " VDSUSP=0x%02x" -#endif - " VLNEXT=0x%02x VWERASE=0x%02x VREPRINT=0x%02x VDISCARD=0x%02x" -#ifdef VSTATUS - " VSTATUS=0x%02x" -#endif - , - VALCC(VINTR), VALCC(VQUIT), VALCC(VERASE), VALCC(VKILL), - VALCC(VEOF), VALCC(VMIN), VALCC(VEOL), VALCC(VTIME), - VALCC(VEOL2), -#ifdef VSWTCH - VALCC(VSWTCH), -#endif - VALCC(VSTART), VALCC(VSTOP), VALCC(VSUSP), -#ifdef VDSUSP - VALCC(VDSUSP), -#endif - VALCC(VLNEXT), VALCC(VWERASE), - VALCC(VREPRINT), VALCC(VDISCARD) -#ifdef VSTATUS - ,VALCC(VSTATUS) -#endif - ); -} -#endif -#endif - -int serial_open(const char *devpath, unsigned long baud, signed short timeout, bool purge) -{ -#ifdef WIN32 - HANDLE hSerial = CreateFile(devpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); - if (unlikely(hSerial == INVALID_HANDLE_VALUE)) - { - DWORD e = GetLastError(); - switch (e) { - case ERROR_ACCESS_DENIED: - applog(LOG_ERR, "Do not have user privileges required to open %s", devpath); - break; - case ERROR_SHARING_VIOLATION: - applog(LOG_ERR, "%s is already in use by another process", devpath); - break; - default: - applog(LOG_DEBUG, "Open %s failed, GetLastError:%d", devpath, (int)e); - break; - } - return -1; - } - - // thanks to af_newbie for pointers about this - COMMCONFIG comCfg = {0}; - comCfg.dwSize = sizeof(COMMCONFIG); - comCfg.wVersion = 1; - comCfg.dcb.DCBlength = sizeof(DCB); - comCfg.dcb.BaudRate = baud; - comCfg.dcb.fBinary = 1; - comCfg.dcb.fDtrControl = DTR_CONTROL_ENABLE; - comCfg.dcb.fRtsControl = RTS_CONTROL_ENABLE; - comCfg.dcb.ByteSize = 8; - - SetCommConfig(hSerial, &comCfg, sizeof(comCfg)); - - // Code must specify a valid timeout value (0 means don't timeout) - const DWORD ctoms = (timeout * 100); - COMMTIMEOUTS cto = {ctoms, 0, ctoms, 0, ctoms}; - SetCommTimeouts(hSerial, &cto); - - if (purge) { - PurgeComm(hSerial, PURGE_RXABORT); - PurgeComm(hSerial, PURGE_TXABORT); - PurgeComm(hSerial, PURGE_RXCLEAR); - PurgeComm(hSerial, PURGE_TXCLEAR); - } - - return _open_osfhandle((intptr_t)hSerial, 0); -#else - int fdDev = open(devpath, O_RDWR | O_CLOEXEC | O_NOCTTY); - - if (unlikely(fdDev == -1)) - { - if (errno == EACCES) - applog(LOG_ERR, "Do not have user privileges required to open %s", devpath); - else - applog(LOG_DEBUG, "Open %s failed, errno:%d", devpath, errno); - - return -1; - } - - struct termios my_termios; - - tcgetattr(fdDev, &my_termios); - -#ifdef TERMIOS_DEBUG - termios_debug(devpath, &my_termios, "before"); -#endif - - switch (baud) { - case 0: - break; - case 19200: - cfsetispeed(&my_termios, B19200); - cfsetospeed(&my_termios, B19200); - break; - case 38400: - cfsetispeed(&my_termios, B38400); - cfsetospeed(&my_termios, B38400); - break; - case 57600: - cfsetispeed(&my_termios, B57600); - cfsetospeed(&my_termios, B57600); - break; - case 115200: - cfsetispeed(&my_termios, B115200); - cfsetospeed(&my_termios, B115200); - break; - // TODO: try some higher speeds with the Icarus and BFL to see - // if they support them and if setting them makes any difference - // N.B. B3000000 doesn't work on Icarus - default: - applog(LOG_WARNING, "Unrecognized baud rate: %lu", baud); - } - - my_termios.c_cflag &= ~(CSIZE | PARENB); - my_termios.c_cflag |= CS8; - my_termios.c_cflag |= CREAD; - my_termios.c_cflag |= CLOCAL; - - my_termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | - ISTRIP | INLCR | IGNCR | ICRNL | IXON); - my_termios.c_oflag &= ~OPOST; - my_termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - - // Code must specify a valid timeout value (0 means don't timeout) - my_termios.c_cc[VTIME] = (cc_t)timeout; - my_termios.c_cc[VMIN] = 0; - -#ifdef TERMIOS_DEBUG - termios_debug(devpath, &my_termios, "settings"); -#endif - - tcsetattr(fdDev, TCSANOW, &my_termios); - -#ifdef TERMIOS_DEBUG - tcgetattr(fdDev, &my_termios); - termios_debug(devpath, &my_termios, "after"); -#endif - - if (purge) - tcflush(fdDev, TCIOFLUSH); - return fdDev; -#endif -} - -ssize_t _serial_read(int fd, char *buf, size_t bufsiz, char *eol) -{ - ssize_t len, tlen = 0; - while (bufsiz) { - len = read(fd, buf, eol ? 1 : bufsiz); - if (unlikely(len == -1)) - break; - tlen += len; - if (eol && *eol == buf[0]) - break; - buf += len; - bufsiz -= len; - } - return tlen; -} - -static FILE *_open_bitstream(const char *path, const char *subdir, const char *filename) -{ - char fullpath[PATH_MAX]; - strcpy(fullpath, path); - strcat(fullpath, "/"); - if (subdir) { - strcat(fullpath, subdir); - strcat(fullpath, "/"); - } - strcat(fullpath, filename); - return fopen(fullpath, "rb"); -} -#define _open_bitstream(path, subdir) do { \ - f = _open_bitstream(path, subdir, filename); \ - if (f) \ - return f; \ -} while(0) - -#define _open_bitstream3(path) do { \ - _open_bitstream(path, dname); \ - _open_bitstream(path, "bitstreams"); \ - _open_bitstream(path, NULL); \ -} while(0) - -FILE *open_bitstream(const char *dname, const char *filename) -{ - FILE *f; - - _open_bitstream3(opt_kernel_path); - _open_bitstream3(cgminer_path); - _open_bitstream3("."); - - return NULL; -} - -#ifndef WIN32 - -static bool _select_wait_read(int fd, struct timeval *timeout) -{ - fd_set rfds; - - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - - if (select(fd+1, &rfds, NULL, NULL, timeout) > 0) - return true; - else - return false; -} - -// Default timeout 100ms - only for device initialisation -const struct timeval tv_timeout_default = { 0, 100000 }; -// Default inter character timeout = 1ms - only for device initialisation -const struct timeval tv_inter_char_default = { 0, 1000 }; - -// Device initialisation function - NOT for work processing -size_t _select_read(int fd, char *buf, size_t bufsiz, struct timeval *timeout, struct timeval *char_timeout, int finished) -{ - struct timeval tv_time, tv_char; - ssize_t siz, red = 0; - char got; - - // timeout is the maximum time to wait for the first character - tv_time.tv_sec = timeout->tv_sec; - tv_time.tv_usec = timeout->tv_usec; - - if (!_select_wait_read(fd, &tv_time)) - return 0; - - while (4242) { - if ((siz = read(fd, buf, 1)) < 0) - return red; - - got = *buf; - buf += siz; - red += siz; - bufsiz -= siz; - - if (bufsiz < 1 || (finished >= 0 && got == finished)) - return red; - - // char_timeout is the maximum time to wait for each subsequent character - // this is OK for initialisation, but bad for work processing - // work processing MUST have a fixed size so this doesn't come into play - tv_char.tv_sec = char_timeout->tv_sec; - tv_char.tv_usec = char_timeout->tv_usec; - - if (!_select_wait_read(fd, &tv_char)) - return red; - } - - return red; -} - -// Device initialisation function - NOT for work processing -size_t _select_write(int fd, char *buf, size_t siz, struct timeval *timeout) -{ - struct timeval tv_time, tv_now, tv_finish; - fd_set rfds; - ssize_t wrote = 0, ret; - - cgtime(&tv_now); - timeradd(&tv_now, timeout, &tv_finish); - - // timeout is the maximum time to spend trying to write - tv_time.tv_sec = timeout->tv_sec; - tv_time.tv_usec = timeout->tv_usec; - - FD_ZERO(&rfds); - FD_SET(fd, &rfds); - - while (siz > 0 && (tv_now.tv_sec < tv_finish.tv_sec || (tv_now.tv_sec == tv_finish.tv_sec && tv_now.tv_usec < tv_finish.tv_usec)) && select(fd+1, NULL, &rfds, NULL, &tv_time) > 0) { - if ((ret = write(fd, buf, 1)) > 0) { - buf++; - wrote++; - siz--; - } - else if (ret < 0) - return wrote; - - cgtime(&tv_now); - } - - return wrote; -} - -int get_serial_cts(int fd) -{ - int flags; - - if (!fd) - return -1; - - ioctl(fd, TIOCMGET, &flags); - return (flags & TIOCM_CTS) ? 1 : 0; -} -#else -int get_serial_cts(const int fd) -{ - if (!fd) - return -1; - const HANDLE fh = (HANDLE)_get_osfhandle(fd); - if (!fh) - return -1; - - DWORD flags; - if (!GetCommModemStatus(fh, &flags)) - return -1; - - return (flags & MS_CTS_ON) ? 1 : 0; -} -#endif // ! WIN32 diff --git a/fpgautils.h b/fpgautils.h deleted file mode 100644 index 8a7dd834..00000000 --- a/fpgautils.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2012 Luke Dashjr - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. See COPYING for more details. - */ - -#ifndef FPGAUTILS_H -#define FPGAUTILS_H - -#include -#include - -typedef bool(*detectone_func_t)(const char*); -typedef int(*autoscan_func_t)(); - -extern int _serial_detect(struct device_drv *drv, detectone_func_t, autoscan_func_t, bool force_autoscan); -#define serial_detect_fauto(drv, detectone, autoscan) \ - _serial_detect(drv, detectone, autoscan, true) -#define serial_detect_auto(drv, detectone, autoscan) \ - _serial_detect(drv, detectone, autoscan, false) -#define serial_detect(drv, detectone) \ - _serial_detect(drv, detectone, NULL, false) -extern int serial_autodetect_devserial(detectone_func_t, const char *prodname); -extern int serial_autodetect_udev(detectone_func_t, const char *prodname); - -extern int serial_open(const char *devpath, unsigned long baud, signed short timeout, bool purge); -extern ssize_t _serial_read(int fd, char *buf, size_t buflen, char *eol); -#define serial_read(fd, buf, count) \ - _serial_read(fd, (char*)(buf), count, NULL) -#define serial_read_line(fd, buf, bufsiz, eol) \ - _serial_read(fd, buf, bufsiz, &eol) -#define serial_close(fd) close(fd) - -extern FILE *open_bitstream(const char *dname, const char *filename); - -extern int get_serial_cts(int fd); - -#ifndef WIN32 -extern const struct timeval tv_timeout_default; -extern const struct timeval tv_inter_char_default; - -extern size_t _select_read(int fd, char *buf, size_t bufsiz, struct timeval *timeout, struct timeval *char_timeout, int finished); -extern size_t _select_write(int fd, char *buf, size_t siz, struct timeval *timeout); - -#define select_open(devpath) \ - serial_open(devpath, 0, 0, false) - -#define select_open_purge(devpath, purge)\ - serial_open(devpath, 0, 0, purge) - -#define select_write(fd, buf, siz) \ - _select_write(fd, buf, siz, (struct timeval *)(&tv_timeout_default)) - -#define select_write_full _select_write - -#define select_read(fd, buf, bufsiz) \ - _select_read(fd, buf, bufsiz, (struct timeval *)(&tv_timeout_default), \ - (struct timeval *)(&tv_inter_char_default), -1) - -#define select_read_til(fd, buf, bufsiz, eol) \ - _select_read(fd, buf, bufsiz, (struct timeval *)(&tv_timeout_default), \ - (struct timeval *)(&tv_inter_char_default), eol) - -#define select_read_wait(fd, buf, bufsiz, timeout) \ - _select_read(fd, buf, bufsiz, timeout, \ - (struct timeval *)(&tv_inter_char_default), -1) - -#define select_read_wait_til(fd, buf, bufsiz, timeout, eol) \ - _select_read(fd, buf, bufsiz, timeout, \ - (struct timeval *)(&tv_inter_char_default), eol) - -#define select_read_wait_both(fd, buf, bufsiz, timeout, char_timeout) \ - _select_read(fd, buf, bufsiz, timeout, char_timeout, -1) - -#define select_read_full _select_read - -#define select_close(fd) close(fd) - -#endif // ! WIN32 - -#endif diff --git a/linux-usb-cgminer b/linux-usb-cgminer deleted file mode 100644 index f3d3b541..00000000 --- a/linux-usb-cgminer +++ /dev/null @@ -1,305 +0,0 @@ -How to setup a cgminer using xubuntu 11.04 live on a USB - -The master version of this document is here: - https://github.com/kanoi/linux-usb-cgminer - -The actual file is: - https://github.com/kanoi/linux-usb-cgminer/blob/master/linux-usb-cgminer - -The copy in cgminer (check to make sure it isn't older) is: - https://github.com/ckolivas/cgminer/blob/master/linux-usb-cgminer - -The original old verion on bitcointalk is: - https://bitcointalk.org/index.php?topic=28402.msg426741#msg426741 - -======== - -I have said to select English for the install process for 2 reasons: -1) I don't know any other spoken language very well -and -2) I'm not sure what problems installing under a different language -might cause (it will probably cause no problems but I don't know) - -Software -======== -Short hardware comment: -Your mining computer doesn't need any HDD or CD/DVD/BD as long as it has at -least 2GB of RAM, can boot USB, has some network connection to the internet -and of course a reasonable mining ATI graphics card -... Or you can boot a windows PC with the USB to only do mining ... and ignore -the system HDD ... wasting energy running the HDD (roughly 10 Watts per HDD) :) - -If you wish to install to an HDD instead of a USB, - see the changes to the instructions at the end - -To create the USB, you need of course a 4GB USB and temporarily need a PC -with a CD (or DVD/BD) writer, a USB port and of course an internet -connection to the PC - -1) Download the xubuntu 11.04 desktop live CD iso for amd64 - ( look here for mirrors: http://www.xubuntu.org/getubuntu ) - -2) Burn it to CD then boot that temporarily on any PC with a CD/DVD/BD and - a USB port (this and the next 2 step won't effect that PC) - Select "English" then select "Try Xubuntu without installing" - and wait for the desktop to appear - (this happens by default if you wait for the timeouts) - -3) Plug in your 4GB USB device and it should appear on the desktop - you can - leave it's contents as long as there is at least 2.8GB free - -4) Now run "Startup Disk Creator" in "Applications->System" - (the system menu is the little rat in the top left corner) - -(if you have no mouse you can get the menu with and navigate -the menu with the arrow keys and key) - -From here select the boot CD as the "Source" and the USB as the "Disk to use" -lastly move the slider to 2GB for reserved extra space - -The 2GB should be enough for modifications - -Click: "Make Install Disk" -After about 10-15 minutes you have a base xubuntu 11.04 boot USB -(you can shut down this computer now) - -5) Boot your cgminer PC with this USB stick, select "English" - then select "Try Xubuntu without installing" and wait for the desktop to - appear (this happens by default if you wait for the timeouts) - -6) Start a terminal - "Applications->Accessories->Terminal Emulator" - -7) sudo apt-get install openssh-server screen - - if you have a problem here then it's probably coz the internet isn't - available ... sort that out by reading elsewhere about routers etc - -8) sudo apt-get install fglrx fglrx-amdcccle fglrx-dev - sudo sync - sudo shutdown -r now - -N.B. always do a "sudo sync" and wait for it to finish every time before -shutting down the PC to ensure all data is written to the USB - -9) sudo aticonfig --lsa - this lists your ATI cards so you can see them - sudo aticonfig --adapter=all --odgt - this checks it can access all the cards ... - -10) sudo aticonfig --adapter=all --initial - this gets an error - no idea why but the xorg.conf is OK - sudo sync - sudo shutdown -r now - -11) sudo aticonfig --adapter=all --odgt - this checks it can access all the cards ... - -12) get AMD-APP-SDK-v2.4-lnx64.tgz from - http://developer.amd.com/sdks/amdappsdk/downloads/pages/default.aspx - ( http://developer.amd.com/Downloads/AMD-APP-SDK-v2.4-lnx64.tgz ) - - sudo su - cd /opt - (replace /home/ubuntu/ with wherever you put the file: ) - tar -xvzf /home/ubuntu/AMD-APP-SDK-v2.4-lnx64.tgz - - cd AMD-APP-SDK-v2.4-lnx64/ - cp -pv lib/x86_64/* /usr/lib/ - rsync -avl include/CL/ /usr/include/CL/ - tar -xvzf icd-registration.tgz - rsync -avl etc/OpenCL/ /etc/OpenCL/ - ldconfig - sync - shutdown -r now - - You now have an OpenCL enabled xubuntu - -13) cgminer: - sudo apt-get install curl - - get the binary linux cgminer - (see the bitcoin forum cgminer thread for where to get it) - https://bitcointalk.org/index.php?topic=28402.0 - - ./cgminer -n - this shows you the GPU's it found on your PC - See further below if you get an error regarding libtinfo.so.5 - -14) An OC option: - This is no longer needed since cgminer 2.* includes OC, however: - - sudo apt-get install libwxbase2.8-0 libwxgtk2.8-0 - - http://sourceforge.net/projects/amdovdrvctrl/ - for an Over/underclocking application and get the file listed below then: - sudo dpkg -i amdoverdrivectrl_1.2.1_amd64.deb - -15) set the screen saver to ONLY blank ... - - Move the mouse to the bottom of the screen and you see a set of icons like - on an Apple PC - Click on Settings, then in the Settings window "Screensaver" - Set "Mode:" to "Blank Screen Only" - -16) apt-get install ntpd - An accurate clock is always a good idea :) - -17) if you wish to ssh into the box you must set a password - to do this you simply have to be logged into it at the screen and type - - sudo passwd ubuntu - - it will prompt you (twice) to enter a password for the ubuntu account - - -Initial setup complete. - -======== - -If you want to SSH into the machine and run cgminer: - From a terminal on the miner display each time after you boot: - xhost + - - 'xhost +' isn't needed if you ssh into the machine with the same - username that the GUI boots into (which is 'ubuntu' in this case) - -Then after you ssh into the machine: - export DISPLAY=:0 -before running cgminer - -Also note, that you should force the screen to blank when mining if -the ATI card is displaying the screen (using the screen saver -application menu) -In my case it takes away 50Mh/s when the screen isn't blanked -It will auto blank - but make sure the blank is of course just blank -as mentioned above at 15) - - -This is of course just the basics ... but it should get you a computer -up and running and able to run cgminer - -======== - -You should keep an eye on USB disk space -The system logger writes log files in the /var/log/ directory -The two main ones that grow large are 'kern.log' and 'syslog' -If you want to keep them, save them away to some other computer -When space is low, just delete them e.g. - - sudo rm -i /var/log/syslog - sudo rm -i /var/log/kern.log - -The 'df' command will show you the current space e.g.: - - sudo df - -Filesystem 1K-blocks Used Available Use% Mounted on -aufs 2099420 892024 1100748 45% / -none 1015720 628 1015092 1% /dev -/dev/sda1 3909348 2837248 1072100 73% /cdrom -/dev/loop0 670848 670848 0 100% /rofs -none 1023772 136 1023636 1% /dev/shm -tmpfs 1023772 16 1023756 1% /tmp -none 1023772 124 1023648 1% /var/run -none 1023772 0 1023772 0% /var/lock - - -This shows the 2GB space allocated when you setup the USB as '/' (aufs) -In this example, it's currently 45% full with almost 1.1GB of free space - -======== - -The latest version (2.0.8) of cgminer is built with 11.10 (not 11.04) -If you get the following error when running the prebuilt version in 11.04: - - ./cgminer: error while loading shared libraries: libtinfo.so.5: cannot open shared object file: No such file or directory - -The fix is to simply link the old curses library to the new name e.g.: - - cd /lib64/ - sudo ln -s libncurses.so.5 libtinfo.so.5 - -======== - -If you wish to install to an HDD instead of a USB: --------------------------------------------------- - -As per before: - -1) Download the xubuntu 11.04 desktop live CD iso for amd64 - ( look here for mirrors: http://www.xubuntu.org/getubuntu ) - -Then: - -2) Burn it to CD then boot that on your new mining PC - Select "English" then select "Install Xubuntu" - (you have 30 seconds to do this) - -3) When the Install window comes up - again select "English" and click "Forward" - -4) The next page will show you if you meet certain install requirements - (make sure you do meet them all) - Don't select the download option - The 3rd party option isn't needed for mining so ignore that also - - Click "Forward" - -5) With "Allocate drive space" it's probably easiest to say to use the - "Erase" option. - - This is just for mining right? :) - - However, if you have anything on the HDD that you want to keep - the - "Erase" install process will delete it - so back it up (quit the install) - Also make sure there are no OTHER HDD attached that it may erase also - i.e. only have attached the one HDD that you want to install onto unless - you know exactly what you are doing - - If you see the "Install Xubuntu 11.04 alongside 'something'" then that - just means that the HDD wasn't blank. - If you want to try this option - do that yourself and then skip to step - 7) below when you get to that. - - There are plenty of other options available if you select "Something else" - but I'm not going to go into all the details here other than to say that - my preferred partioning is: /boot = 1GB = ext2, swap = twice memory size, - / = 100GB = ext3 and the rest: /extra = ext3 - - Click "Forward" - -6) If you selected "Erase" then it allows you to choose the drive to install to - Then click "Install Now" - -7) "Where are you?" sort that out then click "Forward" - -8) "Keyboard layout" sort that out (use the default) then click "Forward" - -9) "Who are you?" The important one here is "Pick a username:" coz that's - the name you will need to ssh into, to access it remotely (and of course - the "Choose a Password" you set) - - If you set the "username" to anything but "ubuntu" then: wherever in this - document I have mentioned the username "ubuntu" you must of course use the - username you chose here instead of "ubuntu" - - Important: set it to "log in automatically" if you ever want to be able - to start cgminer without being in front of the computer since 'X' must - be running to use cgminer properly - That does of course mean that the computer isn't secure from anyone who - has access to it - but then again no computer that can automatically - reboot is secure from anyone who has access to the actual computer itself - - Then click "Forward" - -10) Of course when it completes click on "Restart Now" - ... and remove the Xubuntu CD when it asks you - -11) Wait for it to finish rebooting ... and it will auto login - (unless you didn't do step 9) "Important:") - -12) After it logs in, an upgrade popup for 11.10 (or later) will appear - Select "Don't Upgrade" - -13) Now go to step 6) of the USB script above for what to do next and that - covers everything else needed diff --git a/phatk121016.cl b/phatk121016.cl deleted file mode 100644 index 60f28703..00000000 --- a/phatk121016.cl +++ /dev/null @@ -1,417 +0,0 @@ -// This file is taken and modified from the public-domain poclbm project, and -// I have therefore decided to keep it public-domain. -// Modified version copyright 2011-2012 Con Kolivas - -#ifdef VECTORS4 - typedef uint4 u; -#elif defined VECTORS2 - typedef uint2 u; -#else - typedef uint u; -#endif - -__constant uint K[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -}; - -__constant uint ConstW[128] = { -0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000U, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000280U, -0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, - -0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x80000000U, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000100U, -0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 -}; - -__constant uint H[8] = { - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 -}; - - -#ifdef BITALIGN - #pragma OPENCL EXTENSION cl_amd_media_ops : enable - #define rot(x, y) amd_bitalign(x, x, (uint)(32 - y)) - -// This part is not from the stock poclbm kernel. It's part of an optimization -// added in the Phoenix Miner. - -// Some AMD devices have Vals[0] BFI_INT opcode, which behaves exactly like the -// SHA-256 Ch function, but provides it in exactly one instruction. If -// detected, use it for Ch. Otherwise, construct Ch out of simpler logical -// primitives. - - #ifdef BFI_INT - // Well, slight problem... It turns out BFI_INT isn't actually exposed to - // OpenCL (or CAL IL for that matter) in any way. However, there is - // a similar instruction, BYTE_ALIGN_INT, which is exposed to OpenCL via - // amd_bytealign, takes the same inputs, and provides the same output. - // We can use that as a placeholder for BFI_INT and have the application - // patch it after compilation. - - // This is the BFI_INT function - #define Ch(x, y, z) amd_bytealign(x,y,z) - // Ma can also be implemented in terms of BFI_INT... - #define Ma(z, x, y) amd_bytealign(z^x,y,x) - #else // BFI_INT - // Later SDKs optimise this to BFI INT without patching and GCN - // actually fails if manually patched with BFI_INT - - #define Ch(x, y, z) bitselect((u)z, (u)y, (u)x) - #define Ma(x, y, z) bitselect((u)x, (u)y, (u)z ^ (u)x) - #define rotr(x, y) amd_bitalign((u)x, (u)x, (u)y) - #endif -#else // BITALIGN - #define Ch(x, y, z) (z ^ (x & (y ^ z))) - #define Ma(x, y, z) ((x & z) | (y & (x | z))) - #define rot(x, y) rotate((u)x, (u)y) - #define rotr(x, y) rotate((u)x, (u)(32-y)) -#endif - - - -//Various intermediate calculations for each SHA round -#define s0(n) (S0(Vals[(0 + 128 - (n)) % 8])) -#define S0(n) (rot(n, 30u)^rot(n, 19u)^rot(n,10u)) - -#define s1(n) (S1(Vals[(4 + 128 - (n)) % 8])) -#define S1(n) (rot(n, 26u)^rot(n, 21u)^rot(n, 7u)) - -#define ch(n) Ch(Vals[(4 + 128 - (n)) % 8],Vals[(5 + 128 - (n)) % 8],Vals[(6 + 128 - (n)) % 8]) -#define maj(n) Ma(Vals[(1 + 128 - (n)) % 8],Vals[(2 + 128 - (n)) % 8],Vals[(0 + 128 - (n)) % 8]) - -//t1 calc when W is already calculated -#define t1(n) K[(n) % 64] + Vals[(7 + 128 - (n)) % 8] + W[(n)] + s1(n) + ch(n) - -//t1 calc which calculates W -#define t1W(n) K[(n) % 64] + Vals[(7 + 128 - (n)) % 8] + W(n) + s1(n) + ch(n) - -//Used for constant W Values (the compiler optimizes out zeros) -#define t1C(n) (K[(n) % 64]+ ConstW[(n)]) + Vals[(7 + 128 - (n)) % 8] + s1(n) + ch(n) - -//t2 Calc -#define t2(n) maj(n) + s0(n) - -#define rotC(x,n) (x<> (32-n)) - -//W calculation used for SHA round -#define W(n) (W[n] = P4(n) + P3(n) + P2(n) + P1(n)) - - - -//Partial W calculations (used for the begining where only some values are nonzero) -#define P1(n) ((rot(W[(n)-2],15u)^rot(W[(n)-2],13u)^((W[(n)-2])>>10U))) -#define P2(n) ((rot(W[(n)-15],25u)^rot(W[(n)-15],14u)^((W[(n)-15])>>3U))) - - -#define p1(x) ((rot(x,15u)^rot(x,13u)^((x)>>10U))) -#define p2(x) ((rot(x,25u)^rot(x,14u)^((x)>>3U))) - - -#define P3(n) W[n-7] -#define P4(n) W[n-16] - - -//Partial Calcs for constant W values -#define P1C(n) ((rotC(ConstW[(n)-2],15)^rotC(ConstW[(n)-2],13)^((ConstW[(n)-2])>>10U))) -#define P2C(n) ((rotC(ConstW[(n)-15],25)^rotC(ConstW[(n)-15],14)^((ConstW[(n)-15])>>3U))) -#define P3C(x) ConstW[x-7] -#define P4C(x) ConstW[x-16] - -//SHA round with built in W calc -#define sharoundW(n) Barrier1(n); Vals[(3 + 128 - (n)) % 8] += t1W(n); Vals[(7 + 128 - (n)) % 8] = t1W(n) + t2(n); - -//SHA round without W calc -#define sharound(n) Barrier2(n); Vals[(3 + 128 - (n)) % 8] += t1(n); Vals[(7 + 128 - (n)) % 8] = t1(n) + t2(n); - -//SHA round for constant W values -#define sharoundC(n) Barrier3(n); Vals[(3 + 128 - (n)) % 8] += t1C(n); Vals[(7 + 128 - (n)) % 8] = t1C(n) + t2(n); - -//The compiler is stupid... I put this in there only to stop the compiler from (de)optimizing the order -#define Barrier1(n) t1 = t1C((n+1)) -#define Barrier2(n) t1 = t1C((n)) -#define Barrier3(n) t1 = t1C((n)) - -//#define WORKSIZE 256 -#define MAXBUFFERS (4095) - -__kernel - __attribute__((reqd_work_group_size(WORKSIZE, 1, 1))) -void search( const uint state0, const uint state1, const uint state2, const uint state3, - const uint state4, const uint state5, const uint state6, const uint state7, - const uint B1, const uint C1, const uint D1, - const uint F1, const uint G1, const uint H1, - const u base, - const uint W16, const uint W17, - const uint PreVal4, const uint PreVal0, - const uint PreW18, const uint PreW19, - const uint PreW31, const uint PreW32, - - volatile __global uint * output) -{ - - - u W[124]; - u Vals[8]; - -//Dummy Variable to prevent compiler from reordering between rounds - u t1; - - //Vals[0]=state0; - Vals[1]=B1; - Vals[2]=C1; - Vals[3]=D1; - //Vals[4]=PreVal4; - Vals[5]=F1; - Vals[6]=G1; - Vals[7]=H1; - - W[16] = W16; - W[17] = W17; - -#ifdef VECTORS4 - //Less dependencies to get both the local id and group id and then add them - W[3] = base + (uint)(get_local_id(0)) * 4u + (uint)(get_group_id(0)) * (WORKSIZE * 4u); - uint r = rot(W[3].x,25u)^rot(W[3].x,14u)^((W[3].x)>>3U); - //Since only the 2 LSB is opposite between the nonces, we can save an instruction by flipping the 4 bits in W18 rather than the 1 bit in W3 - W[18] = PreW18 + (u){r, r ^ 0x2004000U, r ^ 0x4008000U, r ^ 0x600C000U}; -#elif defined VECTORS2 - W[3] = base + (uint)(get_local_id(0)) * 2u + (uint)(get_group_id(0)) * (WORKSIZE * 2u); - uint r = rot(W[3].x,25u)^rot(W[3].x,14u)^((W[3].x)>>3U); - W[18] = PreW18 + (u){r, r ^ 0x2004000U}; -#else - W[3] = base + get_local_id(0) + get_group_id(0) * (WORKSIZE); - u r = rot(W[3],25u)^rot(W[3],14u)^((W[3])>>3U); - W[18] = PreW18 + r; -#endif - //the order of the W calcs and Rounds is like this because the compiler needs help finding how to order the instructions - - - - Vals[4] = PreVal4 + W[3]; - Vals[0] = PreVal0 + W[3]; - - sharoundC(4); - W[19] = PreW19 + W[3]; - sharoundC(5); - W[20] = P4C(20) + P1(20); - sharoundC(6); - W[21] = P1(21); - sharoundC(7); - W[22] = P3C(22) + P1(22); - sharoundC(8); - W[23] = W[16] + P1(23); - sharoundC(9); - W[24] = W[17] + P1(24); - sharoundC(10); - W[25] = P1(25) + P3(25); - W[26] = P1(26) + P3(26); - sharoundC(11); - W[27] = P1(27) + P3(27); - W[28] = P1(28) + P3(28); - sharoundC(12); - W[29] = P1(29) + P3(29); - sharoundC(13); - W[30] = P1(30) + P2C(30) + P3(30); - W[31] = PreW31 + (P1(31) + P3(31)); - sharoundC(14); - W[32] = PreW32 + (P1(32) + P3(32)); - sharoundC(15); - sharound(16); - sharound(17); - sharound(18); - sharound(19); - sharound(20); - sharound(21); - sharound(22); - sharound(23); - sharound(24); - sharound(25); - sharound(26); - sharound(27); - sharound(28); - sharound(29); - sharound(30); - sharound(31); - sharound(32); - sharoundW(33); - sharoundW(34); - sharoundW(35); - sharoundW(36); - sharoundW(37); - sharoundW(38); - sharoundW(39); - sharoundW(40); - sharoundW(41); - sharoundW(42); - sharoundW(43); - sharoundW(44); - sharoundW(45); - sharoundW(46); - sharoundW(47); - sharoundW(48); - sharoundW(49); - sharoundW(50); - sharoundW(51); - sharoundW(52); - sharoundW(53); - sharoundW(54); - sharoundW(55); - sharoundW(56); - sharoundW(57); - sharoundW(58); - sharoundW(59); - sharoundW(60); - sharoundW(61); - sharoundW(62); - sharoundW(63); - - W[64]=state0+Vals[0]; - W[65]=state1+Vals[1]; - W[66]=state2+Vals[2]; - W[67]=state3+Vals[3]; - W[68]=state4+Vals[4]; - W[69]=state5+Vals[5]; - W[70]=state6+Vals[6]; - W[71]=state7+Vals[7]; - - Vals[0]=H[0]; - Vals[1]=H[1]; - Vals[2]=H[2]; - Vals[3]=H[3]; - Vals[4]=H[4]; - Vals[5]=H[5]; - Vals[6]=H[6]; - Vals[7]=H[7]; - - //sharound(64 + 0); - const u Temp = (0xb0edbdd0U + K[0]) + W[64]; - Vals[7] = Temp + 0x08909ae5U; - Vals[3] = 0xa54ff53aU + Temp; - -#define P124(n) P2(n) + P1(n) + P4(n) - - - W[64 + 16] = + P2(64 + 16) + P4(64 + 16); - sharound(64 + 1); - W[64 + 17] = P1C(64 + 17) + P2(64 + 17) + P4(64 + 17); - sharound(64 + 2); - W[64 + 18] = P124(64 + 18); - sharound(64 + 3); - W[64 + 19] = P124(64 + 19); - sharound(64 + 4); - W[64 + 20] = P124(64 + 20); - sharound(64 + 5); - W[64 + 21] = P124(64 + 21); - sharound(64 + 6); - W[64 + 22] = P4(64 + 22) + P3C(64 + 22) + P2(64 + 22) + P1(64 + 22); - sharound(64 + 7); - W[64 + 23] = P4(64 + 23) + P3(64 + 23) + P2C(64 + 23) + P1(64 + 23); - sharoundC(64 + 8); - W[64 + 24] = P1(64 + 24) + P4C(64 + 24) + P3(64 + 24); - sharoundC(64 + 9); - W[64 + 25] = P3(64 + 25) + P1(64 + 25); - sharoundC(64 + 10); - W[64 + 26] = P3(64 + 26) + P1(64 + 26); - sharoundC(64 + 11); - W[64 + 27] = P3(64 + 27) + P1(64 + 27); - sharoundC(64 + 12); - W[64 + 28] = P3(64 + 28) + P1(64 + 28); - sharoundC(64 + 13); - W[64 + 29] = P1(64 + 29) + P3(64 + 29); - W[64 + 30] = P3(64 + 30) + P2C(64 + 30) + P1(64 + 30); - sharoundC(64 + 14); - W[64 + 31] = P4C(64 + 31) + P3(64 + 31) + P2(64 + 31) + P1(64 + 31); - sharoundC(64 + 15); - sharound(64 + 16); - sharound(64 + 17); - sharound(64 + 18); - sharound(64 + 19); - sharound(64 + 20); - sharound(64 + 21); - sharound(64 + 22); - sharound(64 + 23); - sharound(64 + 24); - sharound(64 + 25); - sharound(64 + 26); - sharound(64 + 27); - sharound(64 + 28); - sharound(64 + 29); - sharound(64 + 30); - sharound(64 + 31); - sharoundW(64 + 32); - sharoundW(64 + 33); - sharoundW(64 + 34); - sharoundW(64 + 35); - sharoundW(64 + 36); - sharoundW(64 + 37); - sharoundW(64 + 38); - sharoundW(64 + 39); - sharoundW(64 + 40); - sharoundW(64 + 41); - sharoundW(64 + 42); - sharoundW(64 + 43); - sharoundW(64 + 44); - sharoundW(64 + 45); - sharoundW(64 + 46); - sharoundW(64 + 47); - sharoundW(64 + 48); - sharoundW(64 + 49); - sharoundW(64 + 50); - sharoundW(64 + 51); - sharoundW(64 + 52); - sharoundW(64 + 53); - sharoundW(64 + 54); - sharoundW(64 + 55); - sharoundW(64 + 56); - sharoundW(64 + 57); - sharoundW(64 + 58); - - W[117] += W[108] + Vals[3] + Vals[7] + P2(124) + P1(124) + Ch((Vals[0] + Vals[4]) + (K[59] + W(59+64)) + s1(64+59)+ ch(59+64),Vals[1],Vals[2]) - - (-(K[60] + H[7]) - S1((Vals[0] + Vals[4]) + (K[59] + W(59+64)) + s1(64+59)+ ch(59+64))); - -#define FOUND (0x0F) -#define SETFOUND(Xnonce) output[output[FOUND]++] = Xnonce - -#ifdef VECTORS4 - bool result = W[117].x & W[117].y & W[117].z & W[117].w; - if (!result) { - if (!W[117].x) - SETFOUND(W[3].x); - if (!W[117].y) - SETFOUND(W[3].y); - if (!W[117].z) - SETFOUND(W[3].z); - if (!W[117].w) - SETFOUND(W[3].w); - } -#elif defined VECTORS2 - bool result = W[117].x & W[117].y; - if (!result) { - if (!W[117].x) - SETFOUND(W[3].x); - if (!W[117].y) - SETFOUND(W[3].y); - } -#else - if (!W[117]) - SETFOUND(W[3]); -#endif -} diff --git a/poclbm130302.cl b/poclbm130302.cl deleted file mode 100644 index 6f5fd014..00000000 --- a/poclbm130302.cl +++ /dev/null @@ -1,1388 +0,0 @@ -// -ck modified kernel taken from Phoenix taken from poclbm, with aspects of -// phatk and others. -// Modified version copyright 2011-2012 Con Kolivas - -// This file is taken and modified from the public-domain poclbm project, and -// we have therefore decided to keep it public-domain in Phoenix. - -#ifdef VECTORS4 - typedef uint4 u; -#elif defined VECTORS2 - typedef uint2 u; -#else - typedef uint u; -#endif - -__constant uint K[87] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, - - 0xc19bf3f4U, - 0x80000000U, - 0x00000280U, - 0x00a00055U, - 0xf377ed68U, - 0xa54ff53aU, - 0x08909ae5U, - 0x90bb1e3cU, - 0x9b05688cU, - 0xca0b3af3U, - 0x3c6ef372U, - 0xbb67ae85U, - 0x6a09e667U, - 0x50c6645bU, - 0x510e527fU, - 0x3ac42e24U, - 0x5807aa98U, - 0xc19bf274U, - 0x00a00000U, - 0x00000100U, - 0x11002000U, - 0x00400022U, - 0x136032edU -}; - -#define xc19bf3f4U K[64] -#define x80000000U K[65] -#define x00000280U K[66] -#define x00a00055U K[67] -#define xf377ed68U K[68] -#define xa54ff53aU K[69] -#define x08909ae5U K[70] -#define x90bb1e3cU K[71] -#define x9b05688cU K[72] -#define xca0b3af3U K[73] -#define x3c6ef372U K[74] -#define xbb67ae85U K[75] -#define x6a09e667U K[76] -#define x50c6645bU K[77] -#define x510e527fU K[78] -#define x3ac42e24U K[79] -#define x5807aa98U K[80] -#define xc19bf274U K[81] -#define x00a00000U K[82] -#define x00000100U K[83] -#define x11002000U K[84] -#define x00400022U K[85] -#define x136032edU K[86] - -// This part is not from the stock poclbm kernel. It's part of an optimization -// added in the Phoenix Miner. - -// Some AMD devices have a BFI_INT opcode, which behaves exactly like the -// SHA-256 ch function, but provides it in exactly one instruction. If -// detected, use it for ch. Otherwise, construct ch out of simpler logical -// primitives. - -#ifdef BITALIGN - #pragma OPENCL EXTENSION cl_amd_media_ops : enable - #define rotr(x, y) amd_bitalign((u)x, (u)x, (u)y) -#else - #define rotr(x, y) rotate((u)x, (u)(32 - y)) -#endif -#ifdef BFI_INT - // Well, slight problem... It turns out BFI_INT isn't actually exposed to - // OpenCL (or CAL IL for that matter) in any way. However, there is - // a similar instruction, BYTE_ALIGN_INT, which is exposed to OpenCL via - // amd_bytealign, takes the same inputs, and provides the same output. - // We can use that as a placeholder for BFI_INT and have the application - // patch it after compilation. - - // This is the BFI_INT function - #define ch(x, y, z) amd_bytealign(x, y, z) - - // Ma can also be implemented in terms of BFI_INT... - #define Ma(x, y, z) amd_bytealign( (z^x), (y), (x) ) - - // AMD's KernelAnalyzer throws errors compiling the kernel if we use - // amd_bytealign on constants with vectors enabled, so we use this to avoid - // problems. (this is used 4 times, and likely optimized out by the compiler.) - #define Ma2(x, y, z) bitselect((u)x, (u)y, (u)z ^ (u)x) -#else // BFI_INT - //GCN actually fails if manually patched with BFI_INT - - #define ch(x, y, z) bitselect((u)z, (u)y, (u)x) - #define Ma(x, y, z) bitselect((u)x, (u)y, (u)z ^ (u)x) - #define Ma2(x, y, z) Ma(x, y, z) -#endif - - -__kernel -__attribute__((vec_type_hint(u))) -__attribute__((reqd_work_group_size(WORKSIZE, 1, 1))) -void search(const uint state0, const uint state1, const uint state2, const uint state3, - const uint state4, const uint state5, const uint state6, const uint state7, - const uint b1, const uint c1, - const uint f1, const uint g1, const uint h1, -#ifndef GOFFSET - const u base, -#endif - const uint fw0, const uint fw1, const uint fw2, const uint fw3, const uint fw15, const uint fw01r, - const uint D1A, const uint C1addK5, const uint B1addK6, - const uint W16addK16, const uint W17addK17, - const uint PreVal4addT1, const uint Preval0, - volatile __global uint * output) -{ - u Vals[24]; - u *W = &Vals[8]; - -#ifdef GOFFSET - const u nonce = (uint)(get_global_id(0)); -#else - const u nonce = base + (uint)(get_global_id(0)); -#endif - -Vals[5]=Preval0; -Vals[5]+=nonce; - -Vals[0]=(rotr(Vals[5],6)^rotr(Vals[5],11)^rotr(Vals[5],25)); -Vals[0]+=ch(Vals[5],b1,c1); -Vals[0]+=D1A; - -Vals[2]=Vals[0]; -Vals[2]+=h1; - -Vals[1]=PreVal4addT1; -Vals[1]+=nonce; -Vals[0]+=(rotr(Vals[1],2)^rotr(Vals[1],13)^rotr(Vals[1],22)); - -Vals[6]=C1addK5; -Vals[6]+=(rotr(Vals[2],6)^rotr(Vals[2],11)^rotr(Vals[2],25)); -Vals[6]+=ch(Vals[2],Vals[5],b1); - -Vals[3]=Vals[6]; -Vals[3]+=g1; -Vals[0]+=Ma2(g1,Vals[1],f1); -Vals[6]+=(rotr(Vals[0],2)^rotr(Vals[0],13)^rotr(Vals[0],22)); -Vals[6]+=Ma2(f1,Vals[0],Vals[1]); - -Vals[7]=B1addK6; -Vals[7]+=(rotr(Vals[3],6)^rotr(Vals[3],11)^rotr(Vals[3],25)); -Vals[7]+=ch(Vals[3],Vals[2],Vals[5]); - -Vals[4]=Vals[7]; -Vals[4]+=f1; - -Vals[7]+=(rotr(Vals[6],2)^rotr(Vals[6],13)^rotr(Vals[6],22)); -Vals[7]+=Ma(Vals[1],Vals[6],Vals[0]); - -Vals[5]+=(rotr(Vals[4],6)^rotr(Vals[4],11)^rotr(Vals[4],25)); -Vals[5]+=ch(Vals[4],Vals[3],Vals[2]); -Vals[5]+=K[7]; -Vals[1]+=Vals[5]; -Vals[5]+=(rotr(Vals[7],2)^rotr(Vals[7],13)^rotr(Vals[7],22)); -Vals[5]+=Ma(Vals[0],Vals[7],Vals[6]); - -Vals[2]+=(rotr(Vals[1],6)^rotr(Vals[1],11)^rotr(Vals[1],25)); -Vals[2]+=ch(Vals[1],Vals[4],Vals[3]); -Vals[2]+=K[8]; -Vals[0]+=Vals[2]; -Vals[2]+=(rotr(Vals[5],2)^rotr(Vals[5],13)^rotr(Vals[5],22)); -Vals[2]+=Ma(Vals[6],Vals[5],Vals[7]); - -Vals[3]+=(rotr(Vals[0],6)^rotr(Vals[0],11)^rotr(Vals[0],25)); -Vals[3]+=ch(Vals[0],Vals[1],Vals[4]); -Vals[3]+=K[9]; -Vals[6]+=Vals[3]; -Vals[3]+=(rotr(Vals[2],2)^rotr(Vals[2],13)^rotr(Vals[2],22)); -Vals[3]+=Ma(Vals[7],Vals[2],Vals[5]); - -Vals[4]+=(rotr(Vals[6],6)^rotr(Vals[6],11)^rotr(Vals[6],25)); -Vals[4]+=ch(Vals[6],Vals[0],Vals[1]); -Vals[4]+=K[10]; -Vals[7]+=Vals[4]; -Vals[4]+=(rotr(Vals[3],2)^rotr(Vals[3],13)^rotr(Vals[3],22)); -Vals[4]+=Ma(Vals[5],Vals[3],Vals[2]); - -Vals[1]+=(rotr(Vals[7],6)^rotr(Vals[7],11)^rotr(Vals[7],25)); -Vals[1]+=ch(Vals[7],Vals[6],Vals[0]); -Vals[1]+=K[11]; -Vals[5]+=Vals[1]; -Vals[1]+=(rotr(Vals[4],2)^rotr(Vals[4],13)^rotr(Vals[4],22)); -Vals[1]+=Ma(Vals[2],Vals[4],Vals[3]); - -Vals[0]+=(rotr(Vals[5],6)^rotr(Vals[5],11)^rotr(Vals[5],25)); -Vals[0]+=ch(Vals[5],Vals[7],Vals[6]); -Vals[0]+=K[12]; -Vals[2]+=Vals[0]; -Vals[0]+=(rotr(Vals[1],2)^rotr(Vals[1],13)^rotr(Vals[1],22)); -Vals[0]+=Ma(Vals[3],Vals[1],Vals[4]); - -Vals[6]+=(rotr(Vals[2],6)^rotr(Vals[2],11)^rotr(Vals[2],25)); -Vals[6]+=ch(Vals[2],Vals[5],Vals[7]); -Vals[6]+=K[13]; -Vals[3]+=Vals[6]; -Vals[6]+=(rotr(Vals[0],2)^rotr(Vals[0],13)^rotr(Vals[0],22)); -Vals[6]+=Ma(Vals[4],Vals[0],Vals[1]); - -Vals[7]+=(rotr(Vals[3],6)^rotr(Vals[3],11)^rotr(Vals[3],25)); -Vals[7]+=ch(Vals[3],Vals[2],Vals[5]); -Vals[7]+=K[14]; -Vals[4]+=Vals[7]; -Vals[7]+=(rotr(Vals[6],2)^rotr(Vals[6],13)^rotr(Vals[6],22)); -Vals[7]+=Ma(Vals[1],Vals[6],Vals[0]); - -Vals[5]+=(rotr(Vals[4],6)^rotr(Vals[4],11)^rotr(Vals[4],25)); -Vals[5]+=ch(Vals[4],Vals[3],Vals[2]); -Vals[5]+=xc19bf3f4U; -Vals[1]+=Vals[5]; -Vals[5]+=(rotr(Vals[7],2)^rotr(Vals[7],13)^rotr(Vals[7],22)); -Vals[5]+=Ma(Vals[0],Vals[7],Vals[6]); - -Vals[2]+=(rotr(Vals[1],6)^rotr(Vals[1],11)^rotr(Vals[1],25)); -Vals[2]+=ch(Vals[1],Vals[4],Vals[3]); -Vals[2]+=W16addK16; -Vals[0]+=Vals[2]; -Vals[2]+=(rotr(Vals[5],2)^rotr(Vals[5],13)^rotr(Vals[5],22)); -Vals[2]+=Ma(Vals[6],Vals[5],Vals[7]); - -Vals[3]+=(rotr(Vals[0],6)^rotr(Vals[0],11)^rotr(Vals[0],25)); -Vals[3]+=ch(Vals[0],Vals[1],Vals[4]); -Vals[3]+=W17addK17; -Vals[6]+=Vals[3]; -Vals[3]+=(rotr(Vals[2],2)^rotr(Vals[2],13)^rotr(Vals[2],22)); -Vals[3]+=Ma(Vals[7],Vals[2],Vals[5]); - -W[2]=(rotr(nonce,7)^rotr(nonce,18)^(nonce>>3U)); -W[2]+=fw2; -Vals[4]+=W[2]; -Vals[4]+=(rotr(Vals[6],6)^rotr(Vals[6],11)^rotr(Vals[6],25)); -Vals[4]+=ch(Vals[6],Vals[0],Vals[1]); -Vals[4]+=K[18]; -Vals[7]+=Vals[4]; -Vals[4]+=(rotr(Vals[3],2)^rotr(Vals[3],13)^rotr(Vals[3],22)); -Vals[4]+=Ma(Vals[5],Vals[3],Vals[2]); - -W[3]=nonce; -W[3]+=fw3; -Vals[1]+=W[3]; -Vals[1]+=(rotr(Vals[7],6)^rotr(Vals[7],11)^rotr(Vals[7],25)); -Vals[1]+=ch(Vals[7],Vals[6],Vals[0]); -Vals[1]+=K[19]; -Vals[5]+=Vals[1]; -Vals[1]+=(rotr(Vals[4],2)^rotr(Vals[4],13)^rotr(Vals[4],22)); -Vals[1]+=Ma(Vals[2],Vals[4],Vals[3]); - -W[4]=(rotr(W[2],17)^rotr(W[2],19)^(W[2]>>10U)); -W[4]+=x80000000U; -Vals[0]+=W[4]; -Vals[0]+=(rotr(Vals[5],6)^rotr(Vals[5],11)^rotr(Vals[5],25)); -Vals[0]+=ch(Vals[5],Vals[7],Vals[6]); -Vals[0]+=K[20]; -Vals[2]+=Vals[0]; -Vals[0]+=(rotr(Vals[1],2)^rotr(Vals[1],13)^rotr(Vals[1],22)); -Vals[0]+=Ma(Vals[3],Vals[1],Vals[4]); - -W[5]=(rotr(W[3],17)^rotr(W[3],19)^(W[3]>>10U)); -Vals[6]+=W[5]; -Vals[6]+=(rotr(Vals[2],6)^rotr(Vals[2],11)^rotr(Vals[2],25)); -Vals[6]+=ch(Vals[2],Vals[5],Vals[7]); -Vals[6]+=K[21]; -Vals[3]+=Vals[6]; -Vals[6]+=(rotr(Vals[0],2)^rotr(Vals[0],13)^rotr(Vals[0],22)); -Vals[6]+=Ma(Vals[4],Vals[0],Vals[1]); - -W[6]=(rotr(W[4],17)^rotr(W[4],19)^(W[4]>>10U)); -W[6]+=x00000280U; -Vals[7]+=W[6]; -Vals[7]+=(rotr(Vals[3],6)^rotr(Vals[3],11)^rotr(Vals[3],25)); -Vals[7]+=ch(Vals[3],Vals[2],Vals[5]); -Vals[7]+=K[22]; -Vals[4]+=Vals[7]; -Vals[7]+=(rotr(Vals[6],2)^rotr(Vals[6],13)^rotr(Vals[6],22)); -Vals[7]+=Ma(Vals[1],Vals[6],Vals[0]); - -W[7]=(rotr(W[5],17)^rotr(W[5],19)^(W[5]>>10U)); -W[7]+=fw0; -Vals[5]+=W[7]; -Vals[5]+=(rotr(Vals[4],6)^rotr(Vals[4],11)^rotr(Vals[4],25)); -Vals[5]+=ch(Vals[4],Vals[3],Vals[2]); -Vals[5]+=K[23]; -Vals[1]+=Vals[5]; -Vals[5]+=(rotr(Vals[7],2)^rotr(Vals[7],13)^rotr(Vals[7],22)); -Vals[5]+=Ma(Vals[0],Vals[7],Vals[6]); - -W[8]=(rotr(W[6],17)^rotr(W[6],19)^(W[6]>>10U)); -W[8]+=fw1; -Vals[2]+=W[8]; -Vals[2]+=(rotr(Vals[1],6)^rotr(Vals[1],11)^rotr(Vals[1],25)); -Vals[2]+=ch(Vals[1],Vals[4],Vals[3]); -Vals[2]+=K[24]; -Vals[0]+=Vals[2]; -Vals[2]+=(rotr(Vals[5],2)^rotr(Vals[5],13)^rotr(Vals[5],22)); -Vals[2]+=Ma(Vals[6],Vals[5],Vals[7]); - -W[9]=W[2]; -W[9]+=(rotr(W[7],17)^rotr(W[7],19)^(W[7]>>10U)); -Vals[3]+=W[9]; -Vals[3]+=(rotr(Vals[0],6)^rotr(Vals[0],11)^rotr(Vals[0],25)); -Vals[3]+=ch(Vals[0],Vals[1],Vals[4]); -Vals[3]+=K[25]; -Vals[6]+=Vals[3]; -Vals[3]+=(rotr(Vals[2],2)^rotr(Vals[2],13)^rotr(Vals[2],22)); -Vals[3]+=Ma(Vals[7],Vals[2],Vals[5]); - -W[10]=W[3]; -W[10]+=(rotr(W[8],17)^rotr(W[8],19)^(W[8]>>10U)); -Vals[4]+=W[10]; -Vals[4]+=(rotr(Vals[6],6)^rotr(Vals[6],11)^rotr(Vals[6],25)); -Vals[4]+=ch(Vals[6],Vals[0],Vals[1]); -Vals[4]+=K[26]; -Vals[7]+=Vals[4]; -Vals[4]+=(rotr(Vals[3],2)^rotr(Vals[3],13)^rotr(Vals[3],22)); -Vals[4]+=Ma(Vals[5],Vals[3],Vals[2]); - -W[11]=W[4]; -W[11]+=(rotr(W[9],17)^rotr(W[9],19)^(W[9]>>10U)); -Vals[1]+=W[11]; -Vals[1]+=(rotr(Vals[7],6)^rotr(Vals[7],11)^rotr(Vals[7],25)); -Vals[1]+=ch(Vals[7],Vals[6],Vals[0]); -Vals[1]+=K[27]; -Vals[5]+=Vals[1]; -Vals[1]+=(rotr(Vals[4],2)^rotr(Vals[4],13)^rotr(Vals[4],22)); -Vals[1]+=Ma(Vals[2],Vals[4],Vals[3]); - -W[12]=W[5]; -W[12]+=(rotr(W[10],17)^rotr(W[10],19)^(W[10]>>10U)); -Vals[0]+=W[12]; -Vals[0]+=(rotr(Vals[5],6)^rotr(Vals[5],11)^rotr(Vals[5],25)); -Vals[0]+=ch(Vals[5],Vals[7],Vals[6]); -Vals[0]+=K[28]; -Vals[2]+=Vals[0]; -Vals[0]+=(rotr(Vals[1],2)^rotr(Vals[1],13)^rotr(Vals[1],22)); -Vals[0]+=Ma(Vals[3],Vals[1],Vals[4]); - -W[13]=W[6]; -W[13]+=(rotr(W[11],17)^rotr(W[11],19)^(W[11]>>10U)); -Vals[6]+=W[13]; -Vals[6]+=(rotr(Vals[2],6)^rotr(Vals[2],11)^rotr(Vals[2],25)); -Vals[6]+=ch(Vals[2],Vals[5],Vals[7]); -Vals[6]+=K[29]; -Vals[3]+=Vals[6]; -Vals[6]+=(rotr(Vals[0],2)^rotr(Vals[0],13)^rotr(Vals[0],22)); -Vals[6]+=Ma(Vals[4],Vals[0],Vals[1]); - -W[14]=x00a00055U; -W[14]+=W[7]; -W[14]+=(rotr(W[12],17)^rotr(W[12],19)^(W[12]>>10U)); -Vals[7]+=W[14]; -Vals[7]+=(rotr(Vals[3],6)^rotr(Vals[3],11)^rotr(Vals[3],25)); -Vals[7]+=ch(Vals[3],Vals[2],Vals[5]); -Vals[7]+=K[30]; -Vals[4]+=Vals[7]; -Vals[7]+=(rotr(Vals[6],2)^rotr(Vals[6],13)^rotr(Vals[6],22)); -Vals[7]+=Ma(Vals[1],Vals[6],Vals[0]); - -W[15]=fw15; -W[15]+=W[8]; -W[15]+=(rotr(W[13],17)^rotr(W[13],19)^(W[13]>>10U)); -Vals[5]+=W[15]; -Vals[5]+=(rotr(Vals[4],6)^rotr(Vals[4],11)^rotr(Vals[4],25)); -Vals[5]+=ch(Vals[4],Vals[3],Vals[2]); -Vals[5]+=K[31]; -Vals[1]+=Vals[5]; -Vals[5]+=(rotr(Vals[7],2)^rotr(Vals[7],13)^rotr(Vals[7],22)); -Vals[5]+=Ma(Vals[0],Vals[7],Vals[6]); - -W[0]=fw01r; -W[0]+=W[9]; -W[0]+=(rotr(W[14],17)^rotr(W[14],19)^(W[14]>>10U)); -Vals[2]+=W[0]; -Vals[2]+=(rotr(Vals[1],6)^rotr(Vals[1],11)^rotr(Vals[1],25)); -Vals[2]+=ch(Vals[1],Vals[4],Vals[3]); -Vals[2]+=K[32]; -Vals[0]+=Vals[2]; -Vals[2]+=(rotr(Vals[5],2)^rotr(Vals[5],13)^rotr(Vals[5],22)); -Vals[2]+=Ma(Vals[6],Vals[5],Vals[7]); - -W[1]=fw1; -W[1]+=(rotr(W[2],7)^rotr(W[2],18)^(W[2]>>3U)); -W[1]+=W[10]; -W[1]+=(rotr(W[15],17)^rotr(W[15],19)^(W[15]>>10U)); -Vals[3]+=W[1]; -Vals[3]+=(rotr(Vals[0],6)^rotr(Vals[0],11)^rotr(Vals[0],25)); -Vals[3]+=ch(Vals[0],Vals[1],Vals[4]); -Vals[3]+=K[33]; -Vals[6]+=Vals[3]; -Vals[3]+=(rotr(Vals[2],2)^rotr(Vals[2],13)^rotr(Vals[2],22)); -Vals[3]+=Ma(Vals[7],Vals[2],Vals[5]); - -W[2]+=(rotr(W[3],7)^rotr(W[3],18)^(W[3]>>3U)); -W[2]+=W[11]; -W[2]+=(rotr(W[0],17)^rotr(W[0],19)^(W[0]>>10U)); -Vals[4]+=W[2]; -Vals[4]+=(rotr(Vals[6],6)^rotr(Vals[6],11)^rotr(Vals[6],25)); -Vals[4]+=ch(Vals[6],Vals[0],Vals[1]); -Vals[4]+=K[34]; -Vals[7]+=Vals[4]; -Vals[4]+=(rotr(Vals[3],2)^rotr(Vals[3],13)^rotr(Vals[3],22)); -Vals[4]+=Ma(Vals[5],Vals[3],Vals[2]); - -W[3]+=(rotr(W[4],7)^rotr(W[4],18)^(W[4]>>3U)); -W[3]+=W[12]; -W[3]+=(rotr(W[1],17)^rotr(W[1],19)^(W[1]>>10U)); -Vals[1]+=W[3]; -Vals[1]+=(rotr(Vals[7],6)^rotr(Vals[7],11)^rotr(Vals[7],25)); -Vals[1]+=ch(Vals[7],Vals[6],Vals[0]); -Vals[1]+=K[35]; -Vals[5]+=Vals[1]; -Vals[1]+=(rotr(Vals[4],2)^rotr(Vals[4],13)^rotr(Vals[4],22)); -Vals[1]+=Ma(Vals[2],Vals[4],Vals[3]); - -W[4]+=(rotr(W[5],7)^rotr(W[5],18)^(W[5]>>3U)); -W[4]+=W[13]; -W[4]+=(rotr(W[2],17)^rotr(W[2],19)^(W[2]>>10U)); -Vals[0]+=W[4]; -Vals[0]+=(rotr(Vals[5],6)^rotr(Vals[5],11)^rotr(Vals[5],25)); -Vals[0]+=ch(Vals[5],Vals[7],Vals[6]); -Vals[0]+=K[36]; -Vals[2]+=Vals[0]; -Vals[0]+=(rotr(Vals[1],2)^rotr(Vals[1],13)^rotr(Vals[1],22)); -Vals[0]+=Ma(Vals[3],Vals[1],Vals[4]); - -W[5]+=(rotr(W[6],7)^rotr(W[6],18)^(W[6]>>3U)); -W[5]+=W[14]; -W[5]+=(rotr(W[3],17)^rotr(W[3],19)^(W[3]>>10U)); -Vals[6]+=W[5]; -Vals[6]+=(rotr(Vals[2],6)^rotr(Vals[2],11)^rotr(Vals[2],25)); -Vals[6]+=ch(Vals[2],Vals[5],Vals[7]); -Vals[6]+=K[37]; -Vals[3]+=Vals[6]; -Vals[6]+=(rotr(Vals[0],2)^rotr(Vals[0],13)^rotr(Vals[0],22)); -Vals[6]+=Ma(Vals[4],Vals[0],Vals[1]); - -W[6]+=(rotr(W[7],7)^rotr(W[7],18)^(W[7]>>3U)); -W[6]+=W[15]; -W[6]+=(rotr(W[4],17)^rotr(W[4],19)^(W[4]>>10U)); -Vals[7]+=W[6]; -Vals[7]+=(rotr(Vals[3],6)^rotr(Vals[3],11)^rotr(Vals[3],25)); -Vals[7]+=ch(Vals[3],Vals[2],Vals[5]); -Vals[7]+=K[38]; -Vals[4]+=Vals[7]; -Vals[7]+=(rotr(Vals[6],2)^rotr(Vals[6],13)^rotr(Vals[6],22)); -Vals[7]+=Ma(Vals[1],Vals[6],Vals[0]); - -W[7]+=(rotr(W[8],7)^rotr(W[8],18)^(W[8]>>3U)); -W[7]+=W[0]; -W[7]+=(rotr(W[5],17)^rotr(W[5],19)^(W[5]>>10U)); -Vals[5]+=W[7]; -Vals[5]+=(rotr(Vals[4],6)^rotr(Vals[4],11)^rotr(Vals[4],25)); -Vals[5]+=ch(Vals[4],Vals[3],Vals[2]); -Vals[5]+=K[39]; -Vals[1]+=Vals[5]; -Vals[5]+=(rotr(Vals[7],2)^rotr(Vals[7],13)^rotr(Vals[7],22)); -Vals[5]+=Ma(Vals[0],Vals[7],Vals[6]); - -W[8]+=(rotr(W[9],7)^rotr(W[9],18)^(W[9]>>3U)); -W[8]+=W[1]; -W[8]+=(rotr(W[6],17)^rotr(W[6],19)^(W[6]>>10U)); -Vals[2]+=W[8]; -Vals[2]+=(rotr(Vals[1],6)^rotr(Vals[1],11)^rotr(Vals[1],25)); -Vals[2]+=ch(Vals[1],Vals[4],Vals[3]); -Vals[2]+=K[40]; -Vals[0]+=Vals[2]; -Vals[2]+=(rotr(Vals[5],2)^rotr(Vals[5],13)^rotr(Vals[5],22)); -Vals[2]+=Ma(Vals[6],Vals[5],Vals[7]); - -W[9]+=(rotr(W[10],7)^rotr(W[10],18)^(W[10]>>3U)); -W[9]+=W[2]; -W[9]+=(rotr(W[7],17)^rotr(W[7],19)^(W[7]>>10U)); -Vals[3]+=W[9]; -Vals[3]+=(rotr(Vals[0],6)^rotr(Vals[0],11)^rotr(Vals[0],25)); -Vals[3]+=ch(Vals[0],Vals[1],Vals[4]); -Vals[3]+=K[41]; -Vals[6]+=Vals[3]; -Vals[3]+=(rotr(Vals[2],2)^rotr(Vals[2],13)^rotr(Vals[2],22)); -Vals[3]+=Ma(Vals[7],Vals[2],Vals[5]); - -W[10]+=(rotr(W[11],7)^rotr(W[11],18)^(W[11]>>3U)); -W[10]+=W[3]; -W[10]+=(rotr(W[8],17)^rotr(W[8],19)^(W[8]>>10U)); -Vals[4]+=W[10]; -Vals[4]+=(rotr(Vals[6],6)^rotr(Vals[6],11)^rotr(Vals[6],25)); -Vals[4]+=ch(Vals[6],Vals[0],Vals[1]); -Vals[4]+=K[42]; -Vals[7]+=Vals[4]; -Vals[4]+=(rotr(Vals[3],2)^rotr(Vals[3],13)^rotr(Vals[3],22)); -Vals[4]+=Ma(Vals[5],Vals[3],Vals[2]); - -W[11]+=(rotr(W[12],7)^rotr(W[12],18)^(W[12]>>3U)); -W[11]+=W[4]; -W[11]+=(rotr(W[9],17)^rotr(W[9],19)^(W[9]>>10U)); -Vals[1]+=W[11]; -Vals[1]+=(rotr(Vals[7],6)^rotr(Vals[7],11)^rotr(Vals[7],25)); -Vals[1]+=ch(Vals[7],Vals[6],Vals[0]); -Vals[1]+=K[43]; -Vals[5]+=Vals[1]; -Vals[1]+=(rotr(Vals[4],2)^rotr(Vals[4],13)^rotr(Vals[4],22)); -Vals[1]+=Ma(Vals[2],Vals[4],Vals[3]); - -W[12]+=(rotr(W[13],7)^rotr(W[13],18)^(W[13]>>3U)); -W[12]+=W[5]; -W[12]+=(rotr(W[10],17)^rotr(W[10],19)^(W[10]>>10U)); -Vals[0]+=W[12]; -Vals[0]+=(rotr(Vals[5],6)^rotr(Vals[5],11)^rotr(Vals[5],25)); -Vals[0]+=ch(Vals[5],Vals[7],Vals[6]); -Vals[0]+=K[44]; -Vals[2]+=Vals[0]; -Vals[0]+=(rotr(Vals[1],2)^rotr(Vals[1],13)^rotr(Vals[1],22)); -Vals[0]+=Ma(Vals[3],Vals[1],Vals[4]); - -W[13]+=(rotr(W[14],7)^rotr(W[14],18)^(W[14]>>3U)); -W[13]+=W[6]; -W[13]+=(rotr(W[11],17)^rotr(W[11],19)^(W[11]>>10U)); -Vals[6]+=W[13]; -Vals[6]+=(rotr(Vals[2],6)^rotr(Vals[2],11)^rotr(Vals[2],25)); -Vals[6]+=ch(Vals[2],Vals[5],Vals[7]); -Vals[6]+=K[45]; -Vals[3]+=Vals[6]; -Vals[6]+=(rotr(Vals[0],2)^rotr(Vals[0],13)^rotr(Vals[0],22)); -Vals[6]+=Ma(Vals[4],Vals[0],Vals[1]); - -W[14]+=(rotr(W[15],7)^rotr(W[15],18)^(W[15]>>3U)); -W[14]+=W[7]; -W[14]+=(rotr(W[12],17)^rotr(W[12],19)^(W[12]>>10U)); -Vals[7]+=W[14]; -Vals[7]+=(rotr(Vals[3],6)^rotr(Vals[3],11)^rotr(Vals[3],25)); -Vals[7]+=ch(Vals[3],Vals[2],Vals[5]); -Vals[7]+=K[46]; -Vals[4]+=Vals[7]; -Vals[7]+=(rotr(Vals[6],2)^rotr(Vals[6],13)^rotr(Vals[6],22)); -Vals[7]+=Ma(Vals[1],Vals[6],Vals[0]); - -W[15]+=(rotr(W[0],7)^rotr(W[0],18)^(W[0]>>3U)); -W[15]+=W[8]; -W[15]+=(rotr(W[13],17)^rotr(W[13],19)^(W[13]>>10U)); -Vals[5]+=W[15]; -Vals[5]+=(rotr(Vals[4],6)^rotr(Vals[4],11)^rotr(Vals[4],25)); -Vals[5]+=ch(Vals[4],Vals[3],Vals[2]); -Vals[5]+=K[47]; -Vals[1]+=Vals[5]; -Vals[5]+=(rotr(Vals[7],2)^rotr(Vals[7],13)^rotr(Vals[7],22)); -Vals[5]+=Ma(Vals[0],Vals[7],Vals[6]); - -W[0]+=(rotr(W[1],7)^rotr(W[1],18)^(W[1]>>3U)); -W[0]+=W[9]; -W[0]+=(rotr(W[14],17)^rotr(W[14],19)^(W[14]>>10U)); -Vals[2]+=W[0]; -Vals[2]+=(rotr(Vals[1],6)^rotr(Vals[1],11)^rotr(Vals[1],25)); -Vals[2]+=ch(Vals[1],Vals[4],Vals[3]); -Vals[2]+=K[48]; -Vals[0]+=Vals[2]; -Vals[2]+=(rotr(Vals[5],2)^rotr(Vals[5],13)^rotr(Vals[5],22)); -Vals[2]+=Ma(Vals[6],Vals[5],Vals[7]); - -W[1]+=(rotr(W[2],7)^rotr(W[2],18)^(W[2]>>3U)); -W[1]+=W[10]; -W[1]+=(rotr(W[15],17)^rotr(W[15],19)^(W[15]>>10U)); -Vals[3]+=W[1]; -Vals[3]+=(rotr(Vals[0],6)^rotr(Vals[0],11)^rotr(Vals[0],25)); -Vals[3]+=ch(Vals[0],Vals[1],Vals[4]); -Vals[3]+=K[49]; -Vals[6]+=Vals[3]; -Vals[3]+=(rotr(Vals[2],2)^rotr(Vals[2],13)^rotr(Vals[2],22)); -Vals[3]+=Ma(Vals[7],Vals[2],Vals[5]); - -W[2]+=(rotr(W[3],7)^rotr(W[3],18)^(W[3]>>3U)); -W[2]+=W[11]; -W[2]+=(rotr(W[0],17)^rotr(W[0],19)^(W[0]>>10U)); -Vals[4]+=W[2]; -Vals[4]+=(rotr(Vals[6],6)^rotr(Vals[6],11)^rotr(Vals[6],25)); -Vals[4]+=ch(Vals[6],Vals[0],Vals[1]); -Vals[4]+=K[50]; -Vals[7]+=Vals[4]; -Vals[4]+=(rotr(Vals[3],2)^rotr(Vals[3],13)^rotr(Vals[3],22)); -Vals[4]+=Ma(Vals[5],Vals[3],Vals[2]); - -W[3]+=(rotr(W[4],7)^rotr(W[4],18)^(W[4]>>3U)); -W[3]+=W[12]; -W[3]+=(rotr(W[1],17)^rotr(W[1],19)^(W[1]>>10U)); -Vals[1]+=W[3]; -Vals[1]+=(rotr(Vals[7],6)^rotr(Vals[7],11)^rotr(Vals[7],25)); -Vals[1]+=ch(Vals[7],Vals[6],Vals[0]); -Vals[1]+=K[51]; -Vals[5]+=Vals[1]; -Vals[1]+=(rotr(Vals[4],2)^rotr(Vals[4],13)^rotr(Vals[4],22)); -Vals[1]+=Ma(Vals[2],Vals[4],Vals[3]); - -W[4]+=(rotr(W[5],7)^rotr(W[5],18)^(W[5]>>3U)); -W[4]+=W[13]; -W[4]+=(rotr(W[2],17)^rotr(W[2],19)^(W[2]>>10U)); -Vals[0]+=W[4]; -Vals[0]+=(rotr(Vals[5],6)^rotr(Vals[5],11)^rotr(Vals[5],25)); -Vals[0]+=ch(Vals[5],Vals[7],Vals[6]); -Vals[0]+=K[52]; -Vals[2]+=Vals[0]; -Vals[0]+=(rotr(Vals[1],2)^rotr(Vals[1],13)^rotr(Vals[1],22)); -Vals[0]+=Ma(Vals[3],Vals[1],Vals[4]); - -W[5]+=(rotr(W[6],7)^rotr(W[6],18)^(W[6]>>3U)); -W[5]+=W[14]; -W[5]+=(rotr(W[3],17)^rotr(W[3],19)^(W[3]>>10U)); -Vals[6]+=W[5]; -Vals[6]+=(rotr(Vals[2],6)^rotr(Vals[2],11)^rotr(Vals[2],25)); -Vals[6]+=ch(Vals[2],Vals[5],Vals[7]); -Vals[6]+=K[53]; -Vals[3]+=Vals[6]; -Vals[6]+=(rotr(Vals[0],2)^rotr(Vals[0],13)^rotr(Vals[0],22)); -Vals[6]+=Ma(Vals[4],Vals[0],Vals[1]); - -W[6]+=(rotr(W[7],7)^rotr(W[7],18)^(W[7]>>3U)); -W[6]+=W[15]; -W[6]+=(rotr(W[4],17)^rotr(W[4],19)^(W[4]>>10U)); -Vals[7]+=W[6]; -Vals[7]+=(rotr(Vals[3],6)^rotr(Vals[3],11)^rotr(Vals[3],25)); -Vals[7]+=ch(Vals[3],Vals[2],Vals[5]); -Vals[7]+=K[54]; -Vals[4]+=Vals[7]; -Vals[7]+=(rotr(Vals[6],2)^rotr(Vals[6],13)^rotr(Vals[6],22)); -Vals[7]+=Ma(Vals[1],Vals[6],Vals[0]); - -W[7]+=(rotr(W[8],7)^rotr(W[8],18)^(W[8]>>3U)); -W[7]+=W[0]; -W[7]+=(rotr(W[5],17)^rotr(W[5],19)^(W[5]>>10U)); -Vals[5]+=W[7]; -Vals[5]+=(rotr(Vals[4],6)^rotr(Vals[4],11)^rotr(Vals[4],25)); -Vals[5]+=ch(Vals[4],Vals[3],Vals[2]); -Vals[5]+=K[55]; -Vals[1]+=Vals[5]; -Vals[5]+=(rotr(Vals[7],2)^rotr(Vals[7],13)^rotr(Vals[7],22)); -Vals[5]+=Ma(Vals[0],Vals[7],Vals[6]); - -W[8]+=(rotr(W[9],7)^rotr(W[9],18)^(W[9]>>3U)); -W[8]+=W[1]; -W[8]+=(rotr(W[6],17)^rotr(W[6],19)^(W[6]>>10U)); -Vals[2]+=W[8]; -Vals[2]+=(rotr(Vals[1],6)^rotr(Vals[1],11)^rotr(Vals[1],25)); -Vals[2]+=ch(Vals[1],Vals[4],Vals[3]); -Vals[2]+=K[56]; -Vals[0]+=Vals[2]; -Vals[2]+=(rotr(Vals[5],2)^rotr(Vals[5],13)^rotr(Vals[5],22)); -Vals[2]+=Ma(Vals[6],Vals[5],Vals[7]); - -W[9]+=(rotr(W[10],7)^rotr(W[10],18)^(W[10]>>3U)); -W[9]+=W[2]; -W[9]+=(rotr(W[7],17)^rotr(W[7],19)^(W[7]>>10U)); -Vals[3]+=W[9]; -Vals[3]+=(rotr(Vals[0],6)^rotr(Vals[0],11)^rotr(Vals[0],25)); -Vals[3]+=ch(Vals[0],Vals[1],Vals[4]); -Vals[3]+=K[57]; -Vals[6]+=Vals[3]; -Vals[3]+=(rotr(Vals[2],2)^rotr(Vals[2],13)^rotr(Vals[2],22)); -Vals[3]+=Ma(Vals[7],Vals[2],Vals[5]); - -W[10]+=(rotr(W[11],7)^rotr(W[11],18)^(W[11]>>3U)); -W[10]+=W[3]; -W[10]+=(rotr(W[8],17)^rotr(W[8],19)^(W[8]>>10U)); -Vals[4]+=W[10]; -Vals[4]+=(rotr(Vals[6],6)^rotr(Vals[6],11)^rotr(Vals[6],25)); -Vals[4]+=ch(Vals[6],Vals[0],Vals[1]); -Vals[4]+=K[58]; -Vals[7]+=Vals[4]; -Vals[4]+=(rotr(Vals[3],2)^rotr(Vals[3],13)^rotr(Vals[3],22)); -Vals[4]+=Ma(Vals[5],Vals[3],Vals[2]); - -W[11]+=(rotr(W[12],7)^rotr(W[12],18)^(W[12]>>3U)); -W[11]+=W[4]; -W[11]+=(rotr(W[9],17)^rotr(W[9],19)^(W[9]>>10U)); -Vals[1]+=W[11]; -Vals[1]+=(rotr(Vals[7],6)^rotr(Vals[7],11)^rotr(Vals[7],25)); -Vals[1]+=ch(Vals[7],Vals[6],Vals[0]); -Vals[1]+=K[59]; -Vals[5]+=Vals[1]; -Vals[1]+=(rotr(Vals[4],2)^rotr(Vals[4],13)^rotr(Vals[4],22)); -Vals[1]+=Ma(Vals[2],Vals[4],Vals[3]); - -W[12]+=(rotr(W[13],7)^rotr(W[13],18)^(W[13]>>3U)); -W[12]+=W[5]; -W[12]+=(rotr(W[10],17)^rotr(W[10],19)^(W[10]>>10U)); -Vals[0]+=W[12]; -Vals[0]+=(rotr(Vals[5],6)^rotr(Vals[5],11)^rotr(Vals[5],25)); -Vals[0]+=ch(Vals[5],Vals[7],Vals[6]); -Vals[0]+=K[60]; -Vals[2]+=Vals[0]; -Vals[0]+=(rotr(Vals[1],2)^rotr(Vals[1],13)^rotr(Vals[1],22)); -Vals[0]+=Ma(Vals[3],Vals[1],Vals[4]); - -W[13]+=(rotr(W[14],7)^rotr(W[14],18)^(W[14]>>3U)); -W[13]+=W[6]; -W[13]+=(rotr(W[11],17)^rotr(W[11],19)^(W[11]>>10U)); -Vals[6]+=W[13]; -Vals[6]+=(rotr(Vals[2],6)^rotr(Vals[2],11)^rotr(Vals[2],25)); -Vals[6]+=ch(Vals[2],Vals[5],Vals[7]); -Vals[6]+=K[61]; -Vals[3]+=Vals[6]; -Vals[6]+=(rotr(Vals[0],2)^rotr(Vals[0],13)^rotr(Vals[0],22)); -Vals[6]+=Ma(Vals[4],Vals[0],Vals[1]); - -Vals[7]+=W[14]; -Vals[7]+=(rotr(W[15],7)^rotr(W[15],18)^(W[15]>>3U)); -Vals[7]+=W[7]; -Vals[7]+=(rotr(W[12],17)^rotr(W[12],19)^(W[12]>>10U)); -Vals[7]+=(rotr(Vals[3],6)^rotr(Vals[3],11)^rotr(Vals[3],25)); -Vals[7]+=ch(Vals[3],Vals[2],Vals[5]); -Vals[7]+=K[62]; -Vals[4]+=Vals[7]; -Vals[7]+=(rotr(Vals[6],2)^rotr(Vals[6],13)^rotr(Vals[6],22)); -Vals[7]+=Ma(Vals[1],Vals[6],Vals[0]); - -Vals[5]+=W[15]; -Vals[5]+=(rotr(W[0],7)^rotr(W[0],18)^(W[0]>>3U)); -Vals[5]+=W[8]; -Vals[5]+=(rotr(W[13],17)^rotr(W[13],19)^(W[13]>>10U)); -Vals[5]+=(rotr(Vals[4],6)^rotr(Vals[4],11)^rotr(Vals[4],25)); -Vals[5]+=ch(Vals[4],Vals[3],Vals[2]); -Vals[5]+=K[63]; -Vals[1]+=Vals[5]; -Vals[5]+=(rotr(Vals[7],2)^rotr(Vals[7],13)^rotr(Vals[7],22)); -Vals[5]+=Ma(Vals[0],Vals[7],Vals[6]); - -Vals[5]+=state0; - -W[7]=state7; -W[7]+=Vals[2]; - -Vals[2]=xf377ed68U; -Vals[2]+=Vals[5]; -W[0]=Vals[5]; -Vals[5]=x6a09e667U; - -W[3]=state3; -W[3]+=Vals[0]; - -Vals[0]=xa54ff53aU; -Vals[0]+=Vals[2]; -Vals[2]+=x08909ae5U; - -W[6]=state6; -W[6]+=Vals[3]; - -Vals[3]=x90bb1e3cU; -Vals[3]+=(rotr(Vals[0],6)^rotr(Vals[0],11)^rotr(Vals[0],25)); -Vals[3]+=(x9b05688cU^(Vals[0]&xca0b3af3U)); - -Vals[7]+=state1; -Vals[3]+=Vals[7]; -W[1]=Vals[7]; -Vals[7]=xbb67ae85U; - -W[2]=state2; -W[2]+=Vals[6]; - -Vals[6]=x3c6ef372U; -Vals[6]+=Vals[3]; -Vals[3]+=(rotr(Vals[2],2)^rotr(Vals[2],13)^rotr(Vals[2],22)); -Vals[3]+=Ma2(Vals[7],Vals[2],Vals[5]); - -W[5]=state5; -W[5]+=Vals[4]; - -Vals[4]=x50c6645bU; -Vals[4]+=(rotr(Vals[6],6)^rotr(Vals[6],11)^rotr(Vals[6],25)); -Vals[4]+=ch(Vals[6],Vals[0],x510e527fU); -Vals[4]+=W[2]; - -Vals[7]+=Vals[4]; -Vals[4]+=(rotr(Vals[3],2)^rotr(Vals[3],13)^rotr(Vals[3],22)); -Vals[4]+=Ma2(Vals[5],Vals[3],Vals[2]); - -W[4]=state4; -W[4]+=Vals[1]; - -Vals[1]=x3ac42e24U; -Vals[1]+=(rotr(Vals[7],6)^rotr(Vals[7],11)^rotr(Vals[7],25)); -Vals[1]+=ch(Vals[7],Vals[6],Vals[0]); -Vals[1]+=W[3]; -Vals[5]+=Vals[1]; -Vals[1]+=(rotr(Vals[4],2)^rotr(Vals[4],13)^rotr(Vals[4],22)); -Vals[1]+=Ma(Vals[2],Vals[4],Vals[3]); - -Vals[0]+=(rotr(Vals[5],6)^rotr(Vals[5],11)^rotr(Vals[5],25)); -Vals[0]+=ch(Vals[5],Vals[7],Vals[6]); -Vals[0]+=K[4]; -Vals[0]+=W[4]; -Vals[2]+=Vals[0]; -Vals[0]+=(rotr(Vals[1],2)^rotr(Vals[1],13)^rotr(Vals[1],22)); -Vals[0]+=Ma(Vals[3],Vals[1],Vals[4]); - -Vals[6]+=(rotr(Vals[2],6)^rotr(Vals[2],11)^rotr(Vals[2],25)); -Vals[6]+=ch(Vals[2],Vals[5],Vals[7]); -Vals[6]+=K[5]; -Vals[6]+=W[5]; -Vals[3]+=Vals[6]; -Vals[6]+=(rotr(Vals[0],2)^rotr(Vals[0],13)^rotr(Vals[0],22)); -Vals[6]+=Ma(Vals[4],Vals[0],Vals[1]); - -Vals[7]+=(rotr(Vals[3],6)^rotr(Vals[3],11)^rotr(Vals[3],25)); -Vals[7]+=ch(Vals[3],Vals[2],Vals[5]); -Vals[7]+=K[6]; -Vals[7]+=W[6]; -Vals[4]+=Vals[7]; -Vals[7]+=(rotr(Vals[6],2)^rotr(Vals[6],13)^rotr(Vals[6],22)); -Vals[7]+=Ma(Vals[1],Vals[6],Vals[0]); - -Vals[5]+=(rotr(Vals[4],6)^rotr(Vals[4],11)^rotr(Vals[4],25)); -Vals[5]+=ch(Vals[4],Vals[3],Vals[2]); -Vals[5]+=K[7]; -Vals[5]+=W[7]; -Vals[1]+=Vals[5]; -Vals[5]+=(rotr(Vals[7],2)^rotr(Vals[7],13)^rotr(Vals[7],22)); -Vals[5]+=Ma(Vals[0],Vals[7],Vals[6]); - -Vals[2]+=(rotr(Vals[1],6)^rotr(Vals[1],11)^rotr(Vals[1],25)); -Vals[2]+=ch(Vals[1],Vals[4],Vals[3]); -Vals[2]+=x5807aa98U; -Vals[0]+=Vals[2]; -Vals[2]+=(rotr(Vals[5],2)^rotr(Vals[5],13)^rotr(Vals[5],22)); -Vals[2]+=Ma(Vals[6],Vals[5],Vals[7]); - -Vals[3]+=(rotr(Vals[0],6)^rotr(Vals[0],11)^rotr(Vals[0],25)); -Vals[3]+=ch(Vals[0],Vals[1],Vals[4]); -Vals[3]+=K[9]; -Vals[6]+=Vals[3]; -Vals[3]+=(rotr(Vals[2],2)^rotr(Vals[2],13)^rotr(Vals[2],22)); -Vals[3]+=Ma(Vals[7],Vals[2],Vals[5]); - -Vals[4]+=(rotr(Vals[6],6)^rotr(Vals[6],11)^rotr(Vals[6],25)); -Vals[4]+=ch(Vals[6],Vals[0],Vals[1]); -Vals[4]+=K[10]; -Vals[7]+=Vals[4]; -Vals[4]+=(rotr(Vals[3],2)^rotr(Vals[3],13)^rotr(Vals[3],22)); -Vals[4]+=Ma(Vals[5],Vals[3],Vals[2]); - -Vals[1]+=(rotr(Vals[7],6)^rotr(Vals[7],11)^rotr(Vals[7],25)); -Vals[1]+=ch(Vals[7],Vals[6],Vals[0]); -Vals[1]+=K[11]; -Vals[5]+=Vals[1]; -Vals[1]+=(rotr(Vals[4],2)^rotr(Vals[4],13)^rotr(Vals[4],22)); -Vals[1]+=Ma(Vals[2],Vals[4],Vals[3]); - -Vals[0]+=(rotr(Vals[5],6)^rotr(Vals[5],11)^rotr(Vals[5],25)); -Vals[0]+=ch(Vals[5],Vals[7],Vals[6]); -Vals[0]+=K[12]; -Vals[2]+=Vals[0]; -Vals[0]+=(rotr(Vals[1],2)^rotr(Vals[1],13)^rotr(Vals[1],22)); -Vals[0]+=Ma(Vals[3],Vals[1],Vals[4]); - -Vals[6]+=(rotr(Vals[2],6)^rotr(Vals[2],11)^rotr(Vals[2],25)); -Vals[6]+=ch(Vals[2],Vals[5],Vals[7]); -Vals[6]+=K[13]; -Vals[3]+=Vals[6]; -Vals[6]+=(rotr(Vals[0],2)^rotr(Vals[0],13)^rotr(Vals[0],22)); -Vals[6]+=Ma(Vals[4],Vals[0],Vals[1]); - -Vals[7]+=(rotr(Vals[3],6)^rotr(Vals[3],11)^rotr(Vals[3],25)); -Vals[7]+=ch(Vals[3],Vals[2],Vals[5]); -Vals[7]+=K[14]; -Vals[4]+=Vals[7]; -Vals[7]+=(rotr(Vals[6],2)^rotr(Vals[6],13)^rotr(Vals[6],22)); -Vals[7]+=Ma(Vals[1],Vals[6],Vals[0]); - -Vals[5]+=(rotr(Vals[4],6)^rotr(Vals[4],11)^rotr(Vals[4],25)); -Vals[5]+=ch(Vals[4],Vals[3],Vals[2]); -Vals[5]+=xc19bf274U; -Vals[1]+=Vals[5]; -Vals[5]+=(rotr(Vals[7],2)^rotr(Vals[7],13)^rotr(Vals[7],22)); -Vals[5]+=Ma(Vals[0],Vals[7],Vals[6]); - -W[0]+=(rotr(W[1],7)^rotr(W[1],18)^(W[1]>>3U)); -Vals[2]+=W[0]; -Vals[2]+=(rotr(Vals[1],6)^rotr(Vals[1],11)^rotr(Vals[1],25)); -Vals[2]+=ch(Vals[1],Vals[4],Vals[3]); -Vals[2]+=K[16]; -Vals[0]+=Vals[2]; -Vals[2]+=(rotr(Vals[5],2)^rotr(Vals[5],13)^rotr(Vals[5],22)); -Vals[2]+=Ma(Vals[6],Vals[5],Vals[7]); - -W[1]+=(rotr(W[2],7)^rotr(W[2],18)^(W[2]>>3U)); -W[1]+=x00a00000U; -Vals[3]+=W[1]; -Vals[3]+=(rotr(Vals[0],6)^rotr(Vals[0],11)^rotr(Vals[0],25)); -Vals[3]+=ch(Vals[0],Vals[1],Vals[4]); -Vals[3]+=K[17]; -Vals[6]+=Vals[3]; -Vals[3]+=(rotr(Vals[2],2)^rotr(Vals[2],13)^rotr(Vals[2],22)); -Vals[3]+=Ma(Vals[7],Vals[2],Vals[5]); - -W[2]+=(rotr(W[3],7)^rotr(W[3],18)^(W[3]>>3U)); -W[2]+=(rotr(W[0],17)^rotr(W[0],19)^(W[0]>>10U)); -Vals[4]+=W[2]; -Vals[4]+=(rotr(Vals[6],6)^rotr(Vals[6],11)^rotr(Vals[6],25)); -Vals[4]+=ch(Vals[6],Vals[0],Vals[1]); -Vals[4]+=K[18]; -Vals[7]+=Vals[4]; -Vals[4]+=(rotr(Vals[3],2)^rotr(Vals[3],13)^rotr(Vals[3],22)); -Vals[4]+=Ma(Vals[5],Vals[3],Vals[2]); - -W[3]+=(rotr(W[4],7)^rotr(W[4],18)^(W[4]>>3U)); -W[3]+=(rotr(W[1],17)^rotr(W[1],19)^(W[1]>>10U)); -Vals[1]+=W[3]; -Vals[1]+=(rotr(Vals[7],6)^rotr(Vals[7],11)^rotr(Vals[7],25)); -Vals[1]+=ch(Vals[7],Vals[6],Vals[0]); -Vals[1]+=K[19]; -Vals[5]+=Vals[1]; -Vals[1]+=(rotr(Vals[4],2)^rotr(Vals[4],13)^rotr(Vals[4],22)); -Vals[1]+=Ma(Vals[2],Vals[4],Vals[3]); - -W[4]+=(rotr(W[5],7)^rotr(W[5],18)^(W[5]>>3U)); -W[4]+=(rotr(W[2],17)^rotr(W[2],19)^(W[2]>>10U)); -Vals[0]+=W[4]; -Vals[0]+=(rotr(Vals[5],6)^rotr(Vals[5],11)^rotr(Vals[5],25)); -Vals[0]+=ch(Vals[5],Vals[7],Vals[6]); -Vals[0]+=K[20]; -Vals[2]+=Vals[0]; -Vals[0]+=(rotr(Vals[1],2)^rotr(Vals[1],13)^rotr(Vals[1],22)); -Vals[0]+=Ma(Vals[3],Vals[1],Vals[4]); - -W[5]+=(rotr(W[6],7)^rotr(W[6],18)^(W[6]>>3U)); -W[5]+=(rotr(W[3],17)^rotr(W[3],19)^(W[3]>>10U)); -Vals[6]+=W[5]; -Vals[6]+=(rotr(Vals[2],6)^rotr(Vals[2],11)^rotr(Vals[2],25)); -Vals[6]+=ch(Vals[2],Vals[5],Vals[7]); -Vals[6]+=K[21]; -Vals[3]+=Vals[6]; -Vals[6]+=(rotr(Vals[0],2)^rotr(Vals[0],13)^rotr(Vals[0],22)); -Vals[6]+=Ma(Vals[4],Vals[0],Vals[1]); - -W[6]+=(rotr(W[7],7)^rotr(W[7],18)^(W[7]>>3U)); -W[6]+=x00000100U; -W[6]+=(rotr(W[4],17)^rotr(W[4],19)^(W[4]>>10U)); -Vals[7]+=W[6]; -Vals[7]+=(rotr(Vals[3],6)^rotr(Vals[3],11)^rotr(Vals[3],25)); -Vals[7]+=ch(Vals[3],Vals[2],Vals[5]); -Vals[7]+=K[22]; -Vals[4]+=Vals[7]; -Vals[7]+=(rotr(Vals[6],2)^rotr(Vals[6],13)^rotr(Vals[6],22)); -Vals[7]+=Ma(Vals[1],Vals[6],Vals[0]); - -W[7]+=x11002000U; -W[7]+=W[0]; -W[7]+=(rotr(W[5],17)^rotr(W[5],19)^(W[5]>>10U)); -Vals[5]+=W[7]; -Vals[5]+=(rotr(Vals[4],6)^rotr(Vals[4],11)^rotr(Vals[4],25)); -Vals[5]+=ch(Vals[4],Vals[3],Vals[2]); -Vals[5]+=K[23]; -Vals[1]+=Vals[5]; -Vals[5]+=(rotr(Vals[7],2)^rotr(Vals[7],13)^rotr(Vals[7],22)); -Vals[5]+=Ma(Vals[0],Vals[7],Vals[6]); - -W[8]=x80000000U; -W[8]+=W[1]; -W[8]+=(rotr(W[6],17)^rotr(W[6],19)^(W[6]>>10U)); -Vals[2]+=W[8]; -Vals[2]+=(rotr(Vals[1],6)^rotr(Vals[1],11)^rotr(Vals[1],25)); -Vals[2]+=ch(Vals[1],Vals[4],Vals[3]); -Vals[2]+=K[24]; -Vals[0]+=Vals[2]; -Vals[2]+=(rotr(Vals[5],2)^rotr(Vals[5],13)^rotr(Vals[5],22)); -Vals[2]+=Ma(Vals[6],Vals[5],Vals[7]); - -W[9]=W[2]; -W[9]+=(rotr(W[7],17)^rotr(W[7],19)^(W[7]>>10U)); -Vals[3]+=W[9]; -Vals[3]+=(rotr(Vals[0],6)^rotr(Vals[0],11)^rotr(Vals[0],25)); -Vals[3]+=ch(Vals[0],Vals[1],Vals[4]); -Vals[3]+=K[25]; -Vals[6]+=Vals[3]; -Vals[3]+=(rotr(Vals[2],2)^rotr(Vals[2],13)^rotr(Vals[2],22)); -Vals[3]+=Ma(Vals[7],Vals[2],Vals[5]); - -W[10]=W[3]; -W[10]+=(rotr(W[8],17)^rotr(W[8],19)^(W[8]>>10U)); -Vals[4]+=W[10]; -Vals[4]+=(rotr(Vals[6],6)^rotr(Vals[6],11)^rotr(Vals[6],25)); -Vals[4]+=ch(Vals[6],Vals[0],Vals[1]); -Vals[4]+=K[26]; -Vals[7]+=Vals[4]; -Vals[4]+=(rotr(Vals[3],2)^rotr(Vals[3],13)^rotr(Vals[3],22)); -Vals[4]+=Ma(Vals[5],Vals[3],Vals[2]); - -W[11]=W[4]; -W[11]+=(rotr(W[9],17)^rotr(W[9],19)^(W[9]>>10U)); -Vals[1]+=W[11]; -Vals[1]+=(rotr(Vals[7],6)^rotr(Vals[7],11)^rotr(Vals[7],25)); -Vals[1]+=ch(Vals[7],Vals[6],Vals[0]); -Vals[1]+=K[27]; -Vals[5]+=Vals[1]; -Vals[1]+=(rotr(Vals[4],2)^rotr(Vals[4],13)^rotr(Vals[4],22)); -Vals[1]+=Ma(Vals[2],Vals[4],Vals[3]); - -W[12]=W[5]; -W[12]+=(rotr(W[10],17)^rotr(W[10],19)^(W[10]>>10U)); -Vals[0]+=W[12]; -Vals[0]+=(rotr(Vals[5],6)^rotr(Vals[5],11)^rotr(Vals[5],25)); -Vals[0]+=ch(Vals[5],Vals[7],Vals[6]); -Vals[0]+=K[28]; -Vals[2]+=Vals[0]; -Vals[0]+=(rotr(Vals[1],2)^rotr(Vals[1],13)^rotr(Vals[1],22)); -Vals[0]+=Ma(Vals[3],Vals[1],Vals[4]); - -W[13]=W[6]; -W[13]+=(rotr(W[11],17)^rotr(W[11],19)^(W[11]>>10U)); -Vals[6]+=W[13]; -Vals[6]+=(rotr(Vals[2],6)^rotr(Vals[2],11)^rotr(Vals[2],25)); -Vals[6]+=ch(Vals[2],Vals[5],Vals[7]); -Vals[6]+=K[29]; -Vals[3]+=Vals[6]; -Vals[6]+=(rotr(Vals[0],2)^rotr(Vals[0],13)^rotr(Vals[0],22)); -Vals[6]+=Ma(Vals[4],Vals[0],Vals[1]); - -W[14]=x00400022U; -W[14]+=W[7]; -W[14]+=(rotr(W[12],17)^rotr(W[12],19)^(W[12]>>10U)); -Vals[7]+=W[14]; -Vals[7]+=(rotr(Vals[3],6)^rotr(Vals[3],11)^rotr(Vals[3],25)); -Vals[7]+=ch(Vals[3],Vals[2],Vals[5]); -Vals[7]+=K[30]; -Vals[4]+=Vals[7]; -Vals[7]+=(rotr(Vals[6],2)^rotr(Vals[6],13)^rotr(Vals[6],22)); -Vals[7]+=Ma(Vals[1],Vals[6],Vals[0]); - -W[15]=x00000100U; -W[15]+=(rotr(W[0],7)^rotr(W[0],18)^(W[0]>>3U)); -W[15]+=W[8]; -W[15]+=(rotr(W[13],17)^rotr(W[13],19)^(W[13]>>10U)); -Vals[5]+=W[15]; -Vals[5]+=(rotr(Vals[4],6)^rotr(Vals[4],11)^rotr(Vals[4],25)); -Vals[5]+=ch(Vals[4],Vals[3],Vals[2]); -Vals[5]+=K[31]; -Vals[1]+=Vals[5]; -Vals[5]+=(rotr(Vals[7],2)^rotr(Vals[7],13)^rotr(Vals[7],22)); -Vals[5]+=Ma(Vals[0],Vals[7],Vals[6]); - -W[0]+=(rotr(W[1],7)^rotr(W[1],18)^(W[1]>>3U)); -W[0]+=W[9]; -W[0]+=(rotr(W[14],17)^rotr(W[14],19)^(W[14]>>10U)); -Vals[2]+=W[0]; -Vals[2]+=(rotr(Vals[1],6)^rotr(Vals[1],11)^rotr(Vals[1],25)); -Vals[2]+=ch(Vals[1],Vals[4],Vals[3]); -Vals[2]+=K[32]; -Vals[0]+=Vals[2]; -Vals[2]+=(rotr(Vals[5],2)^rotr(Vals[5],13)^rotr(Vals[5],22)); -Vals[2]+=Ma(Vals[6],Vals[5],Vals[7]); - -W[1]+=(rotr(W[2],7)^rotr(W[2],18)^(W[2]>>3U)); -W[1]+=W[10]; -W[1]+=(rotr(W[15],17)^rotr(W[15],19)^(W[15]>>10U)); -Vals[3]+=W[1]; -Vals[3]+=(rotr(Vals[0],6)^rotr(Vals[0],11)^rotr(Vals[0],25)); -Vals[3]+=ch(Vals[0],Vals[1],Vals[4]); -Vals[3]+=K[33]; -Vals[6]+=Vals[3]; -Vals[3]+=(rotr(Vals[2],2)^rotr(Vals[2],13)^rotr(Vals[2],22)); -Vals[3]+=Ma(Vals[7],Vals[2],Vals[5]); - -W[2]+=(rotr(W[3],7)^rotr(W[3],18)^(W[3]>>3U)); -W[2]+=W[11]; -W[2]+=(rotr(W[0],17)^rotr(W[0],19)^(W[0]>>10U)); -Vals[4]+=W[2]; -Vals[4]+=(rotr(Vals[6],6)^rotr(Vals[6],11)^rotr(Vals[6],25)); -Vals[4]+=ch(Vals[6],Vals[0],Vals[1]); -Vals[4]+=K[34]; -Vals[7]+=Vals[4]; -Vals[4]+=(rotr(Vals[3],2)^rotr(Vals[3],13)^rotr(Vals[3],22)); -Vals[4]+=Ma(Vals[5],Vals[3],Vals[2]); - -W[3]+=(rotr(W[4],7)^rotr(W[4],18)^(W[4]>>3U)); -W[3]+=W[12]; -W[3]+=(rotr(W[1],17)^rotr(W[1],19)^(W[1]>>10U)); -Vals[1]+=W[3]; -Vals[1]+=(rotr(Vals[7],6)^rotr(Vals[7],11)^rotr(Vals[7],25)); -Vals[1]+=ch(Vals[7],Vals[6],Vals[0]); -Vals[1]+=K[35]; -Vals[5]+=Vals[1]; -Vals[1]+=(rotr(Vals[4],2)^rotr(Vals[4],13)^rotr(Vals[4],22)); -Vals[1]+=Ma(Vals[2],Vals[4],Vals[3]); - -W[4]+=(rotr(W[5],7)^rotr(W[5],18)^(W[5]>>3U)); -W[4]+=W[13]; -W[4]+=(rotr(W[2],17)^rotr(W[2],19)^(W[2]>>10U)); -Vals[0]+=W[4]; -Vals[0]+=(rotr(Vals[5],6)^rotr(Vals[5],11)^rotr(Vals[5],25)); -Vals[0]+=ch(Vals[5],Vals[7],Vals[6]); -Vals[0]+=K[36]; -Vals[2]+=Vals[0]; -Vals[0]+=(rotr(Vals[1],2)^rotr(Vals[1],13)^rotr(Vals[1],22)); -Vals[0]+=Ma(Vals[3],Vals[1],Vals[4]); - -W[5]+=(rotr(W[6],7)^rotr(W[6],18)^(W[6]>>3U)); -W[5]+=W[14]; -W[5]+=(rotr(W[3],17)^rotr(W[3],19)^(W[3]>>10U)); -Vals[6]+=W[5]; -Vals[6]+=(rotr(Vals[2],6)^rotr(Vals[2],11)^rotr(Vals[2],25)); -Vals[6]+=ch(Vals[2],Vals[5],Vals[7]); -Vals[6]+=K[37]; -Vals[3]+=Vals[6]; -Vals[6]+=(rotr(Vals[0],2)^rotr(Vals[0],13)^rotr(Vals[0],22)); -Vals[6]+=Ma(Vals[4],Vals[0],Vals[1]); - -W[6]+=(rotr(W[7],7)^rotr(W[7],18)^(W[7]>>3U)); -W[6]+=W[15]; -W[6]+=(rotr(W[4],17)^rotr(W[4],19)^(W[4]>>10U)); -Vals[7]+=W[6]; -Vals[7]+=(rotr(Vals[3],6)^rotr(Vals[3],11)^rotr(Vals[3],25)); -Vals[7]+=ch(Vals[3],Vals[2],Vals[5]); -Vals[7]+=K[38]; -Vals[4]+=Vals[7]; -Vals[7]+=(rotr(Vals[6],2)^rotr(Vals[6],13)^rotr(Vals[6],22)); -Vals[7]+=Ma(Vals[1],Vals[6],Vals[0]); - -W[7]+=(rotr(W[8],7)^rotr(W[8],18)^(W[8]>>3U)); -W[7]+=W[0]; -W[7]+=(rotr(W[5],17)^rotr(W[5],19)^(W[5]>>10U)); -Vals[5]+=W[7]; -Vals[5]+=(rotr(Vals[4],6)^rotr(Vals[4],11)^rotr(Vals[4],25)); -Vals[5]+=ch(Vals[4],Vals[3],Vals[2]); -Vals[5]+=K[39]; -Vals[1]+=Vals[5]; -Vals[5]+=(rotr(Vals[7],2)^rotr(Vals[7],13)^rotr(Vals[7],22)); -Vals[5]+=Ma(Vals[0],Vals[7],Vals[6]); - -W[8]+=(rotr(W[9],7)^rotr(W[9],18)^(W[9]>>3U)); -W[8]+=W[1]; -W[8]+=(rotr(W[6],17)^rotr(W[6],19)^(W[6]>>10U)); -Vals[2]+=W[8]; -Vals[2]+=(rotr(Vals[1],6)^rotr(Vals[1],11)^rotr(Vals[1],25)); -Vals[2]+=ch(Vals[1],Vals[4],Vals[3]); -Vals[2]+=K[40]; -Vals[0]+=Vals[2]; -Vals[2]+=(rotr(Vals[5],2)^rotr(Vals[5],13)^rotr(Vals[5],22)); -Vals[2]+=Ma(Vals[6],Vals[5],Vals[7]); - -W[9]+=(rotr(W[10],7)^rotr(W[10],18)^(W[10]>>3U)); -W[9]+=W[2]; -W[9]+=(rotr(W[7],17)^rotr(W[7],19)^(W[7]>>10U)); -Vals[3]+=W[9]; -Vals[3]+=(rotr(Vals[0],6)^rotr(Vals[0],11)^rotr(Vals[0],25)); -Vals[3]+=ch(Vals[0],Vals[1],Vals[4]); -Vals[3]+=K[41]; -Vals[6]+=Vals[3]; -Vals[3]+=(rotr(Vals[2],2)^rotr(Vals[2],13)^rotr(Vals[2],22)); -Vals[3]+=Ma(Vals[7],Vals[2],Vals[5]); - -W[10]+=(rotr(W[11],7)^rotr(W[11],18)^(W[11]>>3U)); -W[10]+=W[3]; -W[10]+=(rotr(W[8],17)^rotr(W[8],19)^(W[8]>>10U)); -Vals[4]+=W[10]; -Vals[4]+=(rotr(Vals[6],6)^rotr(Vals[6],11)^rotr(Vals[6],25)); -Vals[4]+=ch(Vals[6],Vals[0],Vals[1]); -Vals[4]+=K[42]; -Vals[7]+=Vals[4]; -Vals[4]+=(rotr(Vals[3],2)^rotr(Vals[3],13)^rotr(Vals[3],22)); -Vals[4]+=Ma(Vals[5],Vals[3],Vals[2]); - -W[11]+=(rotr(W[12],7)^rotr(W[12],18)^(W[12]>>3U)); -W[11]+=W[4]; -W[11]+=(rotr(W[9],17)^rotr(W[9],19)^(W[9]>>10U)); -Vals[1]+=W[11]; -Vals[1]+=(rotr(Vals[7],6)^rotr(Vals[7],11)^rotr(Vals[7],25)); -Vals[1]+=ch(Vals[7],Vals[6],Vals[0]); -Vals[1]+=K[43]; -Vals[5]+=Vals[1]; -Vals[1]+=(rotr(Vals[4],2)^rotr(Vals[4],13)^rotr(Vals[4],22)); -Vals[1]+=Ma(Vals[2],Vals[4],Vals[3]); - -W[12]+=(rotr(W[13],7)^rotr(W[13],18)^(W[13]>>3U)); -W[12]+=W[5]; -W[12]+=(rotr(W[10],17)^rotr(W[10],19)^(W[10]>>10U)); -Vals[0]+=W[12]; -Vals[0]+=(rotr(Vals[5],6)^rotr(Vals[5],11)^rotr(Vals[5],25)); -Vals[0]+=ch(Vals[5],Vals[7],Vals[6]); -Vals[0]+=K[44]; -Vals[2]+=Vals[0]; -Vals[0]+=(rotr(Vals[1],2)^rotr(Vals[1],13)^rotr(Vals[1],22)); -Vals[0]+=Ma(Vals[3],Vals[1],Vals[4]); - -W[13]+=(rotr(W[14],7)^rotr(W[14],18)^(W[14]>>3U)); -W[13]+=W[6]; -W[13]+=(rotr(W[11],17)^rotr(W[11],19)^(W[11]>>10U)); -Vals[6]+=W[13]; -Vals[6]+=(rotr(Vals[2],6)^rotr(Vals[2],11)^rotr(Vals[2],25)); -Vals[6]+=ch(Vals[2],Vals[5],Vals[7]); -Vals[6]+=K[45]; -Vals[3]+=Vals[6]; -Vals[6]+=(rotr(Vals[0],2)^rotr(Vals[0],13)^rotr(Vals[0],22)); -Vals[6]+=Ma(Vals[4],Vals[0],Vals[1]); - -W[14]+=(rotr(W[15],7)^rotr(W[15],18)^(W[15]>>3U)); -W[14]+=W[7]; -W[14]+=(rotr(W[12],17)^rotr(W[12],19)^(W[12]>>10U)); -Vals[7]+=W[14]; -Vals[7]+=(rotr(Vals[3],6)^rotr(Vals[3],11)^rotr(Vals[3],25)); -Vals[7]+=ch(Vals[3],Vals[2],Vals[5]); -Vals[7]+=K[46]; -Vals[4]+=Vals[7]; -Vals[7]+=(rotr(Vals[6],2)^rotr(Vals[6],13)^rotr(Vals[6],22)); -Vals[7]+=Ma(Vals[1],Vals[6],Vals[0]); - -W[15]+=(rotr(W[0],7)^rotr(W[0],18)^(W[0]>>3U)); -W[15]+=W[8]; -W[15]+=(rotr(W[13],17)^rotr(W[13],19)^(W[13]>>10U)); -Vals[5]+=W[15]; -Vals[5]+=(rotr(Vals[4],6)^rotr(Vals[4],11)^rotr(Vals[4],25)); -Vals[5]+=ch(Vals[4],Vals[3],Vals[2]); -Vals[5]+=K[47]; -Vals[1]+=Vals[5]; -Vals[5]+=(rotr(Vals[7],2)^rotr(Vals[7],13)^rotr(Vals[7],22)); -Vals[5]+=Ma(Vals[0],Vals[7],Vals[6]); - -W[0]+=(rotr(W[1],7)^rotr(W[1],18)^(W[1]>>3U)); -W[0]+=W[9]; -W[0]+=(rotr(W[14],17)^rotr(W[14],19)^(W[14]>>10U)); -Vals[2]+=W[0]; -Vals[2]+=(rotr(Vals[1],6)^rotr(Vals[1],11)^rotr(Vals[1],25)); -Vals[2]+=ch(Vals[1],Vals[4],Vals[3]); -Vals[2]+=K[48]; -Vals[0]+=Vals[2]; -Vals[2]+=(rotr(Vals[5],2)^rotr(Vals[5],13)^rotr(Vals[5],22)); -Vals[2]+=Ma(Vals[6],Vals[5],Vals[7]); - -W[1]+=(rotr(W[2],7)^rotr(W[2],18)^(W[2]>>3U)); -W[1]+=W[10]; -W[1]+=(rotr(W[15],17)^rotr(W[15],19)^(W[15]>>10U)); -Vals[3]+=W[1]; -Vals[3]+=(rotr(Vals[0],6)^rotr(Vals[0],11)^rotr(Vals[0],25)); -Vals[3]+=ch(Vals[0],Vals[1],Vals[4]); -Vals[3]+=K[49]; -Vals[6]+=Vals[3]; -Vals[3]+=(rotr(Vals[2],2)^rotr(Vals[2],13)^rotr(Vals[2],22)); -Vals[3]+=Ma(Vals[7],Vals[2],Vals[5]); - -W[2]+=(rotr(W[3],7)^rotr(W[3],18)^(W[3]>>3U)); -W[2]+=W[11]; -W[2]+=(rotr(W[0],17)^rotr(W[0],19)^(W[0]>>10U)); -Vals[4]+=W[2]; -Vals[4]+=(rotr(Vals[6],6)^rotr(Vals[6],11)^rotr(Vals[6],25)); -Vals[4]+=ch(Vals[6],Vals[0],Vals[1]); -Vals[4]+=K[50]; -Vals[7]+=Vals[4]; -Vals[4]+=(rotr(Vals[3],2)^rotr(Vals[3],13)^rotr(Vals[3],22)); -Vals[4]+=Ma(Vals[5],Vals[3],Vals[2]); - -W[3]+=(rotr(W[4],7)^rotr(W[4],18)^(W[4]>>3U)); -W[3]+=W[12]; -W[3]+=(rotr(W[1],17)^rotr(W[1],19)^(W[1]>>10U)); -Vals[1]+=W[3]; -Vals[1]+=(rotr(Vals[7],6)^rotr(Vals[7],11)^rotr(Vals[7],25)); -Vals[1]+=ch(Vals[7],Vals[6],Vals[0]); -Vals[1]+=K[51]; -Vals[5]+=Vals[1]; -Vals[1]+=(rotr(Vals[4],2)^rotr(Vals[4],13)^rotr(Vals[4],22)); -Vals[1]+=Ma(Vals[2],Vals[4],Vals[3]); - -W[4]+=(rotr(W[5],7)^rotr(W[5],18)^(W[5]>>3U)); -W[4]+=W[13]; -W[4]+=(rotr(W[2],17)^rotr(W[2],19)^(W[2]>>10U)); -Vals[0]+=W[4]; -Vals[0]+=(rotr(Vals[5],6)^rotr(Vals[5],11)^rotr(Vals[5],25)); -Vals[0]+=ch(Vals[5],Vals[7],Vals[6]); -Vals[0]+=K[52]; -Vals[2]+=Vals[0]; -Vals[0]+=(rotr(Vals[1],2)^rotr(Vals[1],13)^rotr(Vals[1],22)); -Vals[0]+=Ma(Vals[3],Vals[1],Vals[4]); - -W[5]+=(rotr(W[6],7)^rotr(W[6],18)^(W[6]>>3U)); -W[5]+=W[14]; -W[5]+=(rotr(W[3],17)^rotr(W[3],19)^(W[3]>>10U)); -Vals[6]+=W[5]; -Vals[6]+=(rotr(Vals[2],6)^rotr(Vals[2],11)^rotr(Vals[2],25)); -Vals[6]+=ch(Vals[2],Vals[5],Vals[7]); -Vals[6]+=K[53]; -Vals[3]+=Vals[6]; -Vals[6]+=(rotr(Vals[0],2)^rotr(Vals[0],13)^rotr(Vals[0],22)); -Vals[6]+=Ma(Vals[4],Vals[0],Vals[1]); - -W[6]+=(rotr(W[7],7)^rotr(W[7],18)^(W[7]>>3U)); -W[6]+=W[15]; -W[6]+=(rotr(W[4],17)^rotr(W[4],19)^(W[4]>>10U)); -Vals[7]+=W[6]; -Vals[7]+=(rotr(Vals[3],6)^rotr(Vals[3],11)^rotr(Vals[3],25)); -Vals[7]+=ch(Vals[3],Vals[2],Vals[5]); -Vals[7]+=K[54]; -Vals[4]+=Vals[7]; -Vals[7]+=(rotr(Vals[6],2)^rotr(Vals[6],13)^rotr(Vals[6],22)); -Vals[7]+=Ma(Vals[1],Vals[6],Vals[0]); - -W[7]+=(rotr(W[8],7)^rotr(W[8],18)^(W[8]>>3U)); -W[7]+=W[0]; -W[7]+=(rotr(W[5],17)^rotr(W[5],19)^(W[5]>>10U)); -Vals[5]+=W[7]; -Vals[5]+=(rotr(Vals[4],6)^rotr(Vals[4],11)^rotr(Vals[4],25)); -Vals[5]+=ch(Vals[4],Vals[3],Vals[2]); -Vals[5]+=K[55]; -Vals[1]+=Vals[5]; -Vals[5]+=(rotr(Vals[7],2)^rotr(Vals[7],13)^rotr(Vals[7],22)); -Vals[5]+=Ma(Vals[0],Vals[7],Vals[6]); - -W[8]+=(rotr(W[9],7)^rotr(W[9],18)^(W[9]>>3U)); -W[8]+=W[1]; -W[8]+=(rotr(W[6],17)^rotr(W[6],19)^(W[6]>>10U)); -Vals[2]+=W[8]; -Vals[2]+=(rotr(Vals[1],6)^rotr(Vals[1],11)^rotr(Vals[1],25)); -Vals[2]+=ch(Vals[1],Vals[4],Vals[3]); -Vals[2]+=K[56]; -Vals[0]+=Vals[2]; - -W[9]+=(rotr(W[10],7)^rotr(W[10],18)^(W[10]>>3U)); -W[9]+=W[2]; -W[9]+=(rotr(W[7],17)^rotr(W[7],19)^(W[7]>>10U)); -Vals[3]+=W[9]; -Vals[3]+=(rotr(Vals[0],6)^rotr(Vals[0],11)^rotr(Vals[0],25)); -Vals[3]+=ch(Vals[0],Vals[1],Vals[4]); -Vals[3]+=K[57]; -Vals[3]+=Vals[6]; - -W[10]+=(rotr(W[11],7)^rotr(W[11],18)^(W[11]>>3U)); -W[10]+=W[3]; -W[10]+=(rotr(W[8],17)^rotr(W[8],19)^(W[8]>>10U)); -Vals[4]+=W[10]; -Vals[4]+=(rotr(Vals[3],6)^rotr(Vals[3],11)^rotr(Vals[3],25)); -Vals[4]+=ch(Vals[3],Vals[0],Vals[1]); -Vals[4]+=K[58]; -Vals[4]+=Vals[7]; -Vals[1]+=(rotr(Vals[4],6)^rotr(Vals[4],11)^rotr(Vals[4],25)); -Vals[1]+=ch(Vals[4],Vals[3],Vals[0]); -Vals[1]+=W[11]; -Vals[1]+=(rotr(W[12],7)^rotr(W[12],18)^(W[12]>>3U)); -Vals[1]+=W[4]; -Vals[1]+=(rotr(W[9],17)^rotr(W[9],19)^(W[9]>>10U)); -Vals[1]+=K[59]; -Vals[1]+=Vals[5]; - -Vals[2]+=Ma(Vals[6],Vals[5],Vals[7]); -Vals[2]+=(rotr(Vals[5],2)^rotr(Vals[5],13)^rotr(Vals[5],22)); -Vals[2]+=W[12]; -Vals[2]+=(rotr(W[13],7)^rotr(W[13],18)^(W[13]>>3U)); -Vals[2]+=W[5]; -Vals[2]+=(rotr(W[10],17)^rotr(W[10],19)^(W[10]>>10U)); -Vals[2]+=Vals[0]; -Vals[2]+=(rotr(Vals[1],6)^rotr(Vals[1],11)^rotr(Vals[1],25)); -Vals[2]+=ch(Vals[1],Vals[4],Vals[3]); - -#define FOUND (0x0F) -#define SETFOUND(Xnonce) output[output[FOUND]++] = Xnonce - -#if defined(VECTORS2) || defined(VECTORS4) - if (any(Vals[2] == x136032edU)) { - if (Vals[2].x == x136032edU) - SETFOUND(nonce.x); - if (Vals[2].y == x136032edU) - SETFOUND(nonce.y); -#if defined(VECTORS4) - if (Vals[2].z == x136032edU) - SETFOUND(nonce.z); - if (Vals[2].w == x136032edU) - SETFOUND(nonce.w); -#endif - } -#else - if (Vals[2] == x136032edU) - SETFOUND(nonce); -#endif -} diff --git a/usbutils.c b/usbutils.c deleted file mode 100644 index 130331c0..00000000 --- a/usbutils.c +++ /dev/null @@ -1,3709 +0,0 @@ -/* - * Copyright 2012-2013 Andrew Smith - * Copyright 2013 Con Kolivas - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. See COPYING for more details. - */ - -#include "config.h" - -#include -#include -#include - -#include "logging.h" -#include "miner.h" -#include "usbutils.h" - -#define NODEV(err) ((err) == LIBUSB_ERROR_NO_DEVICE || \ - (err) == LIBUSB_ERROR_PIPE || \ - (err) == LIBUSB_ERROR_OTHER) - -/* Timeout errors on writes are basically unrecoverable */ -#define WRITENODEV(err) ((err) == LIBUSB_ERROR_TIMEOUT || NODEV(err)) - -#define NOCONTROLDEV(err) ((err) == LIBUSB_ERROR_NO_DEVICE || \ - (err) == LIBUSB_ERROR_OTHER) - -/* - * WARNING - these assume DEVLOCK(cgpu, pstate) is called first and - * DEVUNLOCK(cgpu, pstate) in called in the same function with the same pstate - * given to DEVLOCK. - * You must call DEVUNLOCK(cgpu, pstate) before exiting the function or it will leave - * the thread Cancelability unrestored - */ -#define DEVWLOCK(cgpu, _pth_state) do { \ - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &_pth_state); \ - cg_wlock(&cgpu->usbinfo.devlock); \ - } while (0) - -#define DEVWUNLOCK(cgpu, _pth_state) do { \ - cg_wunlock(&cgpu->usbinfo.devlock); \ - pthread_setcancelstate(_pth_state, NULL); \ - } while (0) - -#define DEVRLOCK(cgpu, _pth_state) do { \ - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &_pth_state); \ - cg_rlock(&cgpu->usbinfo.devlock); \ - } while (0) - -#define DEVRUNLOCK(cgpu, _pth_state) do { \ - cg_runlock(&cgpu->usbinfo.devlock); \ - pthread_setcancelstate(_pth_state, NULL); \ - } while (0) - -#define USB_CONFIG 1 - -#ifdef WIN32 -#define BFLSC_TIMEOUT_MS 999 -#define BITFORCE_TIMEOUT_MS 999 -#define BITFURY_TIMEOUT_MS 999 -#define MODMINER_TIMEOUT_MS 999 -#define AVALON_TIMEOUT_MS 999 -#define KLONDIKE_TIMEOUT_MS 999 -#define ICARUS_TIMEOUT_MS 999 -#define HASHFAST_TIMEOUT_MS 999 - -/* The safety timeout we use, cancelling async transfers on windows that fail - * to timeout on their own. */ -#define WIN_CALLBACK_EXTRA 40 -#else -#define BFLSC_TIMEOUT_MS 300 -#define BITFORCE_TIMEOUT_MS 200 -#define BITFURY_TIMEOUT_MS 100 -#define MODMINER_TIMEOUT_MS 100 -#define AVALON_TIMEOUT_MS 200 -#define KLONDIKE_TIMEOUT_MS 200 -#define ICARUS_TIMEOUT_MS 200 -#define HASHFAST_TIMEOUT_MS 200 -#endif - -#define USB_EPS(_intx, _epinfosx) { \ - .interface = _intx, \ - .ctrl_transfer = _intx, \ - .epinfo_count = ARRAY_SIZE(_epinfosx), \ - .epinfos = _epinfosx \ - } - -#define USB_EPS_CTRL(_inty, _ctrlinty, _epinfosy) { \ - .interface = _inty, \ - .ctrl_transfer = _ctrlinty, \ - .epinfo_count = ARRAY_SIZE(_epinfosy), \ - .epinfos = _epinfosy \ - } - -/* Linked list of all async transfers in progress. Protected by cgusb_fd_lock. - * This allows us to not stop the usb polling thread till all are complete, and - * to find cancellable transfers. */ -static struct list_head ut_list; - -#ifdef USE_BFLSC -// N.B. transfer size is 512 with USB2.0, but only 64 with USB1.1 -static struct usb_epinfo bas_epinfos[] = { - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(1), 0, 0 }, - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(2), 0, 0 } -}; - -static struct usb_intinfo bas_ints[] = { - USB_EPS(0, bas_epinfos) -}; -#endif - -#ifdef USE_BITFORCE -// N.B. transfer size is 512 with USB2.0, but only 64 with USB1.1 -static struct usb_epinfo bfl_epinfos[] = { - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(1), 0, 0 }, - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(2), 0, 0 } -}; - -static struct usb_intinfo bfl_ints[] = { - USB_EPS(0, bfl_epinfos) -}; -#endif - -#ifdef USE_BITFURY -static struct usb_epinfo bfu0_epinfos[] = { - { LIBUSB_TRANSFER_TYPE_INTERRUPT, 8, EPI(2), 0, 0 } -}; - -static struct usb_epinfo bfu1_epinfos[] = { - { LIBUSB_TRANSFER_TYPE_BULK, 16, EPI(3), 0, 0 }, - { LIBUSB_TRANSFER_TYPE_BULK, 16, EPO(4), 0, 0 } -}; - -/* Default to interface 1 */ -static struct usb_intinfo bfu_ints[] = { - USB_EPS(1, bfu1_epinfos), - USB_EPS(0, bfu0_epinfos) -}; -#endif - -#ifdef USE_HASHFAST -#include "driver-hashfast.h" - -static struct usb_epinfo hfa0_epinfos[] = { - { LIBUSB_TRANSFER_TYPE_INTERRUPT, 8, EPI(3), 0, 0 } -}; - -static struct usb_epinfo hfa1_epinfos[] = { - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(1), 0, 0 }, - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(2), 0, 0 } -}; - -/* Default to interface 1 */ -static struct usb_intinfo hfa_ints[] = { - USB_EPS(1, hfa1_epinfos), - USB_EPS(0, hfa0_epinfos) -}; -#endif - -#ifdef USE_MODMINER -static struct usb_epinfo mmq_epinfos[] = { - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(3), 0, 0 }, - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(3), 0, 0 } -}; - -static struct usb_intinfo mmq_ints[] = { - USB_EPS(1, mmq_epinfos) -}; -#endif - -#ifdef USE_AVALON -static struct usb_epinfo ava_epinfos[] = { - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(1), 0, 0 }, - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(2), 0, 0 } -}; - -static struct usb_intinfo ava_ints[] = { - USB_EPS(0, ava_epinfos) -}; -#endif - -#ifdef USE_KLONDIKE -static struct usb_epinfo kln_epinfos[] = { - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(1), 0, 0 }, - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(1), 0, 0 } -}; - -static struct usb_intinfo kln_ints[] = { - USB_EPS(0, kln_epinfos) -}; -#endif - -#ifdef USE_ICARUS -static struct usb_epinfo ica_epinfos[] = { - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(3), 0, 0 }, - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(2), 0, 0 } -}; - -static struct usb_intinfo ica_ints[] = { - USB_EPS(0, ica_epinfos) -}; - -static struct usb_epinfo amu_epinfos[] = { - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(1), 0, 0 }, - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(1), 0, 0 } -}; - -static struct usb_intinfo amu_ints[] = { - USB_EPS(0, amu_epinfos) -}; - -static struct usb_epinfo llt_epinfos[] = { - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(1), 0, 0 }, - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(2), 0, 0 } -}; - -static struct usb_intinfo llt_ints[] = { - USB_EPS(0, llt_epinfos) -}; - -static struct usb_epinfo cmr1_epinfos[] = { - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(1), 0, 0 }, - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(2), 0, 0 } -}; - -static struct usb_intinfo cmr1_ints[] = { - USB_EPS(0, cmr1_epinfos) -}; - -static struct usb_epinfo cmr2_epinfos0[] = { - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(1), 0, 0 }, - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(2), 0, 0 } -}; -static struct usb_epinfo cmr2_epinfos1[] = { - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(3), 0, 0 }, - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(4), 0, 0 }, -}; -static struct usb_epinfo cmr2_epinfos2[] = { - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(5), 0, 0 }, - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(6), 0, 0 }, -}; -static struct usb_epinfo cmr2_epinfos3[] = { - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(7), 0, 0 }, - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(8), 0, 0 } -}; - -static struct usb_intinfo cmr2_ints[] = { - USB_EPS_CTRL(0, 1, cmr2_epinfos0), - USB_EPS_CTRL(1, 2, cmr2_epinfos1), - USB_EPS_CTRL(2, 3, cmr2_epinfos2), - USB_EPS_CTRL(3, 4, cmr2_epinfos3) -}; -#endif - -#define IDVENDOR_FTDI 0x0403 - -#define INTINFO(_ints) \ - .intinfo_count = ARRAY_SIZE(_ints), \ - .intinfos = _ints - -#define USBEP(_usbdev, _intinfo, _epinfo) (_usbdev->found->intinfos[_intinfo].epinfos[_epinfo].ep) -#define THISIF(_found, _this) (_found->intinfos[_this].interface) -#define USBIF(_usbdev, _this) THISIF(_usbdev->found, _this) - -// TODO: Add support for (at least) Isochronous endpoints -static struct usb_find_devices find_dev[] = { -#ifdef USE_BFLSC - { - .drv = DRIVER_bflsc, - .name = "BAS", - .ident = IDENT_BAS, - .idVendor = IDVENDOR_FTDI, - .idProduct = 0x6014, - //.iManufacturer = "Butterfly Labs", - .iProduct = "BitFORCE SHA256 SC", - .config = 1, - .timeout = BFLSC_TIMEOUT_MS, - .latency = LATENCY_STD, - INTINFO(bas_ints) }, -#endif -#ifdef USE_BITFORCE - { - .drv = DRIVER_bitforce, - .name = "BFL", - .ident = IDENT_BFL, - .idVendor = IDVENDOR_FTDI, - .idProduct = 0x6014, - .iManufacturer = "Butterfly Labs Inc.", - .iProduct = "BitFORCE SHA256", - .config = 1, - .timeout = BITFORCE_TIMEOUT_MS, - .latency = LATENCY_STD, - INTINFO(bfl_ints) }, -#endif -#ifdef USE_BITFURY - { - .drv = DRIVER_bitfury, - .name = "BF1", - .ident = IDENT_BFU, - .idVendor = 0x03eb, - .idProduct = 0x204b, - .config = 1, - .timeout = BITFURY_TIMEOUT_MS, - .latency = LATENCY_UNUSED, - //.iManufacturer = "BPMC", - .iProduct = "Bitfury BF1", - INTINFO(bfu_ints) - }, -#endif -#ifdef USE_MODMINER - { - .drv = DRIVER_modminer, - .name = "MMQ", - .ident = IDENT_MMQ, - .idVendor = 0x1fc9, - .idProduct = 0x0003, - .config = 1, - .timeout = MODMINER_TIMEOUT_MS, - .latency = LATENCY_UNUSED, - INTINFO(mmq_ints) }, -#endif -#ifdef USE_AVALON - { - .drv = DRIVER_avalon, - .name = "BTB", - .ident = IDENT_BTB, - .idVendor = IDVENDOR_FTDI, - .idProduct = 0x6001, - .iManufacturer = "Burnin Electronics", - .iProduct = "BitBurner", - .config = 1, - .timeout = AVALON_TIMEOUT_MS, - .latency = 10, - INTINFO(ava_ints) }, - { - .drv = DRIVER_avalon, - .name = "BBF", - .ident = IDENT_BBF, - .idVendor = IDVENDOR_FTDI, - .idProduct = 0x6001, - .iManufacturer = "Burnin Electronics", - .iProduct = "BitBurner Fury", - .config = 1, - .timeout = AVALON_TIMEOUT_MS, - .latency = 10, - INTINFO(ava_ints) }, - { - .drv = DRIVER_avalon, - .name = "AVA", - .ident = IDENT_AVA, - .idVendor = IDVENDOR_FTDI, - .idProduct = 0x6001, - .config = 1, - .timeout = AVALON_TIMEOUT_MS, - .latency = 10, - INTINFO(ava_ints) }, -#endif -#ifdef USE_HASHFAST - { - .drv = DRIVER_hashfast, - .name = "HFA", - .ident = IDENT_HFA, - .idVendor = HF_USB_VENDOR_ID, - .idProduct = HF_USB_PRODUCT_ID_G1, - .iManufacturer = "HashFast LLC", - .iProduct = "M1 Module", - .config = 1, - .timeout = HASHFAST_TIMEOUT_MS, - .latency = LATENCY_UNUSED, - INTINFO(hfa_ints) }, -#endif -#ifdef USE_KLONDIKE - { - .drv = DRIVER_klondike, - .name = "KLN", - .ident = IDENT_KLN, - .idVendor = 0x04D8, - .idProduct = 0xF60A, - .config = 1, - .timeout = KLONDIKE_TIMEOUT_MS, - .latency = 10, - INTINFO(kln_ints) }, -#endif -#ifdef USE_ICARUS - { - .drv = DRIVER_icarus, - .name = "ICA", - .ident = IDENT_ICA, - .idVendor = 0x067b, - .idProduct = 0x2303, - .config = 1, - .timeout = ICARUS_TIMEOUT_MS, - .latency = LATENCY_UNUSED, - INTINFO(ica_ints) }, - { - .drv = DRIVER_icarus, - .name = "AMU", - .ident = IDENT_AMU, - .idVendor = 0x10c4, - .idProduct = 0xea60, - .config = 1, - .timeout = ICARUS_TIMEOUT_MS, - .latency = LATENCY_UNUSED, - INTINFO(amu_ints) }, - { - .drv = DRIVER_icarus, - .name = "BLT", - .ident = IDENT_BLT, - .idVendor = IDVENDOR_FTDI, - .idProduct = 0x6001, - .iProduct = "FT232R USB UART", - .config = 1, - .timeout = ICARUS_TIMEOUT_MS, - .latency = LATENCY_STD, - INTINFO(llt_ints) }, - // For any that don't match the above "BLT" - { - .drv = DRIVER_icarus, - .name = "LLT", - .ident = IDENT_LLT, - .idVendor = IDVENDOR_FTDI, - .idProduct = 0x6001, - .config = 1, - .timeout = ICARUS_TIMEOUT_MS, - .latency = LATENCY_STD, - INTINFO(llt_ints) }, - { - .drv = DRIVER_icarus, - .name = "CMR", - .ident = IDENT_CMR1, - .idVendor = IDVENDOR_FTDI, - .idProduct = 0x6014, - .iProduct = "Cairnsmore1", - .config = 1, - .timeout = ICARUS_TIMEOUT_MS, - .latency = LATENCY_STD, - INTINFO(cmr1_ints) }, - { - .drv = DRIVER_icarus, - .name = "CMR", - .ident = IDENT_CMR2, - .idVendor = IDVENDOR_FTDI, - .idProduct = 0x8350, - .iProduct = "Cairnsmore1", - .config = 1, - .timeout = ICARUS_TIMEOUT_MS, - .latency = LATENCY_STD, - INTINFO(cmr2_ints) }, -#endif - { DRIVER_MAX, NULL, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, NULL } -}; - -#define STRBUFLEN 256 -static const char *BLANK = ""; -static const char *space = " "; -static const char *nodatareturned = "no data returned "; - -#define IOERR_CHECK(cgpu, err) \ - if (err == LIBUSB_ERROR_IO) { \ - cgpu->usbinfo.ioerr_count++; \ - cgpu->usbinfo.continuous_ioerr_count++; \ - } else { \ - cgpu->usbinfo.continuous_ioerr_count = 0; \ - } - -/* Timeout errors on writes are unusual and should be treated as IO errors. */ -#define WRITEIOERR_CHECK(cgpu, err) \ - if (err == LIBUSB_ERROR_IO || err == LIBUSB_ERROR_TIMEOUT) { \ - cgpu->usbinfo.ioerr_count++; \ - cgpu->usbinfo.continuous_ioerr_count++; \ - } else { \ - cgpu->usbinfo.continuous_ioerr_count = 0; \ - } - -#if 0 // enable USBDEBUG - only during development testing - static const char *debug_true_str = "true"; - static const char *debug_false_str = "false"; - static const char *nodevstr = "=NODEV"; - #define bool_str(boo) ((boo) ? debug_true_str : debug_false_str) - #define isnodev(err) (NODEV(err) ? nodevstr : BLANK) - #define USBDEBUG(fmt, ...) applog(LOG_WARNING, fmt, ##__VA_ARGS__) -#else - #define USBDEBUG(fmt, ...) -#endif - -// For device limits by driver -static struct driver_count { - uint32_t count; - uint32_t limit; -} drv_count[DRIVER_MAX]; - -// For device limits by list of bus/dev -static struct usb_busdev { - int bus_number; - int device_address; - void *resource1; - void *resource2; -} *busdev; - -static int busdev_count = 0; - -// Total device limit -static int total_count = 0; -static int total_limit = 999999; - -struct usb_in_use_list { - struct usb_busdev in_use; - struct usb_in_use_list *prev; - struct usb_in_use_list *next; -}; - -// List of in use devices -static struct usb_in_use_list *in_use_head = NULL; - -struct resource_work { - bool lock; - const char *dname; - uint8_t bus_number; - uint8_t device_address; - struct resource_work *next; -}; - -// Pending work for the reslock thread -struct resource_work *res_work_head = NULL; - -struct resource_reply { - uint8_t bus_number; - uint8_t device_address; - bool got; - struct resource_reply *next; -}; - -// Replies to lock requests -struct resource_reply *res_reply_head = NULL; - -// Some stats need to always be defined -#define SEQ0 0 -#define SEQ1 1 - -// NONE must be 0 - calloced -#define MODE_NONE 0 -#define MODE_CTRL_READ (1 << 0) -#define MODE_CTRL_WRITE (1 << 1) -#define MODE_BULK_READ (1 << 2) -#define MODE_BULK_WRITE (1 << 3) - -// Set this to 0 to remove stats processing -#define DO_USB_STATS 1 - -static bool stats_initialised = false; - -#if DO_USB_STATS - -#define MODE_SEP_STR "+" -#define MODE_NONE_STR "X" -#define MODE_CTRL_READ_STR "cr" -#define MODE_CTRL_WRITE_STR "cw" -#define MODE_BULK_READ_STR "br" -#define MODE_BULK_WRITE_STR "bw" - -// One for each CMD, TIMEOUT, ERROR -struct cg_usb_stats_item { - uint64_t count; - double total_delay; - double min_delay; - double max_delay; - struct timeval first; - struct timeval last; -}; - -#define CMD_CMD 0 -#define CMD_TIMEOUT 1 -#define CMD_ERROR 2 - -// One for each C_CMD -struct cg_usb_stats_details { - int seq; - uint32_t modes; - struct cg_usb_stats_item item[CMD_ERROR+1]; -}; - -// One for each device -struct cg_usb_stats { - char *name; - int device_id; - struct cg_usb_stats_details *details; -}; - -static struct cg_usb_stats *usb_stats = NULL; -static int next_stat = USB_NOSTAT; - -#define SECTOMS(s) ((int)((s) * 1000)) - -#define USB_STATS(sgpu_, sta_, fin_, err_, mode_, cmd_, seq_, tmo_) \ - stats(sgpu_, sta_, fin_, err_, mode_, cmd_, seq_, tmo_) -#define STATS_TIMEVAL(tv_) cgtime(tv_) -#define USB_REJECT(sgpu_, mode_) rejected_inc(sgpu_, mode_) - -#else -#define USB_STATS(sgpu_, sta_, fin_, err_, mode_, cmd_, seq_, tmo_) -#define STATS_TIMEVAL(tv_) -#define USB_REJECT(sgpu_, mode_) - -#endif // DO_USB_STATS - -/* Create usb_commands array from USB_PARSE_COMMANDS macro in usbutils.h */ -char *usb_commands[] = { - USB_PARSE_COMMANDS(JUMPTABLE) - "Null" -}; - -#ifdef EOL -#undef EOL -#endif -#define EOL "\n" - -static const char *DESDEV = "Device"; -static const char *DESCON = "Config"; -static const char *DESSTR = "String"; -static const char *DESINT = "Interface"; -static const char *DESEP = "Endpoint"; -static const char *DESHID = "HID"; -static const char *DESRPT = "Report"; -static const char *DESPHY = "Physical"; -static const char *DESHUB = "Hub"; - -static const char *EPIN = "In: "; -static const char *EPOUT = "Out: "; -static const char *EPX = "?: "; - -static const char *CONTROL = "Control"; -static const char *ISOCHRONOUS_X = "Isochronous+?"; -static const char *ISOCHRONOUS_N_X = "Isochronous+None+?"; -static const char *ISOCHRONOUS_N_D = "Isochronous+None+Data"; -static const char *ISOCHRONOUS_N_F = "Isochronous+None+Feedback"; -static const char *ISOCHRONOUS_N_I = "Isochronous+None+Implicit"; -static const char *ISOCHRONOUS_A_X = "Isochronous+Async+?"; -static const char *ISOCHRONOUS_A_D = "Isochronous+Async+Data"; -static const char *ISOCHRONOUS_A_F = "Isochronous+Async+Feedback"; -static const char *ISOCHRONOUS_A_I = "Isochronous+Async+Implicit"; -static const char *ISOCHRONOUS_D_X = "Isochronous+Adaptive+?"; -static const char *ISOCHRONOUS_D_D = "Isochronous+Adaptive+Data"; -static const char *ISOCHRONOUS_D_F = "Isochronous+Adaptive+Feedback"; -static const char *ISOCHRONOUS_D_I = "Isochronous+Adaptive+Implicit"; -static const char *ISOCHRONOUS_S_X = "Isochronous+Sync+?"; -static const char *ISOCHRONOUS_S_D = "Isochronous+Sync+Data"; -static const char *ISOCHRONOUS_S_F = "Isochronous+Sync+Feedback"; -static const char *ISOCHRONOUS_S_I = "Isochronous+Sync+Implicit"; -static const char *BULK = "Bulk"; -static const char *INTERRUPT = "Interrupt"; -static const char *UNKNOWN = "Unknown"; - -static const char *destype(uint8_t bDescriptorType) -{ - switch (bDescriptorType) { - case LIBUSB_DT_DEVICE: - return DESDEV; - case LIBUSB_DT_CONFIG: - return DESCON; - case LIBUSB_DT_STRING: - return DESSTR; - case LIBUSB_DT_INTERFACE: - return DESINT; - case LIBUSB_DT_ENDPOINT: - return DESEP; - case LIBUSB_DT_HID: - return DESHID; - case LIBUSB_DT_REPORT: - return DESRPT; - case LIBUSB_DT_PHYSICAL: - return DESPHY; - case LIBUSB_DT_HUB: - return DESHUB; - } - return UNKNOWN; -} - -static const char *epdir(uint8_t bEndpointAddress) -{ - switch (bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) { - case LIBUSB_ENDPOINT_IN: - return EPIN; - case LIBUSB_ENDPOINT_OUT: - return EPOUT; - } - return EPX; -} - -static const char *epatt(uint8_t bmAttributes) -{ - switch(bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) { - case LIBUSB_TRANSFER_TYPE_CONTROL: - return CONTROL; - case LIBUSB_TRANSFER_TYPE_BULK: - return BULK; - case LIBUSB_TRANSFER_TYPE_INTERRUPT: - return INTERRUPT; - case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: - switch(bmAttributes & LIBUSB_ISO_SYNC_TYPE_MASK) { - case LIBUSB_ISO_SYNC_TYPE_NONE: - switch(bmAttributes & LIBUSB_ISO_USAGE_TYPE_MASK) { - case LIBUSB_ISO_USAGE_TYPE_DATA: - return ISOCHRONOUS_N_D; - case LIBUSB_ISO_USAGE_TYPE_FEEDBACK: - return ISOCHRONOUS_N_F; - case LIBUSB_ISO_USAGE_TYPE_IMPLICIT: - return ISOCHRONOUS_N_I; - } - return ISOCHRONOUS_N_X; - case LIBUSB_ISO_SYNC_TYPE_ASYNC: - switch(bmAttributes & LIBUSB_ISO_USAGE_TYPE_MASK) { - case LIBUSB_ISO_USAGE_TYPE_DATA: - return ISOCHRONOUS_A_D; - case LIBUSB_ISO_USAGE_TYPE_FEEDBACK: - return ISOCHRONOUS_A_F; - case LIBUSB_ISO_USAGE_TYPE_IMPLICIT: - return ISOCHRONOUS_A_I; - } - return ISOCHRONOUS_A_X; - case LIBUSB_ISO_SYNC_TYPE_ADAPTIVE: - switch(bmAttributes & LIBUSB_ISO_USAGE_TYPE_MASK) { - case LIBUSB_ISO_USAGE_TYPE_DATA: - return ISOCHRONOUS_D_D; - case LIBUSB_ISO_USAGE_TYPE_FEEDBACK: - return ISOCHRONOUS_D_F; - case LIBUSB_ISO_USAGE_TYPE_IMPLICIT: - return ISOCHRONOUS_D_I; - } - return ISOCHRONOUS_D_X; - case LIBUSB_ISO_SYNC_TYPE_SYNC: - switch(bmAttributes & LIBUSB_ISO_USAGE_TYPE_MASK) { - case LIBUSB_ISO_USAGE_TYPE_DATA: - return ISOCHRONOUS_S_D; - case LIBUSB_ISO_USAGE_TYPE_FEEDBACK: - return ISOCHRONOUS_S_F; - case LIBUSB_ISO_USAGE_TYPE_IMPLICIT: - return ISOCHRONOUS_S_I; - } - return ISOCHRONOUS_S_X; - } - return ISOCHRONOUS_X; - } - - return UNKNOWN; -} - -static void append(char **buf, char *append, size_t *off, size_t *len) -{ - int new = strlen(append); - if ((new + *off) >= *len) - { - *len *= 2; - *buf = realloc(*buf, *len); - if (unlikely(!*buf)) - quit(1, "USB failed to realloc append"); - } - - strcpy(*buf + *off, append); - *off += new; -} - -static bool setgetdes(ssize_t count, libusb_device *dev, struct libusb_device_handle *handle, struct libusb_config_descriptor **config, int cd, char **buf, size_t *off, size_t *len) -{ - char tmp[512]; - int err; - - err = libusb_set_configuration(handle, cd); - if (err) { - snprintf(tmp, sizeof(tmp), EOL " ** dev %d: Failed to set config descriptor to %d, err %d", - (int)count, cd, err); - append(buf, tmp, off, len); - return false; - } - - err = libusb_get_active_config_descriptor(dev, config); - if (err) { - snprintf(tmp, sizeof(tmp), EOL " ** dev %d: Failed to get active config descriptor set to %d, err %d", - (int)count, cd, err); - append(buf, tmp, off, len); - return false; - } - - snprintf(tmp, sizeof(tmp), EOL " ** dev %d: Set & Got active config descriptor to %d, err %d", - (int)count, cd, err); - append(buf, tmp, off, len); - return true; -} - -static void usb_full(ssize_t *count, libusb_device *dev, char **buf, size_t *off, size_t *len, int level) -{ - struct libusb_device_descriptor desc; - uint8_t bus_number; - uint8_t device_address; - struct libusb_device_handle *handle; - struct libusb_config_descriptor *config; - const struct libusb_interface_descriptor *idesc; - const struct libusb_endpoint_descriptor *epdesc; - unsigned char man[STRBUFLEN+1]; - unsigned char prod[STRBUFLEN+1]; - unsigned char ser[STRBUFLEN+1]; - char tmp[512]; - int err, i, j, k; - - err = libusb_get_device_descriptor(dev, &desc); - if (opt_usb_list_all && err) { - snprintf(tmp, sizeof(tmp), EOL ".USB dev %d: Failed to get descriptor, err %d", - (int)(++(*count)), err); - append(buf, tmp, off, len); - return; - } - - bus_number = libusb_get_bus_number(dev); - device_address = libusb_get_device_address(dev); - - if (!opt_usb_list_all) { - bool known = false; - - for (i = 0; find_dev[i].drv != DRIVER_MAX; i++) - if ((find_dev[i].idVendor == desc.idVendor) && - (find_dev[i].idProduct == desc.idProduct)) { - known = true; - break; - } - - if (!known) - return; - } - - (*count)++; - - if (level == 0) { - snprintf(tmp, sizeof(tmp), EOL ".USB dev %d: Bus %d Device %d ID: %04x:%04x", - (int)(*count), (int)bus_number, (int)device_address, - desc.idVendor, desc.idProduct); - } else { - snprintf(tmp, sizeof(tmp), EOL ".USB dev %d: Bus %d Device %d Device Descriptor:" EOL "\tLength: %d" EOL - "\tDescriptor Type: %s" EOL "\tUSB: %04x" EOL "\tDeviceClass: %d" EOL - "\tDeviceSubClass: %d" EOL "\tDeviceProtocol: %d" EOL "\tMaxPacketSize0: %d" EOL - "\tidVendor: %04x" EOL "\tidProduct: %04x" EOL "\tDeviceRelease: %x" EOL - "\tNumConfigurations: %d", - (int)(*count), (int)bus_number, (int)device_address, - (int)(desc.bLength), destype(desc.bDescriptorType), - desc.bcdUSB, (int)(desc.bDeviceClass), (int)(desc.bDeviceSubClass), - (int)(desc.bDeviceProtocol), (int)(desc.bMaxPacketSize0), - desc.idVendor, desc.idProduct, desc.bcdDevice, - (int)(desc.bNumConfigurations)); - } - append(buf, tmp, off, len); - - err = libusb_open(dev, &handle); - if (err) { - snprintf(tmp, sizeof(tmp), EOL " ** dev %d: Failed to open, err %d", (int)(*count), err); - append(buf, tmp, off, len); - return; - } - - err = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, man, STRBUFLEN); - if (err < 0) - snprintf((char *)man, sizeof(man), "** err:(%d) %s", err, libusb_error_name(err)); - - err = libusb_get_string_descriptor_ascii(handle, desc.iProduct, prod, STRBUFLEN); - if (err < 0) - snprintf((char *)prod, sizeof(prod), "** err:(%d) %s", err, libusb_error_name(err)); - - if (level == 0) { - libusb_close(handle); - snprintf(tmp, sizeof(tmp), EOL " Manufacturer: '%s'" EOL " Product: '%s'", man, prod); - append(buf, tmp, off, len); - return; - } - - if (libusb_kernel_driver_active(handle, 0) == 1) { - snprintf(tmp, sizeof(tmp), EOL " * dev %d: kernel attached", (int)(*count)); - append(buf, tmp, off, len); - } - - err = libusb_get_active_config_descriptor(dev, &config); - if (err) { - if (!setgetdes(*count, dev, handle, &config, 1, buf, off, len) - && !setgetdes(*count, dev, handle, &config, 0, buf, off, len)) { - libusb_close(handle); - snprintf(tmp, sizeof(tmp), EOL " ** dev %d: Failed to set config descriptor to %d or %d", - (int)(*count), 1, 0); - append(buf, tmp, off, len); - return; - } - } - - snprintf(tmp, sizeof(tmp), EOL " dev %d: Active Config:" EOL "\tDescriptorType: %s" EOL - "\tNumInterfaces: %d" EOL "\tConfigurationValue: %d" EOL - "\tAttributes: %d" EOL "\tMaxPower: %d", - (int)(*count), destype(config->bDescriptorType), - (int)(config->bNumInterfaces), (int)(config->iConfiguration), - (int)(config->bmAttributes), (int)(config->MaxPower)); - append(buf, tmp, off, len); - - for (i = 0; i < (int)(config->bNumInterfaces); i++) { - for (j = 0; j < config->interface[i].num_altsetting; j++) { - idesc = &(config->interface[i].altsetting[j]); - - snprintf(tmp, sizeof(tmp), EOL " _dev %d: Interface Descriptor %d:" EOL - "\tDescriptorType: %s" EOL "\tInterfaceNumber: %d" EOL - "\tNumEndpoints: %d" EOL "\tInterfaceClass: %d" EOL - "\tInterfaceSubClass: %d" EOL "\tInterfaceProtocol: %d", - (int)(*count), j, destype(idesc->bDescriptorType), - (int)(idesc->bInterfaceNumber), - (int)(idesc->bNumEndpoints), - (int)(idesc->bInterfaceClass), - (int)(idesc->bInterfaceSubClass), - (int)(idesc->bInterfaceProtocol)); - append(buf, tmp, off, len); - - for (k = 0; k < (int)(idesc->bNumEndpoints); k++) { - epdesc = &(idesc->endpoint[k]); - - snprintf(tmp, sizeof(tmp), EOL " __dev %d: Interface %d Endpoint %d:" EOL - "\tDescriptorType: %s" EOL - "\tEndpointAddress: %s0x%x" EOL - "\tAttributes: %s" EOL "\tMaxPacketSize: %d" EOL - "\tInterval: %d" EOL "\tRefresh: %d", - (int)(*count), (int)(idesc->bInterfaceNumber), k, - destype(epdesc->bDescriptorType), - epdir(epdesc->bEndpointAddress), - (int)(epdesc->bEndpointAddress), - epatt(epdesc->bmAttributes), - epdesc->wMaxPacketSize, - (int)(epdesc->bInterval), - (int)(epdesc->bRefresh)); - append(buf, tmp, off, len); - } - } - } - - libusb_free_config_descriptor(config); - config = NULL; - - err = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, ser, STRBUFLEN); - if (err < 0) - snprintf((char *)ser, sizeof(ser), "** err:(%d) %s", err, libusb_error_name(err)); - - snprintf(tmp, sizeof(tmp), EOL " dev %d: More Info:" EOL "\tManufacturer: '%s'" EOL - "\tProduct: '%s'" EOL "\tSerial '%s'", - (int)(*count), man, prod, ser); - append(buf, tmp, off, len); - - libusb_close(handle); -} - -// Function to dump all USB devices -void usb_all(int level) -{ - libusb_device **list; - ssize_t count, i, j; - char *buf; - size_t len, off; - - count = libusb_get_device_list(NULL, &list); - if (count < 0) { - applog(LOG_ERR, "USB all: failed, err:(%d) %s", (int)count, libusb_error_name((int)count)); - return; - } - - if (count == 0) - applog(LOG_WARNING, "USB all: found no devices"); - else - { - len = 10000; - buf = malloc(len+1); - if (unlikely(!buf)) - quit(1, "USB failed to malloc buf in usb_all"); - - sprintf(buf, "USB all: found %d devices", (int)count); - off = strlen(buf); - - if (!opt_usb_list_all) - append(&buf, " - listing known devices", &off, &len); - - j = -1; - for (i = 0; i < count; i++) - usb_full(&j, list[i], &buf, &off, &len, level); - - _applog(LOG_WARNING, buf, false); - - free(buf); - - if (j == -1) - applog(LOG_WARNING, "No known USB devices"); - else - applog(LOG_WARNING, "%d %sUSB devices", - (int)(++j), opt_usb_list_all ? BLANK : "known "); - - } - - libusb_free_device_list(list, 1); -} - -static void cgusb_check_init() -{ - mutex_lock(&cgusb_lock); - - if (stats_initialised == false) { - // N.B. environment LIBUSB_DEBUG also sets libusb_set_debug() - if (opt_usbdump >= 0) { - libusb_set_debug(NULL, opt_usbdump); - usb_all(opt_usbdump); - } - stats_initialised = true; - } - - mutex_unlock(&cgusb_lock); -} - -const char *usb_cmdname(enum usb_cmds cmd) -{ - cgusb_check_init(); - - return usb_commands[cmd]; -} - -void usb_applog(struct cgpu_info *cgpu, enum usb_cmds cmd, char *msg, int amount, int err) -{ - if (msg && !*msg) - msg = NULL; - - if (!msg && amount == 0 && err == LIBUSB_SUCCESS) - msg = (char *)nodatareturned; - - applog(LOG_ERR, "%s%i: %s failed%s%s (err=%d amt=%d)", - cgpu->drv->name, cgpu->device_id, - usb_cmdname(cmd), - msg ? space : BLANK, msg ? msg : BLANK, - err, amount); -} - -static void in_use_store_ress(uint8_t bus_number, uint8_t device_address, void *resource1, void *resource2) -{ - struct usb_in_use_list *in_use_tmp; - bool found = false, empty = true; - - mutex_lock(&cgusb_lock); - in_use_tmp = in_use_head; - while (in_use_tmp) { - if (in_use_tmp->in_use.bus_number == (int)bus_number && - in_use_tmp->in_use.device_address == (int)device_address) { - found = true; - - if (in_use_tmp->in_use.resource1) - empty = false; - in_use_tmp->in_use.resource1 = resource1; - - if (in_use_tmp->in_use.resource2) - empty = false; - in_use_tmp->in_use.resource2 = resource2; - - break; - } - in_use_tmp = in_use_tmp->next; - } - mutex_unlock(&cgusb_lock); - - if (found == false) - applog(LOG_ERR, "FAIL: USB store_ress not found (%d:%d)", - (int)bus_number, (int)device_address); - - if (empty == false) - applog(LOG_ERR, "FAIL: USB store_ress not empty (%d:%d)", - (int)bus_number, (int)device_address); -} - -static void in_use_get_ress(uint8_t bus_number, uint8_t device_address, void **resource1, void **resource2) -{ - struct usb_in_use_list *in_use_tmp; - bool found = false, empty = false; - - mutex_lock(&cgusb_lock); - in_use_tmp = in_use_head; - while (in_use_tmp) { - if (in_use_tmp->in_use.bus_number == (int)bus_number && - in_use_tmp->in_use.device_address == (int)device_address) { - found = true; - - if (!in_use_tmp->in_use.resource1) - empty = true; - *resource1 = in_use_tmp->in_use.resource1; - in_use_tmp->in_use.resource1 = NULL; - - if (!in_use_tmp->in_use.resource2) - empty = true; - *resource2 = in_use_tmp->in_use.resource2; - in_use_tmp->in_use.resource2 = NULL; - - break; - } - in_use_tmp = in_use_tmp->next; - } - mutex_unlock(&cgusb_lock); - - if (found == false) - applog(LOG_ERR, "FAIL: USB get_lock not found (%d:%d)", - (int)bus_number, (int)device_address); - - if (empty == true) - applog(LOG_ERR, "FAIL: USB get_lock empty (%d:%d)", - (int)bus_number, (int)device_address); -} - -static bool __is_in_use(uint8_t bus_number, uint8_t device_address) -{ - struct usb_in_use_list *in_use_tmp; - bool ret = false; - - in_use_tmp = in_use_head; - while (in_use_tmp) { - if (in_use_tmp->in_use.bus_number == (int)bus_number && - in_use_tmp->in_use.device_address == (int)device_address) { - ret = true; - break; - } - in_use_tmp = in_use_tmp->next; - } - - return ret; -} - -static bool is_in_use_bd(uint8_t bus_number, uint8_t device_address) -{ - bool ret; - - mutex_lock(&cgusb_lock); - ret = __is_in_use(bus_number, device_address); - mutex_unlock(&cgusb_lock); - return ret; -} - -static bool is_in_use(libusb_device *dev) -{ - return is_in_use_bd(libusb_get_bus_number(dev), libusb_get_device_address(dev)); -} - -static void add_in_use(uint8_t bus_number, uint8_t device_address) -{ - struct usb_in_use_list *in_use_tmp; - bool found = false; - - mutex_lock(&cgusb_lock); - if (unlikely(__is_in_use(bus_number, device_address))) { - found = true; - goto nofway; - } - - in_use_tmp = calloc(1, sizeof(*in_use_tmp)); - if (unlikely(!in_use_tmp)) - quit(1, "USB failed to calloc in_use_tmp"); - in_use_tmp->in_use.bus_number = (int)bus_number; - in_use_tmp->in_use.device_address = (int)device_address; - in_use_tmp->next = in_use_head; - if (in_use_head) - in_use_head->prev = in_use_tmp; - in_use_head = in_use_tmp; -nofway: - mutex_unlock(&cgusb_lock); - - if (found) - applog(LOG_ERR, "FAIL: USB add already in use (%d:%d)", - (int)bus_number, (int)device_address); -} - -static void remove_in_use(uint8_t bus_number, uint8_t device_address) -{ - struct usb_in_use_list *in_use_tmp; - bool found = false; - - mutex_lock(&cgusb_lock); - - in_use_tmp = in_use_head; - while (in_use_tmp) { - if (in_use_tmp->in_use.bus_number == (int)bus_number && - in_use_tmp->in_use.device_address == (int)device_address) { - found = true; - if (in_use_tmp == in_use_head) { - in_use_head = in_use_head->next; - if (in_use_head) - in_use_head->prev = NULL; - } else { - in_use_tmp->prev->next = in_use_tmp->next; - if (in_use_tmp->next) - in_use_tmp->next->prev = in_use_tmp->prev; - } - free(in_use_tmp); - break; - } - in_use_tmp = in_use_tmp->next; - } - - mutex_unlock(&cgusb_lock); - - if (!found) - applog(LOG_ERR, "FAIL: USB remove not already in use (%d:%d)", - (int)bus_number, (int)device_address); -} - -static bool cgminer_usb_lock_bd(struct device_drv *drv, uint8_t bus_number, uint8_t device_address) -{ - struct resource_work *res_work; - bool ret; - - applog(LOG_DEBUG, "USB lock %s %d-%d", drv->dname, (int)bus_number, (int)device_address); - - res_work = calloc(1, sizeof(*res_work)); - if (unlikely(!res_work)) - quit(1, "USB failed to calloc lock res_work"); - res_work->lock = true; - res_work->dname = (const char *)(drv->dname); - res_work->bus_number = bus_number; - res_work->device_address = device_address; - - mutex_lock(&cgusbres_lock); - res_work->next = res_work_head; - res_work_head = res_work; - mutex_unlock(&cgusbres_lock); - - cgsem_post(&usb_resource_sem); - - // TODO: add a timeout fail - restart the resource thread? - while (true) { - cgsleep_ms(50); - - mutex_lock(&cgusbres_lock); - if (res_reply_head) { - struct resource_reply *res_reply_prev = NULL; - struct resource_reply *res_reply = res_reply_head; - while (res_reply) { - if (res_reply->bus_number == bus_number && - res_reply->device_address == device_address) { - - if (res_reply_prev) - res_reply_prev->next = res_reply->next; - else - res_reply_head = res_reply->next; - - mutex_unlock(&cgusbres_lock); - - ret = res_reply->got; - - free(res_reply); - - return ret; - } - res_reply_prev = res_reply; - res_reply = res_reply->next; - } - } - mutex_unlock(&cgusbres_lock); - } -} - -static bool cgminer_usb_lock(struct device_drv *drv, libusb_device *dev) -{ - return cgminer_usb_lock_bd(drv, libusb_get_bus_number(dev), libusb_get_device_address(dev)); -} - -static void cgminer_usb_unlock_bd(struct device_drv *drv, uint8_t bus_number, uint8_t device_address) -{ - struct resource_work *res_work; - - applog(LOG_DEBUG, "USB unlock %s %d-%d", drv->dname, (int)bus_number, (int)device_address); - - res_work = calloc(1, sizeof(*res_work)); - if (unlikely(!res_work)) - quit(1, "USB failed to calloc unlock res_work"); - res_work->lock = false; - res_work->dname = (const char *)(drv->dname); - res_work->bus_number = bus_number; - res_work->device_address = device_address; - - mutex_lock(&cgusbres_lock); - res_work->next = res_work_head; - res_work_head = res_work; - mutex_unlock(&cgusbres_lock); - - cgsem_post(&usb_resource_sem); - - return; -} - -static void cgminer_usb_unlock(struct device_drv *drv, libusb_device *dev) -{ - cgminer_usb_unlock_bd(drv, libusb_get_bus_number(dev), libusb_get_device_address(dev)); -} - -static struct cg_usb_device *free_cgusb(struct cg_usb_device *cgusb) -{ - applog(LOG_DEBUG, "USB free %s", cgusb->found->name); - - if (cgusb->serial_string && cgusb->serial_string != BLANK) - free(cgusb->serial_string); - - if (cgusb->manuf_string && cgusb->manuf_string != BLANK) - free(cgusb->manuf_string); - - if (cgusb->prod_string && cgusb->prod_string != BLANK) - free(cgusb->prod_string); - - if (cgusb->descriptor) - free(cgusb->descriptor); - - free(cgusb->found); - - free(cgusb); - - return NULL; -} - -static void _usb_uninit(struct cgpu_info *cgpu) -{ - int ifinfo; - - // May have happened already during a failed initialisation - // if release_cgpu() was called due to a USB NODEV(err) - if (!cgpu->usbdev) - return; - - applog(LOG_DEBUG, "USB uninit %s%i", - cgpu->drv->name, cgpu->device_id); - - if (cgpu->usbdev->handle) { - for (ifinfo = cgpu->usbdev->found->intinfo_count - 1; ifinfo >= 0; ifinfo--) { - libusb_release_interface(cgpu->usbdev->handle, - THISIF(cgpu->usbdev->found, ifinfo)); - } -#ifdef LINUX - libusb_attach_kernel_driver(cgpu->usbdev->handle, THISIF(cgpu->usbdev->found, ifinfo)); -#endif - cg_wlock(&cgusb_fd_lock); - libusb_close(cgpu->usbdev->handle); - cgpu->usbdev->handle = NULL; - cg_wunlock(&cgusb_fd_lock); - } - cgpu->usbdev = free_cgusb(cgpu->usbdev); -} - -void usb_uninit(struct cgpu_info *cgpu) -{ - int pstate; - - DEVWLOCK(cgpu, pstate); - - _usb_uninit(cgpu); - - DEVWUNLOCK(cgpu, pstate); -} - -/* We have dropped the read devlock before entering this function but we pick - * up the write lock to prevent any attempts to work on dereferenced code once - * the nodev flag has been set. */ -static void release_cgpu(struct cgpu_info *cgpu) -{ - struct cg_usb_device *cgusb = cgpu->usbdev; - struct cgpu_info *lookcgpu; - int i; - - // It has already been done - if (cgpu->usbinfo.nodev) - return; - - applog(LOG_DEBUG, "USB release %s%i", - cgpu->drv->name, cgpu->device_id); - - zombie_devs++; - total_count--; - drv_count[cgpu->drv->drv_id].count--; - - cgpu->usbinfo.nodev = true; - cgpu->usbinfo.nodev_count++; - cgtime(&cgpu->usbinfo.last_nodev); - - // Any devices sharing the same USB device should be marked also - for (i = 0; i < total_devices; i++) { - lookcgpu = get_devices(i); - if (lookcgpu != cgpu && lookcgpu->usbdev == cgusb) { - total_count--; - drv_count[lookcgpu->drv->drv_id].count--; - - lookcgpu->usbinfo.nodev = true; - lookcgpu->usbinfo.nodev_count++; - memcpy(&(lookcgpu->usbinfo.last_nodev), - &(cgpu->usbinfo.last_nodev), sizeof(struct timeval)); - lookcgpu->usbdev = NULL; - } - } - - _usb_uninit(cgpu); - cgminer_usb_unlock_bd(cgpu->drv, cgpu->usbinfo.bus_number, cgpu->usbinfo.device_address); -} - -/* - * Force a NODEV on a device so it goes back to hotplug - */ -void usb_nodev(struct cgpu_info *cgpu) -{ - int pstate; - - DEVWLOCK(cgpu, pstate); - - release_cgpu(cgpu); - - DEVWUNLOCK(cgpu, pstate); -} - -/* - * Use the same usbdev thus locking is across all related devices - */ -struct cgpu_info *usb_copy_cgpu(struct cgpu_info *orig) -{ - struct cgpu_info *copy; - int pstate; - - DEVWLOCK(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); - - copy->name = orig->name; - copy->drv = copy_drv(orig->drv); - copy->deven = orig->deven; - copy->threads = orig->threads; - - copy->usbdev = orig->usbdev; - - memcpy(&(copy->usbinfo), &(orig->usbinfo), sizeof(copy->usbinfo)); - - copy->usbinfo.nodev = (copy->usbdev == NULL); - - DEVWUNLOCK(orig, pstate); - - return copy; -} - -struct cgpu_info *usb_alloc_cgpu(struct device_drv *drv, int threads) -{ - struct cgpu_info *cgpu = calloc(1, sizeof(*cgpu)); - - if (unlikely(!cgpu)) - quit(1, "Failed to calloc cgpu for %s in usb_alloc_cgpu", drv->dname); - - cgpu->drv = drv; - cgpu->deven = DEV_ENABLED; - cgpu->threads = threads; - - cgpu->usbinfo.nodev = true; - - cglock_init(&cgpu->usbinfo.devlock); - - return cgpu; -} - -struct cgpu_info *usb_free_cgpu(struct cgpu_info *cgpu) -{ - if (cgpu->drv->copy) - free(cgpu->drv); - - free(cgpu->device_path); - - free(cgpu); - - return NULL; -} - -#define USB_INIT_FAIL 0 -#define USB_INIT_OK 1 -#define USB_INIT_IGNORE 2 - -static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found) -{ - struct cg_usb_device *cgusb = NULL; - struct libusb_config_descriptor *config = NULL; - const struct libusb_interface_descriptor *idesc; - const struct libusb_endpoint_descriptor *epdesc; - unsigned char strbuf[STRBUFLEN+1]; - char devpath[32]; - char devstr[STRBUFLEN+1]; - int err, ifinfo, epinfo, alt, epnum, pstate; - int bad = USB_INIT_FAIL; - int cfg, claimed = 0; - - DEVWLOCK(cgpu, pstate); - - cgpu->usbinfo.bus_number = libusb_get_bus_number(dev); - cgpu->usbinfo.device_address = libusb_get_device_address(dev); - - if (found->intinfo_count > 1) { - snprintf(devpath, sizeof(devpath), "%d:%d-i%d", - (int)(cgpu->usbinfo.bus_number), - (int)(cgpu->usbinfo.device_address), - THISIF(found, 0)); - } else { - snprintf(devpath, sizeof(devpath), "%d:%d", - (int)(cgpu->usbinfo.bus_number), - (int)(cgpu->usbinfo.device_address)); - } - - cgpu->device_path = strdup(devpath); - - snprintf(devstr, sizeof(devstr), "- %s device %s", found->name, devpath); - - cgusb = calloc(1, sizeof(*cgusb)); - if (unlikely(!cgusb)) - quit(1, "USB failed to calloc _usb_init cgusb"); - cgusb->found = found; - - if (found->idVendor == IDVENDOR_FTDI) - cgusb->usb_type = USB_TYPE_FTDI; - - cgusb->ident = found->ident; - - cgusb->descriptor = calloc(1, sizeof(*(cgusb->descriptor))); - if (unlikely(!cgusb->descriptor)) - quit(1, "USB failed to calloc _usb_init cgusb descriptor"); - - err = libusb_get_device_descriptor(dev, cgusb->descriptor); - if (err) { - applog(LOG_DEBUG, - "USB init failed to get descriptor, err %d %s", - err, devstr); - goto dame; - } - - cg_wlock(&cgusb_fd_lock); - err = libusb_open(dev, &(cgusb->handle)); - cg_wunlock(&cgusb_fd_lock); - if (err) { - switch (err) { - case LIBUSB_ERROR_ACCESS: - applog(LOG_ERR, - "USB init, 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, open device failed, err %d, " - "you need to install a WinUSB driver for %s", - err, devstr); - break; -#endif - default: - applog(LOG_DEBUG, - "USB init, open failed, err %d %s", - err, devstr); - } - goto dame; - } - -#ifdef LINUX - for (ifinfo = 0; ifinfo < found->intinfo_count; ifinfo++) { - if (libusb_kernel_driver_active(cgusb->handle, THISIF(found, ifinfo)) == 1) { - applog(LOG_DEBUG, "USB init, kernel attached ... %s", devstr); - err = libusb_detach_kernel_driver(cgusb->handle, THISIF(found, ifinfo)); - if (err == 0) { - applog(LOG_DEBUG, - "USB init, kernel detached ifinfo %d interface %d" - " successfully %s", - ifinfo, THISIF(found, ifinfo), devstr); - } else { - applog(LOG_WARNING, - "USB init, kernel detach ifinfo %d interface %d failed," - " err %d in use? %s", - ifinfo, THISIF(found, ifinfo), err, devstr); - goto nokernel; - } - } - } -#endif - - if (found->iManufacturer) { - unsigned char man[STRBUFLEN+1]; - - err = libusb_get_string_descriptor_ascii(cgusb->handle, - cgusb->descriptor->iManufacturer, - man, STRBUFLEN); - if (err < 0) { - applog(LOG_DEBUG, - "USB init, failed to get iManufacturer, err %d %s", - err, devstr); - goto cldame; - } - if (strcmp((char *)man, found->iManufacturer)) { - applog(LOG_DEBUG, "USB init, iManufacturer mismatch %s", - devstr); - applog(LOG_DEBUG, "Found %s vs %s", man, found->iManufacturer); - bad = USB_INIT_IGNORE; - goto cldame; - } - } - - if (found->iProduct) { - unsigned char prod[STRBUFLEN+1]; - - err = libusb_get_string_descriptor_ascii(cgusb->handle, - cgusb->descriptor->iProduct, - prod, STRBUFLEN); - if (err < 0) { - applog(LOG_DEBUG, - "USB init, failed to get iProduct, err %d %s", - err, devstr); - goto cldame; - } - if (strcmp((char *)prod, found->iProduct)) { - applog(LOG_DEBUG, "USB init, iProduct mismatch %s", - devstr); - applog(LOG_DEBUG, "Found %s vs %s", prod, found->iProduct); - bad = USB_INIT_IGNORE; - goto cldame; - } - } - - cfg = -1; - err = libusb_get_configuration(cgusb->handle, &cfg); - if (err) - cfg = -1; - - // Try to set it if we can't read it or it's different - if (cfg != found->config) { - err = libusb_set_configuration(cgusb->handle, found->config); - if (err) { - switch(err) { - case LIBUSB_ERROR_BUSY: - applog(LOG_WARNING, - "USB init, set config %d in use %s", - found->config, devstr); - break; - default: - applog(LOG_DEBUG, - "USB init, failed to set config to %d, err %d %s", - found->config, err, devstr); - } - goto cldame; - } - } - - err = libusb_get_active_config_descriptor(dev, &config); - if (err) { - applog(LOG_DEBUG, - "USB init, failed to get config descriptor, err %d %s", - err, devstr); - goto cldame; - } - - int imax = -1; - for (ifinfo = 0; ifinfo < found->intinfo_count; ifinfo++) - if (found->intinfos[ifinfo].interface > imax) - imax = found->intinfos[ifinfo].interface; - - if ((int)(config->bNumInterfaces) <= imax) { - applog(LOG_DEBUG, "USB init bNumInterfaces %d <= interface max %d for %s", - (int)(config->bNumInterfaces), imax, devstr); - goto cldame; - } - - for (ifinfo = 0; ifinfo < found->intinfo_count; ifinfo++) - for (epinfo = 0; epinfo < found->intinfos[ifinfo].epinfo_count; epinfo++) - found->intinfos[ifinfo].epinfos[epinfo].found = false; - - for (ifinfo = 0; ifinfo < found->intinfo_count; ifinfo++) { - int interface = found->intinfos[ifinfo].interface; - for (alt = 0; alt < config->interface[interface].num_altsetting; alt++) { - idesc = &(config->interface[interface].altsetting[alt]); - for (epnum = 0; epnum < (int)(idesc->bNumEndpoints); epnum++) { - struct usb_epinfo *epinfos = found->intinfos[ifinfo].epinfos; - epdesc = &(idesc->endpoint[epnum]); - for (epinfo = 0; epinfo < found->intinfos[ifinfo].epinfo_count; epinfo++) { - if (!epinfos[epinfo].found) { - if (epdesc->bmAttributes == epinfos[epinfo].att - && epdesc->wMaxPacketSize >= epinfos[epinfo].size - && epdesc->bEndpointAddress == epinfos[epinfo].ep) { - epinfos[epinfo].found = true; - epinfos[epinfo].wMaxPacketSize = epdesc->wMaxPacketSize; - break; - } - } - } - } - } - } - - for (ifinfo = 0; ifinfo < found->intinfo_count; ifinfo++) - for (epinfo = 0; epinfo < found->intinfos[ifinfo].epinfo_count; epinfo++) - if (found->intinfos[ifinfo].epinfos[epinfo].found == false) { - applog(LOG_DEBUG, "USB init found (%d,%d) == false %s", - ifinfo, epinfo, devstr); - goto cldame; - } - - claimed = 0; - for (ifinfo = 0; ifinfo < found->intinfo_count; ifinfo++) { - err = libusb_claim_interface(cgusb->handle, THISIF(found, ifinfo)); - if (err == 0) - claimed++; - else { - switch(err) { - case LIBUSB_ERROR_BUSY: - applog(LOG_WARNING, - "USB init, claim ifinfo %d interface %d in use %s", - ifinfo, THISIF(found, ifinfo), devstr); - break; - default: - applog(LOG_DEBUG, - "USB init, claim ifinfo %d interface %d failed," - " err %d %s", - ifinfo, THISIF(found, ifinfo), err, devstr); - } - goto reldame; - } - } - - cfg = -1; - err = libusb_get_configuration(cgusb->handle, &cfg); - if (err) - cfg = -1; - if (cfg != found->config) { - applog(LOG_WARNING, - "USB init, incorrect config (%d!=%d) after claim of %s", - cfg, found->config, devstr); - goto reldame; - } - - cgusb->usbver = cgusb->descriptor->bcdUSB; - -// TODO: allow this with the right version of the libusb include and running library -// cgusb->speed = libusb_get_device_speed(dev); - - err = libusb_get_string_descriptor_ascii(cgusb->handle, - cgusb->descriptor->iProduct, strbuf, STRBUFLEN); - if (err > 0) - cgusb->prod_string = strdup((char *)strbuf); - else - cgusb->prod_string = (char *)BLANK; - - err = libusb_get_string_descriptor_ascii(cgusb->handle, - cgusb->descriptor->iManufacturer, strbuf, STRBUFLEN); - if (err > 0) - cgusb->manuf_string = strdup((char *)strbuf); - else - cgusb->manuf_string = (char *)BLANK; - - err = libusb_get_string_descriptor_ascii(cgusb->handle, - cgusb->descriptor->iSerialNumber, strbuf, STRBUFLEN); - if (err > 0) - cgusb->serial_string = strdup((char *)strbuf); - else - cgusb->serial_string = (char *)BLANK; - -// TODO: ? -// cgusb->fwVersion <- for temp1/temp2 decision? or serial? (driver-modminer.c) -// cgusb->interfaceVersion - - applog(LOG_DEBUG, - "USB init %s usbver=%04x prod='%s' manuf='%s' serial='%s'", - devstr, cgusb->usbver, cgusb->prod_string, - cgusb->manuf_string, cgusb->serial_string); - - cgpu->usbdev = cgusb; - cgpu->usbinfo.nodev = false; - - libusb_free_config_descriptor(config); - - // Allow a name change based on the idVendor+idProduct - // N.B. must be done before calling add_cgpu() - if (strcmp(cgpu->drv->name, found->name)) { - if (!cgpu->drv->copy) - cgpu->drv = copy_drv(cgpu->drv); - cgpu->drv->name = (char *)(found->name); - } - - bad = USB_INIT_OK; - goto out_unlock; - -reldame: - - ifinfo = claimed; - while (ifinfo-- > 0) - libusb_release_interface(cgusb->handle, THISIF(found, ifinfo)); - -cldame: -#ifdef LINUX - libusb_attach_kernel_driver(cgusb->handle, THISIF(found, ifinfo)); - -nokernel: -#endif - cg_wlock(&cgusb_fd_lock); - libusb_close(cgusb->handle); - cgusb->handle = NULL; - cg_wunlock(&cgusb_fd_lock); - -dame: - - if (config) - libusb_free_config_descriptor(config); - - cgusb = free_cgusb(cgusb); - -out_unlock: - DEVWUNLOCK(cgpu, pstate); - - return bad; -} - -bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found_match) -{ - struct usb_find_devices *found_use = NULL; - int uninitialised_var(ret); - int i; - - for (i = 0; find_dev[i].drv != DRIVER_MAX; i++) { - if (find_dev[i].drv == found_match->drv && - find_dev[i].idVendor == found_match->idVendor && - find_dev[i].idProduct == found_match->idProduct) { - found_use = malloc(sizeof(*found_use)); - if (unlikely(!found_use)) - quit(1, "USB failed to malloc found_use"); - memcpy(found_use, &(find_dev[i]), sizeof(*found_use)); - - ret = _usb_init(cgpu, dev, found_use); - - if (ret != USB_INIT_IGNORE) - break; - } - } - - if (ret == USB_INIT_FAIL) - applog(LOG_ERR, "%s detect (%d:%d) failed to initialise (incorrect device?)", - cgpu->drv->dname, - (int)(cgpu->usbinfo.bus_number), - (int)(cgpu->usbinfo.device_address)); - - return (ret == USB_INIT_OK); -} - -static bool usb_check_device(struct device_drv *drv, struct libusb_device *dev, struct usb_find_devices *look) -{ - struct libusb_device_descriptor desc; - int bus_number, device_address; - int err, i; - bool ok; - - err = libusb_get_device_descriptor(dev, &desc); - if (err) { - applog(LOG_DEBUG, "USB check device: Failed to get descriptor, err %d", err); - return false; - } - - if (desc.idVendor != look->idVendor || desc.idProduct != look->idProduct) { - applog(LOG_DEBUG, "%s looking for %s %04x:%04x but found %04x:%04x instead", - drv->name, look->name, look->idVendor, look->idProduct, desc.idVendor, desc.idProduct); - - return false; - } - - if (busdev_count > 0) { - bus_number = (int)libusb_get_bus_number(dev); - device_address = (int)libusb_get_device_address(dev); - ok = false; - for (i = 0; i < busdev_count; i++) { - if (bus_number == busdev[i].bus_number) { - if (busdev[i].device_address == -1 || - device_address == busdev[i].device_address) { - ok = true; - break; - } - } - } - if (!ok) { - applog(LOG_DEBUG, "%s rejected %s %04x:%04x with bus:dev (%d:%d)", - drv->name, look->name, look->idVendor, look->idProduct, - bus_number, device_address); - return false; - } - } - - applog(LOG_DEBUG, "%s looking for and found %s %04x:%04x", - drv->name, look->name, look->idVendor, look->idProduct); - - return true; -} - -static struct usb_find_devices *usb_check_each(int drvnum, struct device_drv *drv, struct libusb_device *dev) -{ - struct usb_find_devices *found; - int i; - - for (i = 0; find_dev[i].drv != DRIVER_MAX; i++) - if (find_dev[i].drv == drvnum) { - if (usb_check_device(drv, dev, &(find_dev[i]))) { - found = malloc(sizeof(*found)); - if (unlikely(!found)) - quit(1, "USB failed to malloc found"); - memcpy(found, &(find_dev[i]), sizeof(*found)); - return found; - } - } - - return NULL; -} - -#define DRIVER_USB_CHECK_EACH(X) if (drv->drv_id == DRIVER_##X) \ - return usb_check_each(DRIVER_##X, drv, dev); - -static struct usb_find_devices *usb_check(__maybe_unused struct device_drv *drv, __maybe_unused struct libusb_device *dev) -{ - if (drv_count[drv->drv_id].count >= drv_count[drv->drv_id].limit) { - applog(LOG_DEBUG, - "USB scan devices3: %s limit %d reached", - drv->dname, drv_count[drv->drv_id].limit); - return NULL; - } - - DRIVER_PARSE_COMMANDS(DRIVER_USB_CHECK_EACH) - - return NULL; -} - -void usb_detect(struct device_drv *drv, bool (*device_detect)(struct libusb_device *, struct usb_find_devices *)) -{ - libusb_device **list; - ssize_t count, i; - struct usb_find_devices *found; - - applog(LOG_DEBUG, "USB scan devices: checking for %s devices", drv->name); - - if (total_count >= total_limit) { - applog(LOG_DEBUG, "USB scan devices: total limit %d reached", total_limit); - return; - } - - if (drv_count[drv->drv_id].count >= drv_count[drv->drv_id].limit) { - applog(LOG_DEBUG, - "USB scan devices: %s limit %d reached", - drv->dname, drv_count[drv->drv_id].limit); - return; - } - - count = libusb_get_device_list(NULL, &list); - if (count < 0) { - applog(LOG_DEBUG, "USB scan devices: failed, err %d", (int)count); - return; - } - - if (count == 0) - applog(LOG_DEBUG, "USB scan devices: found no devices"); - else - cgsleep_ms(166); - - for (i = 0; i < count; i++) { - if (total_count >= total_limit) { - applog(LOG_DEBUG, "USB scan devices2: total limit %d reached", total_limit); - break; - } - - if (drv_count[drv->drv_id].count >= drv_count[drv->drv_id].limit) { - applog(LOG_DEBUG, - "USB scan devices2: %s limit %d reached", - drv->dname, drv_count[drv->drv_id].limit); - break; - } - - found = usb_check(drv, list[i]); - if (found != NULL) { - if (is_in_use(list[i]) || cgminer_usb_lock(drv, list[i]) == false) - free(found); - else { - if (!device_detect(list[i], found)) - cgminer_usb_unlock(drv, list[i]); - else { - total_count++; - drv_count[drv->drv_id].count++; - } - free(found); - } - } - } - - libusb_free_device_list(list, 1); -} - -#if DO_USB_STATS -static void modes_str(char *buf, uint32_t modes) -{ - bool first; - - *buf = '\0'; - - if (modes == MODE_NONE) - strcpy(buf, MODE_NONE_STR); - else { - first = true; - - if (modes & MODE_CTRL_READ) { - strcpy(buf, MODE_CTRL_READ_STR); - first = false; - } - - if (modes & MODE_CTRL_WRITE) { - if (!first) - strcat(buf, MODE_SEP_STR); - strcat(buf, MODE_CTRL_WRITE_STR); - first = false; - } - - if (modes & MODE_BULK_READ) { - if (!first) - strcat(buf, MODE_SEP_STR); - strcat(buf, MODE_BULK_READ_STR); - first = false; - } - - if (modes & MODE_BULK_WRITE) { - if (!first) - strcat(buf, MODE_SEP_STR); - strcat(buf, MODE_BULK_WRITE_STR); - first = false; - } - } -} -#endif - -// The stat data can be spurious due to not locking it before copying it - -// however that would require the stat() function to also lock and release -// a mutex every time a usb read or write is called which would slow -// things down more -struct api_data *api_usb_stats(__maybe_unused int *count) -{ -#if DO_USB_STATS - struct cg_usb_stats_details *details; - struct cg_usb_stats *sta; - struct api_data *root = NULL; - int device; - int cmdseq; - char modes_s[32]; - - if (next_stat == USB_NOSTAT) - return NULL; - - while (*count < next_stat * C_MAX * 2) { - device = *count / (C_MAX * 2); - cmdseq = *count % (C_MAX * 2); - - (*count)++; - - sta = &(usb_stats[device]); - details = &(sta->details[cmdseq]); - - // Only show stats that have results - if (details->item[CMD_CMD].count == 0 && - details->item[CMD_TIMEOUT].count == 0 && - details->item[CMD_ERROR].count == 0) - continue; - - root = api_add_string(root, "Name", sta->name, false); - root = api_add_int(root, "ID", &(sta->device_id), false); - root = api_add_const(root, "Stat", usb_commands[cmdseq/2], false); - root = api_add_int(root, "Seq", &(details->seq), true); - modes_str(modes_s, details->modes); - root = api_add_string(root, "Modes", modes_s, true); - root = api_add_uint64(root, "Count", - &(details->item[CMD_CMD].count), true); - root = api_add_double(root, "Total Delay", - &(details->item[CMD_CMD].total_delay), true); - root = api_add_double(root, "Min Delay", - &(details->item[CMD_CMD].min_delay), true); - root = api_add_double(root, "Max Delay", - &(details->item[CMD_CMD].max_delay), true); - root = api_add_uint64(root, "Timeout Count", - &(details->item[CMD_TIMEOUT].count), true); - root = api_add_double(root, "Timeout Total Delay", - &(details->item[CMD_TIMEOUT].total_delay), true); - root = api_add_double(root, "Timeout Min Delay", - &(details->item[CMD_TIMEOUT].min_delay), true); - root = api_add_double(root, "Timeout Max Delay", - &(details->item[CMD_TIMEOUT].max_delay), true); - root = api_add_uint64(root, "Error Count", - &(details->item[CMD_ERROR].count), true); - root = api_add_double(root, "Error Total Delay", - &(details->item[CMD_ERROR].total_delay), true); - root = api_add_double(root, "Error Min Delay", - &(details->item[CMD_ERROR].min_delay), true); - root = api_add_double(root, "Error Max Delay", - &(details->item[CMD_ERROR].max_delay), true); - root = api_add_timeval(root, "First Command", - &(details->item[CMD_CMD].first), true); - root = api_add_timeval(root, "Last Command", - &(details->item[CMD_CMD].last), true); - root = api_add_timeval(root, "First Timeout", - &(details->item[CMD_TIMEOUT].first), true); - root = api_add_timeval(root, "Last Timeout", - &(details->item[CMD_TIMEOUT].last), true); - root = api_add_timeval(root, "First Error", - &(details->item[CMD_ERROR].first), true); - root = api_add_timeval(root, "Last Error", - &(details->item[CMD_ERROR].last), true); - - return root; - } -#endif - return NULL; -} - -#if DO_USB_STATS -static void newstats(struct cgpu_info *cgpu) -{ - int i; - - mutex_lock(&cgusb_lock); - - cgpu->usbinfo.usbstat = next_stat + 1; - - usb_stats = realloc(usb_stats, sizeof(*usb_stats) * (next_stat+1)); - if (unlikely(!usb_stats)) - quit(1, "USB failed to realloc usb_stats %d", next_stat+1); - - usb_stats[next_stat].name = cgpu->drv->name; - usb_stats[next_stat].device_id = -1; - usb_stats[next_stat].details = calloc(1, sizeof(struct cg_usb_stats_details) * C_MAX * 2); - if (unlikely(!usb_stats[next_stat].details)) - quit(1, "USB failed to calloc details for %d", next_stat+1); - - for (i = 1; i < C_MAX * 2; i += 2) - usb_stats[next_stat].details[i].seq = 1; - - next_stat++; - - mutex_unlock(&cgusb_lock); -} -#endif - -void update_usb_stats(__maybe_unused struct cgpu_info *cgpu) -{ -#if DO_USB_STATS - if (cgpu->usbinfo.usbstat < 1) - newstats(cgpu); - - // we don't know the device_id until after add_cgpu() - usb_stats[cgpu->usbinfo.usbstat - 1].device_id = cgpu->device_id; -#endif -} - -#if DO_USB_STATS -static void stats(struct cgpu_info *cgpu, struct timeval *tv_start, struct timeval *tv_finish, int err, int mode, enum usb_cmds cmd, int seq, int timeout) -{ - struct cg_usb_stats_details *details; - double diff; - int item, extrams; - - if (cgpu->usbinfo.usbstat < 1) - newstats(cgpu); - - cgpu->usbinfo.tmo_count++; - - // timeout checks are only done when stats are enabled - extrams = SECTOMS(tdiff(tv_finish, tv_start)) - timeout; - if (extrams >= USB_TMO_0) { - uint32_t totms = (uint32_t)(timeout + extrams); - int offset = 0; - - if (extrams >= USB_TMO_2) { - applog(LOG_ERR, "%s%i: TIMEOUT %s took %dms but was %dms", - cgpu->drv->name, cgpu->device_id, - usb_cmdname(cmd), totms, timeout) ; - offset = 2; - } else if (extrams >= USB_TMO_1) - offset = 1; - - cgpu->usbinfo.usb_tmo[offset].count++; - cgpu->usbinfo.usb_tmo[offset].total_over += extrams; - cgpu->usbinfo.usb_tmo[offset].total_tmo += timeout; - if (cgpu->usbinfo.usb_tmo[offset].min_tmo == 0) { - cgpu->usbinfo.usb_tmo[offset].min_tmo = totms; - cgpu->usbinfo.usb_tmo[offset].max_tmo = totms; - } else { - if (cgpu->usbinfo.usb_tmo[offset].min_tmo > totms) - cgpu->usbinfo.usb_tmo[offset].min_tmo = totms; - if (cgpu->usbinfo.usb_tmo[offset].max_tmo < totms) - cgpu->usbinfo.usb_tmo[offset].max_tmo = totms; - } - } - - details = &(usb_stats[cgpu->usbinfo.usbstat - 1].details[cmd * 2 + seq]); - details->modes |= mode; - - diff = tdiff(tv_finish, tv_start); - - switch (err) { - case LIBUSB_SUCCESS: - item = CMD_CMD; - break; - case LIBUSB_ERROR_TIMEOUT: - item = CMD_TIMEOUT; - break; - default: - item = CMD_ERROR; - break; - } - - if (details->item[item].count == 0) { - details->item[item].min_delay = diff; - memcpy(&(details->item[item].first), tv_start, sizeof(*tv_start)); - } else if (diff < details->item[item].min_delay) - details->item[item].min_delay = diff; - - if (diff > details->item[item].max_delay) - details->item[item].max_delay = diff; - - details->item[item].total_delay += diff; - memcpy(&(details->item[item].last), tv_start, sizeof(*tv_start)); - details->item[item].count++; -} - -static void rejected_inc(struct cgpu_info *cgpu, uint32_t mode) -{ - struct cg_usb_stats_details *details; - int item = CMD_ERROR; - - if (cgpu->usbinfo.usbstat < 1) - newstats(cgpu); - - details = &(usb_stats[cgpu->usbinfo.usbstat - 1].details[C_REJECTED * 2 + 0]); - details->modes |= mode; - details->item[item].count++; -} -#endif - -static char *find_end(unsigned char *buf, unsigned char *ptr, int ptrlen, int tot, char *end, int endlen, bool first) -{ - unsigned char *search; - - if (endlen > tot) - return NULL; - - // If end is only 1 char - do a faster search - if (endlen == 1) { - if (first) - search = buf; - else - search = ptr; - - return strchr((char *)search, *end); - } else { - if (first) - search = buf; - else { - // must allow end to have been chopped in 2 - if ((tot - ptrlen) >= (endlen - 1)) - search = ptr - (endlen - 1); - else - search = ptr - (tot - ptrlen); - } - - return strstr((char *)search, end); - } -} - -#define USB_MAX_READ 8192 -#define USB_RETRY_MAX 5 - -struct usb_transfer { - cgsem_t cgsem; - struct libusb_transfer *transfer; - bool cancellable; - struct list_head list; -}; - -bool async_usb_transfers(void) -{ - bool ret; - - cg_rlock(&cgusb_fd_lock); - ret = !list_empty(&ut_list); - cg_runlock(&cgusb_fd_lock); - - return ret; -} - -/* Cancellable transfers should only be labelled as such if it is safe for them - * to effectively mimic timing out early. This flag is usually used to signify - * a read is waiting on a non-critical response that takes a long time and the - * driver wishes it be aborted if work restart message has been sent. */ -void cancel_usb_transfers(void) -{ - struct usb_transfer *ut; - int cancellations = 0; - - cg_wlock(&cgusb_fd_lock); - list_for_each_entry(ut, &ut_list, list) { - if (ut->cancellable) { - ut->cancellable = false; - libusb_cancel_transfer(ut->transfer); - cancellations++; - } - } - cg_wunlock(&cgusb_fd_lock); - - if (cancellations) - applog(LOG_DEBUG, "Cancelled %d USB transfers", cancellations); -} - -static void init_usb_transfer(struct usb_transfer *ut) -{ - cgsem_init(&ut->cgsem); - ut->transfer = libusb_alloc_transfer(0); - if (unlikely(!ut->transfer)) - quit(1, "Failed to libusb_alloc_transfer"); - ut->transfer->user_data = ut; - ut->cancellable = false; -} - -static void complete_usb_transfer(struct usb_transfer *ut) -{ - cg_wlock(&cgusb_fd_lock); - list_del(&ut->list); - cg_wunlock(&cgusb_fd_lock); - - cgsem_destroy(&ut->cgsem); - libusb_free_transfer(ut->transfer); -} - -static void LIBUSB_CALL transfer_callback(struct libusb_transfer *transfer) -{ - struct usb_transfer *ut = transfer->user_data; - - ut->cancellable = false; - cgsem_post(&ut->cgsem); -} - -static int usb_transfer_toerr(int ret) -{ - if (ret <= 0) - return ret; - - switch (ret) { - default: - case LIBUSB_TRANSFER_COMPLETED: - ret = LIBUSB_SUCCESS; - break; - case LIBUSB_TRANSFER_ERROR: - ret = LIBUSB_ERROR_IO; - break; - case LIBUSB_TRANSFER_TIMED_OUT: - case LIBUSB_TRANSFER_CANCELLED: - ret = LIBUSB_ERROR_TIMEOUT; - break; - case LIBUSB_TRANSFER_STALL: - ret = LIBUSB_ERROR_PIPE; - break; - case LIBUSB_TRANSFER_NO_DEVICE: - ret = LIBUSB_ERROR_NO_DEVICE; - break; - case LIBUSB_TRANSFER_OVERFLOW: - ret = LIBUSB_ERROR_OVERFLOW; - break; - } - return ret; -} - -/* Wait for callback function to tell us it has finished the USB transfer, but - * use our own timer to cancel the request if we go beyond the timeout. */ -static int callback_wait(struct usb_transfer *ut, int *transferred, unsigned int timeout) -{ - struct libusb_transfer *transfer= ut->transfer; - int ret; - - ret = cgsem_mswait(&ut->cgsem, timeout); - if (ret == ETIMEDOUT) { - /* We are emulating a timeout ourself here */ - libusb_cancel_transfer(transfer); - - /* Now wait for the callback function to be invoked. */ - cgsem_wait(&ut->cgsem); - } - ret = transfer->status; - ret = usb_transfer_toerr(ret); - - /* No need to sort out mutexes here since they won't be reused */ - *transferred = transfer->actual_length; - - return ret; -} - -static int usb_submit_transfer(struct usb_transfer *ut, struct libusb_transfer *transfer, - bool cancellable) -{ - int err; - - INIT_LIST_HEAD(&ut->list); - - cg_wlock(&cgusb_fd_lock); - err = libusb_submit_transfer(transfer); - if (likely(!err)) - ut->cancellable = cancellable; - list_add(&ut->list, &ut_list); - cg_wunlock(&cgusb_fd_lock); - - return err; -} - -static int -usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo, - int epinfo, unsigned char *data, int length, - int *transferred, unsigned int timeout, - struct cgpu_info *cgpu, __maybe_unused int mode, - enum usb_cmds cmd, __maybe_unused int seq, bool cancellable) -{ - int bulk_timeout, callback_timeout = timeout; - struct usb_epinfo *usb_epinfo; - struct usb_transfer ut; - unsigned char endpoint; - int err, errn; -#if DO_USB_STATS - struct timeval tv_start, tv_finish; -#endif - unsigned char buf[512]; -#ifdef WIN32 - /* On windows the callback_timeout is a safety mechanism only. */ - bulk_timeout = timeout; - callback_timeout += WIN_CALLBACK_EXTRA; -#else - /* We give the transfer no timeout since we manage timeouts ourself on - * non windows. */ - bulk_timeout = 0; -#endif - - usb_epinfo = &(cgpu->usbdev->found->intinfos[intinfo].epinfos[epinfo]); - endpoint = usb_epinfo->ep; - - /* Avoid any async transfers during shutdown to allow the polling - * thread to be shut down after all existing transfers are complete */ - if (unlikely(cgpu->shutdown)) - return libusb_bulk_transfer(dev_handle, endpoint, data, length, transferred, timeout); - - if (length > usb_epinfo->wMaxPacketSize) - length = usb_epinfo->wMaxPacketSize; - if ((endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT) - memcpy(buf, data, length); - - USBDEBUG("USB debug: @usb_bulk_transfer(%s (nodev=%s),intinfo=%d,epinfo=%d,data=%p,length=%d,timeout=%u,mode=%d,cmd=%s,seq=%d) endpoint=%d", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), intinfo, epinfo, data, length, timeout, mode, usb_cmdname(cmd), seq, (int)endpoint); - - init_usb_transfer(&ut); - libusb_fill_bulk_transfer(ut.transfer, dev_handle, endpoint, buf, length, - transfer_callback, &ut, bulk_timeout); - STATS_TIMEVAL(&tv_start); - err = usb_submit_transfer(&ut, ut.transfer, cancellable); - errn = errno; - if (!err) - err = callback_wait(&ut, transferred, callback_timeout); - else - err = usb_transfer_toerr(err); - complete_usb_transfer(&ut); - - STATS_TIMEVAL(&tv_finish); - USB_STATS(cgpu, &tv_start, &tv_finish, err, mode, cmd, seq, timeout); - - if (err < 0) { - applog(LOG_DEBUG, "%s%i: %s (amt=%d err=%d ern=%d)", - cgpu->drv->name, cgpu->device_id, - usb_cmdname(cmd), *transferred, err, errn); - } - - if (err == LIBUSB_ERROR_PIPE) { - int retries = 0; - - do { - cgpu->usbinfo.last_pipe = time(NULL); - cgpu->usbinfo.pipe_count++; - applog(LOG_INFO, "%s%i: libusb pipe error, trying to clear", - cgpu->drv->name, cgpu->device_id); - err = libusb_clear_halt(dev_handle, endpoint); - applog(LOG_DEBUG, "%s%i: libusb pipe error%scleared", - cgpu->drv->name, cgpu->device_id, err ? " not " : " "); - - if (err) - cgpu->usbinfo.clear_fail_count++; - } while (err && ++retries < USB_RETRY_MAX); - } - if ((endpoint & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) - memcpy(data, buf, *transferred); - - return err; -} - -int _usb_read(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t bufsiz, int *processed, int timeout, const char *end, enum usb_cmds cmd, bool readonce, bool cancellable) -{ - struct cg_usb_device *usbdev; - bool ftdi; - struct timeval read_start, tv_finish; - unsigned int initial_timeout; - int bufleft, err, got, tot, pstate; - bool first = true; - bool dobuffer; - char *search; - int endlen; - unsigned char *ptr, *usbbuf = cgpu->usbinfo.bulkbuf; - const size_t usbbufread = 512; /* Always read full size */ - double done; - - DEVRLOCK(cgpu, pstate); - - if (cgpu->usbinfo.nodev) { - *buf = '\0'; - *processed = 0; - USB_REJECT(cgpu, MODE_BULK_READ); - - err = LIBUSB_ERROR_NO_DEVICE; - goto out_noerrmsg; - } - - usbdev = cgpu->usbdev; - ftdi = (usbdev->usb_type == USB_TYPE_FTDI); - - USBDEBUG("USB debug: _usb_read(%s (nodev=%s),intinfo=%d,epinfo=%d,buf=%p,bufsiz=%d,proc=%p,timeout=%u,end=%s,cmd=%s,ftdi=%s,readonce=%s)", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), intinfo, epinfo, buf, (int)bufsiz, processed, timeout, end ? (char *)str_text((char *)end) : "NULL", usb_cmdname(cmd), bool_str(ftdi), bool_str(readonce)); - - if (bufsiz > USB_MAX_READ) - quit(1, "%s USB read request %d too large (max=%d)", cgpu->drv->name, (int)bufsiz, USB_MAX_READ); - - if (timeout == DEVTIMEOUT) - timeout = usbdev->found->timeout; - - if (end == NULL) { - tot = usbdev->bufamt; - bufleft = bufsiz - tot; - if (tot) - memcpy(usbbuf, usbdev->buffer, tot); - ptr = usbbuf + tot; - usbdev->bufamt = 0; - - err = LIBUSB_SUCCESS; - initial_timeout = timeout; - cgtime(&read_start); - while (bufleft > 0) { - got = 0; - - err = usb_bulk_transfer(usbdev->handle, intinfo, epinfo, - ptr, usbbufread, &got, timeout, - cgpu, MODE_BULK_READ, cmd, first ? SEQ0 : SEQ1, - cancellable); - cgtime(&tv_finish); - ptr[got] = '\0'; - - USBDEBUG("USB debug: @_usb_read(%s (nodev=%s)) first=%s err=%d%s got=%d ptr='%s' usbbufread=%d", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), bool_str(first), err, isnodev(err), got, (char *)str_text((char *)ptr), (int)usbbufread); - - IOERR_CHECK(cgpu, err); - - if (ftdi) { - // first 2 bytes returned are an FTDI status - if (got > 2) { - got -= 2; - memmove(ptr, ptr+2, got+1); - } else { - got = 0; - *ptr = '\0'; - } - } - - tot += got; - - if (err || readonce) - break; - - ptr += got; - bufleft -= got; - - first = false; - - done = tdiff(&tv_finish, &read_start); - // N.B. this is: return last err with whatever size has already been read - timeout = initial_timeout - (done * 1000); - if (timeout <= 0) - break; - } - - // N.B. usbdev->buffer was emptied before the while() loop - if (tot > (int)bufsiz) { - usbdev->bufamt = tot - bufsiz; - memcpy(usbdev->buffer, usbbuf + bufsiz, usbdev->bufamt); - tot -= usbdev->bufamt; - usbbuf[tot] = '\0'; - applog(LOG_DEBUG, "USB: %s%i read1 buffering %d extra bytes", - cgpu->drv->name, cgpu->device_id, usbdev->bufamt); - } - - *processed = tot; - memcpy((char *)buf, (const char *)usbbuf, (tot < (int)bufsiz) ? tot + 1 : (int)bufsiz); - - goto out_unlock; - } - - tot = usbdev->bufamt; - bufleft = bufsiz - tot; - if (tot) - memcpy(usbbuf, usbdev->buffer, tot); - ptr = usbbuf + tot; - usbdev->bufamt = 0; - - endlen = strlen(end); - err = LIBUSB_SUCCESS; - initial_timeout = timeout; - cgtime(&read_start); - - while (bufleft > 0) { - got = 0; - err = usb_bulk_transfer(usbdev->handle, intinfo, epinfo, - ptr, usbbufread, &got, timeout, - cgpu, MODE_BULK_READ, cmd, first ? SEQ0 : SEQ1, - cancellable); - cgtime(&tv_finish); - ptr[got] = '\0'; - - USBDEBUG("USB debug: @_usb_read(%s (nodev=%s)) first=%s err=%d%s got=%d ptr='%s' usbbufread=%d", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), bool_str(first), err, isnodev(err), got, (char *)str_text((char *)ptr), (int)usbbufread); - - IOERR_CHECK(cgpu, err); - - if (ftdi) { - // first 2 bytes returned are an FTDI status - if (got > 2) { - got -= 2; - memmove(ptr, ptr+2, got+1); - } else { - got = 0; - *ptr = '\0'; - } - } - - tot += got; - - if (err || readonce) - break; - - if (find_end(usbbuf, ptr, got, tot, (char *)end, endlen, first)) - break; - - ptr += got; - bufleft -= got; - - first = false; - - done = tdiff(&tv_finish, &read_start); - // N.B. this is: return LIBUSB_SUCCESS with whatever size has already been read - timeout = initial_timeout - (done * 1000); - if (timeout <= 0) - break; - } - - dobuffer = false; - - if ((search = find_end(usbbuf, usbbuf, tot, tot, (char *)end, endlen, true))) { - // end finishes after bufsiz - if ((search + endlen - (char *)usbbuf) > (int)bufsiz) { - usbdev->bufamt = tot - bufsiz; - dobuffer = true; - } else { - // extra data after end - if (*(search + endlen)) { - usbdev->bufamt = tot - (search + endlen - (char *)usbbuf); - dobuffer = true; - } - } - } else { - // no end, but still bigger than bufsiz - if (tot > (int)bufsiz) { - usbdev->bufamt = tot - bufsiz; - dobuffer = true; - } - } - - if (dobuffer) { - tot -= usbdev->bufamt; - memcpy(usbdev->buffer, usbbuf + tot, usbdev->bufamt); - usbbuf[tot] = '\0'; - applog(LOG_DEBUG, "USB: %s%i read2 buffering %d extra bytes", - cgpu->drv->name, cgpu->device_id, usbdev->bufamt); - } - - *processed = tot; - memcpy((char *)buf, (const char *)usbbuf, (tot < (int)bufsiz) ? tot + 1 : (int)bufsiz); - -out_unlock: - if (err && err != LIBUSB_ERROR_TIMEOUT) { - applog(LOG_WARNING, "%s %i %s usb read err:(%d) %s", cgpu->drv->name, cgpu->device_id, usb_cmdname(cmd), - err, libusb_error_name(err)); - if (cgpu->usbinfo.continuous_ioerr_count > USB_RETRY_MAX) - err = LIBUSB_ERROR_OTHER; - } -out_noerrmsg: - if (NODEV(err)) { - cg_ruwlock(&cgpu->usbinfo.devlock); - release_cgpu(cgpu); - DEVWUNLOCK(cgpu, pstate); - } else - DEVRUNLOCK(cgpu, pstate); - - return err; -} - -int _usb_write(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t bufsiz, int *processed, int timeout, enum usb_cmds cmd) -{ - struct cg_usb_device *usbdev; - struct timeval write_start, tv_finish; - unsigned int initial_timeout; - __maybe_unused bool first = true; - int err, sent, tot, pstate; - double done; - - DEVRLOCK(cgpu, pstate); - - USBDEBUG("USB debug: _usb_write(%s (nodev=%s),intinfo=%d,epinfo=%d,buf='%s',bufsiz=%d,proc=%p,timeout=%u,cmd=%s)", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), intinfo, epinfo, (char *)str_text(buf), (int)bufsiz, processed, timeout, usb_cmdname(cmd)); - - *processed = 0; - - if (cgpu->usbinfo.nodev) { - USB_REJECT(cgpu, MODE_BULK_WRITE); - - err = LIBUSB_ERROR_NO_DEVICE; - goto out_noerrmsg; - } - - usbdev = cgpu->usbdev; - if (timeout == DEVTIMEOUT) - timeout = usbdev->found->timeout; - - tot = 0; - err = LIBUSB_SUCCESS; - initial_timeout = timeout; - cgtime(&write_start); - while (bufsiz > 0) { - int tosend = bufsiz; - - if (usbdev->usecps) { - int cpms = usbdev->cps / 1000 ? : 1; - if (tosend > cpms) - tosend = cpms; - } - err = usb_bulk_transfer(usbdev->handle, intinfo, epinfo, - (unsigned char *)buf, tosend, &sent, timeout, - cgpu, MODE_BULK_WRITE, cmd, first ? SEQ0 : SEQ1, - false); - cgtime(&tv_finish); - - USBDEBUG("USB debug: @_usb_write(%s (nodev=%s)) err=%d%s sent=%d", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), err, isnodev(err), sent); - - WRITEIOERR_CHECK(cgpu, err); - - tot += sent; - - if (err) - break; - - buf += sent; - bufsiz -= sent; - - first = false; - - done = tdiff(&tv_finish, &write_start); - // N.B. this is: return last err with whatever size was written - timeout = initial_timeout - (done * 1000); - if (timeout <= 0) - break; - } - - *processed = tot; - - if (err) { - applog(LOG_WARNING, "%s %i %s usb write err:(%d) %s", cgpu->drv->name, cgpu->device_id, usb_cmdname(cmd), - err, libusb_error_name(err)); - if (cgpu->usbinfo.continuous_ioerr_count > USB_RETRY_MAX) - err = LIBUSB_ERROR_OTHER; - } -out_noerrmsg: - if (WRITENODEV(err)) { - cg_ruwlock(&cgpu->usbinfo.devlock); - release_cgpu(cgpu); - DEVWUNLOCK(cgpu, pstate); - } else - DEVRUNLOCK(cgpu, pstate); - - return err; -} - -/* As we do for bulk reads, emulate a sync function for control transfers using - * our own timeouts that takes the same parameters as libusb_control_transfer. - */ -static int usb_control_transfer(struct cgpu_info *cgpu, libusb_device_handle *dev_handle, uint8_t bmRequestType, - uint8_t bRequest, uint16_t wValue, uint16_t wIndex, - unsigned char *buffer, uint16_t wLength, unsigned int timeout) -{ - struct usb_transfer ut; - unsigned char buf[70]; - int err, transferred; - - if (unlikely(cgpu->shutdown)) - return libusb_control_transfer(dev_handle, bmRequestType, bRequest, wValue, wIndex, buffer, wLength, timeout); - - init_usb_transfer(&ut); - libusb_fill_control_setup(buf, bmRequestType, bRequest, wValue, - wIndex, wLength); - if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT) - memcpy(buf + LIBUSB_CONTROL_SETUP_SIZE, buffer, wLength); - libusb_fill_control_transfer(ut.transfer, dev_handle, buf, transfer_callback, - &ut, 0); - err = usb_submit_transfer(&ut, ut.transfer, false); - if (!err) - err = callback_wait(&ut, &transferred, timeout); - if (err == LIBUSB_SUCCESS && transferred) { - if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) - memcpy(buffer, libusb_control_transfer_get_data(ut.transfer), - transferred); - err = transferred; - goto out; - } - err = usb_transfer_toerr(err); -out: - complete_usb_transfer(&ut); - return err; -} - -int __usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint32_t *data, int siz, unsigned int timeout, __maybe_unused enum usb_cmds cmd) -{ - struct cg_usb_device *usbdev; -#if DO_USB_STATS - struct timeval tv_start, tv_finish; -#endif - unsigned char buf[64]; - uint32_t *buf32 = (uint32_t *)buf; - int err, i, bufsiz; - - USBDEBUG("USB debug: _usb_transfer(%s (nodev=%s),type=%"PRIu8",req=%"PRIu8",value=%"PRIu16",index=%"PRIu16",siz=%d,timeout=%u,cmd=%s)", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), request_type, bRequest, wValue, wIndex, siz, timeout, usb_cmdname(cmd)); - - if (cgpu->usbinfo.nodev) { - USB_REJECT(cgpu, MODE_CTRL_WRITE); - - err = LIBUSB_ERROR_NO_DEVICE; - goto out_; - } - usbdev = cgpu->usbdev; - if (timeout == DEVTIMEOUT) - timeout = usbdev->found->timeout; - - USBDEBUG("USB debug: @_usb_transfer() data=%s", bin2hex((unsigned char *)data, (size_t)siz)); - - if (siz > 0) { - bufsiz = siz - 1; - bufsiz >>= 2; - bufsiz++; - for (i = 0; i < bufsiz; i++) - buf32[i] = htole32(data[i]); - } - - USBDEBUG("USB debug: @_usb_transfer() buf=%s", bin2hex(buf, (size_t)siz)); - - STATS_TIMEVAL(&tv_start); - err = usb_control_transfer(cgpu, usbdev->handle, request_type, bRequest, - wValue, wIndex, buf, (uint16_t)siz, timeout); - STATS_TIMEVAL(&tv_finish); - USB_STATS(cgpu, &tv_start, &tv_finish, err, MODE_CTRL_WRITE, cmd, SEQ0, timeout); - - USBDEBUG("USB debug: @_usb_transfer(%s (nodev=%s)) err=%d%s", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), err, isnodev(err)); - - WRITEIOERR_CHECK(cgpu, err); - - if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) { - applog(LOG_WARNING, "%s %i usb transfer err:(%d) %s", cgpu->drv->name, cgpu->device_id, - err, libusb_error_name(err)); - } -out_: - return err; -} - -/* We use the write devlock for control transfers since some control transfers - * are rare but may be changing settings within the device causing problems - * if concurrent transfers are happening. Using the write lock serialises - * any transfers. */ -int _usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint32_t *data, int siz, unsigned int timeout, enum usb_cmds cmd) -{ - int pstate, err; - - DEVWLOCK(cgpu, pstate); - - err = __usb_transfer(cgpu, request_type, bRequest, wValue, wIndex, data, siz, timeout, cmd); - - if (NOCONTROLDEV(err)) - release_cgpu(cgpu); - - DEVWUNLOCK(cgpu, pstate); - - return err; -} - -int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, char *buf, int bufsiz, int *amount, unsigned int timeout, __maybe_unused enum usb_cmds cmd) -{ - struct cg_usb_device *usbdev; -#if DO_USB_STATS - struct timeval tv_start, tv_finish; -#endif - unsigned char tbuf[64]; - int err, pstate; - - DEVWLOCK(cgpu, pstate); - - USBDEBUG("USB debug: _usb_transfer_read(%s (nodev=%s),type=%"PRIu8",req=%"PRIu8",value=%"PRIu16",index=%"PRIu16",bufsiz=%d,timeout=%u,cmd=%s)", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), request_type, bRequest, wValue, wIndex, bufsiz, timeout, usb_cmdname(cmd)); - - if (cgpu->usbinfo.nodev) { - USB_REJECT(cgpu, MODE_CTRL_READ); - - err = LIBUSB_ERROR_NO_DEVICE; - goto out_noerrmsg; - } - usbdev = cgpu->usbdev; - if (timeout == DEVTIMEOUT) - timeout = usbdev->found->timeout; - - *amount = 0; - - memset(tbuf, 0, 64); - STATS_TIMEVAL(&tv_start); - err = usb_control_transfer(cgpu, usbdev->handle, request_type, bRequest, - wValue, wIndex, tbuf, (uint16_t)bufsiz, timeout); - STATS_TIMEVAL(&tv_finish); - USB_STATS(cgpu, &tv_start, &tv_finish, err, MODE_CTRL_READ, cmd, SEQ0, timeout); - memcpy(buf, tbuf, bufsiz); - - USBDEBUG("USB debug: @_usb_transfer_read(%s (nodev=%s)) amt/err=%d%s%s%s", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), err, isnodev(err), err > 0 ? " = " : BLANK, err > 0 ? bin2hex((unsigned char *)buf, (size_t)err) : BLANK); - - IOERR_CHECK(cgpu, err); - - if (err > 0) { - *amount = err; - err = 0; - } - if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) { - applog(LOG_WARNING, "%s %i usb transfer read err:(%d) %s", cgpu->drv->name, cgpu->device_id, - err, libusb_error_name(err)); - } -out_noerrmsg: - if (NOCONTROLDEV(err)) - release_cgpu(cgpu); - - DEVWUNLOCK(cgpu, pstate); - - return err; -} - -#define FTDI_STATUS_B0_MASK (FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | FTDI_RS0_RLSD) -#define FTDI_RS0_CTS (1 << 4) -#define FTDI_RS0_DSR (1 << 5) -#define FTDI_RS0_RI (1 << 6) -#define FTDI_RS0_RLSD (1 << 7) - -/* Clear to send for FTDI */ -int usb_ftdi_cts(struct cgpu_info *cgpu) -{ - char buf[2], ret; - int err, amount; - - err = _usb_transfer_read(cgpu, (uint8_t)FTDI_TYPE_IN, (uint8_t)5, - (uint16_t)0, (uint16_t)0, buf, 2, - &amount, DEVTIMEOUT, C_FTDI_STATUS); - /* We return true in case drivers are waiting indefinitely to try and - * write to something that's not there. */ - if (err) - return true; - - ret = buf[0] & FTDI_STATUS_B0_MASK; - return (ret & FTDI_RS0_CTS); -} - -int _usb_ftdi_set_latency(struct cgpu_info *cgpu, int intinfo) -{ - int err = 0; - int pstate; - - DEVWLOCK(cgpu, pstate); - - if (cgpu->usbdev) { - if (cgpu->usbdev->usb_type != USB_TYPE_FTDI) { - applog(LOG_ERR, "%s: cgid %d latency request on non-FTDI device", - cgpu->drv->name, cgpu->cgminer_id); - err = LIBUSB_ERROR_NOT_SUPPORTED; - } else if (cgpu->usbdev->found->latency == LATENCY_UNUSED) { - applog(LOG_ERR, "%s: cgid %d invalid latency (UNUSED)", - cgpu->drv->name, cgpu->cgminer_id); - err = LIBUSB_ERROR_NOT_SUPPORTED; - } - - if (!err) - err = __usb_transfer(cgpu, FTDI_TYPE_OUT, FTDI_REQUEST_LATENCY, - cgpu->usbdev->found->latency, - USBIF(cgpu->usbdev, intinfo), - NULL, 0, DEVTIMEOUT, C_LATENCY); - } - - DEVWUNLOCK(cgpu, pstate); - - applog(LOG_DEBUG, "%s: cgid %d %s got err %d", - cgpu->drv->name, cgpu->cgminer_id, - usb_cmdname(C_LATENCY), err); - - return err; -} - -void usb_buffer_clear(struct cgpu_info *cgpu) -{ - int pstate; - - DEVWLOCK(cgpu, pstate); - - if (cgpu->usbdev) - cgpu->usbdev->bufamt = 0; - - DEVWUNLOCK(cgpu, pstate); -} - -uint32_t usb_buffer_size(struct cgpu_info *cgpu) -{ - uint32_t ret = 0; - int pstate; - - DEVRLOCK(cgpu, pstate); - - if (cgpu->usbdev) - ret = cgpu->usbdev->bufamt; - - DEVRUNLOCK(cgpu, pstate); - - return ret; -} - -void usb_set_cps(struct cgpu_info *cgpu, int cps) -{ - int pstate; - - DEVWLOCK(cgpu, pstate); - - if (cgpu->usbdev) - cgpu->usbdev->cps = cps; - - DEVWUNLOCK(cgpu, pstate); -} - -void usb_enable_cps(struct cgpu_info *cgpu) -{ - int pstate; - - DEVWLOCK(cgpu, pstate); - - if (cgpu->usbdev) - cgpu->usbdev->usecps = true; - - DEVWUNLOCK(cgpu, pstate); -} - -void usb_disable_cps(struct cgpu_info *cgpu) -{ - int pstate; - - DEVWLOCK(cgpu, pstate); - - if (cgpu->usbdev) - cgpu->usbdev->usecps = false; - - DEVWUNLOCK(cgpu, pstate); -} - -/* - * The value returned (0) when usbdev is NULL - * doesn't matter since it also means the next call to - * any usbutils function will fail with a nodev - * N.B. this is to get the interface number to use in a control_transfer - * which for some devices isn't actually the interface number - */ -int _usb_interface(struct cgpu_info *cgpu, int intinfo) -{ - int interface = 0; - int pstate; - - DEVRLOCK(cgpu, pstate); - - if (cgpu->usbdev) - interface = cgpu->usbdev->found->intinfos[intinfo].ctrl_transfer; - - DEVRUNLOCK(cgpu, pstate); - - return interface; -} - -enum sub_ident usb_ident(struct cgpu_info *cgpu) -{ - enum sub_ident ident = IDENT_UNK; - int pstate; - - DEVRLOCK(cgpu, pstate); - - if (cgpu->usbdev) - ident = cgpu->usbdev->ident; - - DEVRUNLOCK(cgpu, pstate); - - return ident; -} - -// Need to set all devices with matching usbdev -void usb_set_dev_start(struct cgpu_info *cgpu) -{ - struct cg_usb_device *cgusb; - struct cgpu_info *cgpu2; - struct timeval now; - int pstate; - - DEVWLOCK(cgpu, pstate); - - cgusb = cgpu->usbdev; - - // If the device wasn't dropped - if (cgusb != NULL) { - int i; - - cgtime(&now); - - for (i = 0; i < total_devices; i++) { - cgpu2 = get_devices(i); - if (cgpu2->usbdev == cgusb) - copy_time(&(cgpu2->dev_start_tv), &now); - } - } - - DEVWUNLOCK(cgpu, pstate); -} - -void usb_cleanup(void) -{ - struct cgpu_info *cgpu; - int count, pstate; - int i; - - hotplug_time = 0; - - cgsleep_ms(10); - - count = 0; - for (i = 0; i < total_devices; i++) { - cgpu = devices[i]; - switch (cgpu->drv->drv_id) { - case DRIVER_bflsc: - case DRIVER_bitforce: - case DRIVER_bitfury: - case DRIVER_modminer: - case DRIVER_icarus: - case DRIVER_avalon: - case DRIVER_klondike: - case DRIVER_hashfast: - DEVWLOCK(cgpu, pstate); - release_cgpu(cgpu); - DEVWUNLOCK(cgpu, pstate); - count++; - break; - default: - break; - } - } - - /* - * Must attempt to wait for the resource thread to release coz - * during a restart it won't automatically release them in linux - */ - if (count) { - struct timeval start, now; - - cgtime(&start); - while (42) { - cgsleep_ms(50); - - mutex_lock(&cgusbres_lock); - - if (!res_work_head) - break; - - cgtime(&now); - if (tdiff(&now, &start) > 0.366) { - applog(LOG_WARNING, - "usb_cleanup gave up waiting for resource thread"); - break; - } - - mutex_unlock(&cgusbres_lock); - } - mutex_unlock(&cgusbres_lock); - } - - cgsem_destroy(&usb_resource_sem); -} - -#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; \ - } -void usb_initialise(void) -{ - char *fre, *ptr, *comma, *colon; - int bus, dev, lim, i; - bool found; - - INIT_LIST_HEAD(&ut_list); - - for (i = 0; i < DRIVER_MAX; i++) { - drv_count[i].count = 0; - drv_count[i].limit = 999999; - } - - cgusb_check_init(); - - if (opt_usb_select && *opt_usb_select) { - // Absolute device limit - if (*opt_usb_select == ':') { - total_limit = atoi(opt_usb_select+1); - if (total_limit < 0) - quit(1, "Invalid --usb total limit"); - // Comma list of bus:dev devices to match - } else if (isdigit(*opt_usb_select)) { - fre = ptr = strdup(opt_usb_select); - do { - comma = strchr(ptr, ','); - if (comma) - *(comma++) = '\0'; - - colon = strchr(ptr, ':'); - if (!colon) - quit(1, "Invalid --usb bus:dev missing ':'"); - - *(colon++) = '\0'; - - if (!isdigit(*ptr)) - quit(1, "Invalid --usb bus:dev - bus must be a number"); - - if (!isdigit(*colon) && *colon != '*') - quit(1, "Invalid --usb bus:dev - dev must be a number or '*'"); - - bus = atoi(ptr); - if (bus <= 0) - quit(1, "Invalid --usb bus:dev - bus must be > 0"); - - if (*colon == '*') - dev = -1; - else { - dev = atoi(colon); - if (dev <= 0) - quit(1, "Invalid --usb bus:dev - dev must be > 0 or '*'"); - } - - busdev = realloc(busdev, sizeof(*busdev) * (++busdev_count)); - if (unlikely(!busdev)) - quit(1, "USB failed to realloc busdev"); - - busdev[busdev_count-1].bus_number = bus; - busdev[busdev_count-1].device_address = dev; - - ptr = comma; - } while (ptr); - free(fre); - // Comma list of DRV:limit - } else { - fre = ptr = strdup(opt_usb_select); - do { - comma = strchr(ptr, ','); - if (comma) - *(comma++) = '\0'; - - colon = strchr(ptr, ':'); - if (!colon) - quit(1, "Invalid --usb DRV:limit missing ':'"); - - *(colon++) = '\0'; - - if (!isdigit(*colon)) - quit(1, "Invalid --usb DRV:limit - limit must be a number"); - - lim = atoi(colon); - if (lim < 0) - quit(1, "Invalid --usb DRV:limit - limit must be >= 0"); - - found = false; - /* Use the DRIVER_PARSE_COMMANDS macro to iterate - * over all the drivers. */ - DRIVER_PARSE_COMMANDS(DRIVER_COUNT_FOUND) - if (!found) - quit(1, "Invalid --usb DRV:limit - unknown DRV='%s'", ptr); - - ptr = comma; - } while (ptr); - free(fre); - } - } -} - -#ifndef WIN32 -#include -#include -#include -#include -#include -#include -#include - -#ifndef __APPLE__ -union semun { - int val; - struct semid_ds *buf; - unsigned short *array; - struct seminfo *__buf; -}; -#endif - -#else -static LPSECURITY_ATTRIBUTES unsec(LPSECURITY_ATTRIBUTES sec) -{ - FreeSid(((PSECURITY_DESCRIPTOR)(sec->lpSecurityDescriptor))->Group); - free(sec->lpSecurityDescriptor); - free(sec); - return NULL; -} - -static LPSECURITY_ATTRIBUTES mksec(const char *dname, uint8_t bus_number, uint8_t device_address) -{ - SID_IDENTIFIER_AUTHORITY SIDAuthWorld = {SECURITY_WORLD_SID_AUTHORITY}; - PSID gsid = NULL; - LPSECURITY_ATTRIBUTES sec_att = NULL; - PSECURITY_DESCRIPTOR sec_des = NULL; - - sec_des = malloc(sizeof(*sec_des)); - if (unlikely(!sec_des)) - quit(1, "MTX: Failed to malloc LPSECURITY_DESCRIPTOR"); - - if (!InitializeSecurityDescriptor(sec_des, SECURITY_DESCRIPTOR_REVISION)) { - applog(LOG_ERR, - "MTX: %s (%d:%d) USB failed to init secdes err (%d)", - dname, (int)bus_number, (int)device_address, - (int)GetLastError()); - free(sec_des); - return NULL; - } - - if (!SetSecurityDescriptorDacl(sec_des, TRUE, NULL, FALSE)) { - applog(LOG_ERR, - "MTX: %s (%d:%d) USB failed to secdes dacl err (%d)", - dname, (int)bus_number, (int)device_address, - (int)GetLastError()); - free(sec_des); - return NULL; - } - - if(!AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &gsid)) { - applog(LOG_ERR, - "MTX: %s (%d:%d) USB failed to create gsid err (%d)", - dname, (int)bus_number, (int)device_address, - (int)GetLastError()); - free(sec_des); - return NULL; - } - - if (!SetSecurityDescriptorGroup(sec_des, gsid, FALSE)) { - applog(LOG_ERR, - "MTX: %s (%d:%d) USB failed to secdes grp err (%d)", - dname, (int)bus_number, (int)device_address, - (int)GetLastError()); - FreeSid(gsid); - free(sec_des); - return NULL; - } - - sec_att = malloc(sizeof(*sec_att)); - if (unlikely(!sec_att)) - quit(1, "MTX: Failed to malloc LPSECURITY_ATTRIBUTES"); - - sec_att->nLength = sizeof(*sec_att); - sec_att->lpSecurityDescriptor = sec_des; - sec_att->bInheritHandle = FALSE; - - return sec_att; -} -#endif - -// Any errors should always be printed since they will rarely if ever occur -// and thus it is best to always display them -static bool resource_lock(const char *dname, uint8_t bus_number, uint8_t device_address) -{ - applog(LOG_DEBUG, "USB res lock %s %d-%d", dname, (int)bus_number, (int)device_address); - -#ifdef WIN32 - struct cgpu_info *cgpu; - LPSECURITY_ATTRIBUTES sec; - HANDLE usbMutex; - char name[64]; - DWORD res; - int i; - - if (is_in_use_bd(bus_number, device_address)) - return false; - - snprintf(name, sizeof(name), "cg-usb-%d-%d", (int)bus_number, (int)device_address); - - sec = mksec(dname, bus_number, device_address); - if (!sec) - return false; - - usbMutex = CreateMutex(sec, FALSE, name); - if (usbMutex == NULL) { - applog(LOG_ERR, - "MTX: %s USB failed to get '%s' err (%d)", - dname, name, (int)GetLastError()); - sec = unsec(sec); - return false; - } - - res = WaitForSingleObject(usbMutex, 0); - - switch(res) { - case WAIT_OBJECT_0: - case WAIT_ABANDONED: - // Am I using it already? - for (i = 0; i < total_devices; i++) { - cgpu = get_devices(i); - if (cgpu->usbinfo.bus_number == bus_number && - cgpu->usbinfo.device_address == device_address && - cgpu->usbinfo.nodev == false) { - if (ReleaseMutex(usbMutex)) { - applog(LOG_WARNING, - "MTX: %s USB can't get '%s' - device in use", - dname, name); - goto fail; - } - applog(LOG_ERR, - "MTX: %s USB can't get '%s' - device in use - failure (%d)", - dname, name, (int)GetLastError()); - goto fail; - } - } - break; - case WAIT_TIMEOUT: - if (!hotplug_mode) - applog(LOG_WARNING, - "MTX: %s USB failed to get '%s' - device in use", - dname, name); - goto fail; - case WAIT_FAILED: - applog(LOG_ERR, - "MTX: %s USB failed to get '%s' err (%d)", - dname, name, (int)GetLastError()); - goto fail; - default: - applog(LOG_ERR, - "MTX: %s USB failed to get '%s' unknown reply (%d)", - dname, name, (int)res); - goto fail; - } - - add_in_use(bus_number, device_address); - in_use_store_ress(bus_number, device_address, (void *)usbMutex, (void *)sec); - - return true; -fail: - CloseHandle(usbMutex); - sec = unsec(sec); - return false; -#else - struct semid_ds seminfo; - union semun opt; - char name[64]; - key_t *key; - int *sem; - int fd, count; - - if (is_in_use_bd(bus_number, device_address)) - return false; - - snprintf(name, sizeof(name), "/tmp/cgminer-usb-%d-%d", (int)bus_number, (int)device_address); - fd = open(name, O_CREAT|O_RDONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); - if (fd == -1) { - applog(LOG_ERR, - "SEM: %s USB open failed '%s' err (%d) %s", - dname, name, errno, strerror(errno)); - goto _out; - } - close(fd); - - key = malloc(sizeof(*key)); - if (unlikely(!key)) - quit(1, "SEM: Failed to malloc key"); - - sem = malloc(sizeof(*sem)); - if (unlikely(!sem)) - quit(1, "SEM: Failed to malloc sem"); - - *key = ftok(name, 'K'); - *sem = semget(*key, 1, IPC_CREAT | IPC_EXCL | 438); - if (*sem < 0) { - if (errno != EEXIST) { - applog(LOG_ERR, - "SEM: %s USB failed to get '%s' err (%d) %s", - dname, name, errno, strerror(errno)); - goto free_out; - } - - *sem = semget(*key, 1, 0); - if (*sem < 0) { - applog(LOG_ERR, - "SEM: %s USB failed to access '%s' err (%d) %s", - dname, name, errno, strerror(errno)); - goto free_out; - } - - opt.buf = &seminfo; - count = 0; - while (++count) { - // Should NEVER take 100ms - if (count > 99) { - applog(LOG_ERR, - "SEM: %s USB timeout waiting for (%d) '%s'", - dname, *sem, name); - goto free_out; - } - if (semctl(*sem, 0, IPC_STAT, opt) == -1) { - applog(LOG_ERR, - "SEM: %s USB failed to wait for (%d) '%s' count %d err (%d) %s", - dname, *sem, name, count, errno, strerror(errno)); - goto free_out; - } - if (opt.buf->sem_otime != 0) - break; - cgsleep_ms(1); - } - } - - struct sembuf sops[] = { - { 0, 0, IPC_NOWAIT | SEM_UNDO }, - { 0, 1, IPC_NOWAIT | SEM_UNDO } - }; - - if (semop(*sem, sops, 2)) { - if (errno == EAGAIN) { - if (!hotplug_mode) - applog(LOG_WARNING, - "SEM: %s USB failed to get (%d) '%s' - device in use", - dname, *sem, name); - } else { - applog(LOG_DEBUG, - "SEM: %s USB failed to get (%d) '%s' err (%d) %s", - dname, *sem, name, errno, strerror(errno)); - } - goto free_out; - } - - add_in_use(bus_number, device_address); - in_use_store_ress(bus_number, device_address, (void *)key, (void *)sem); - return true; - -free_out: - free(sem); - free(key); -_out: - return false; -#endif -} - -// Any errors should always be printed since they will rarely if ever occur -// and thus it is best to always display them -static void resource_unlock(const char *dname, uint8_t bus_number, uint8_t device_address) -{ - applog(LOG_DEBUG, "USB res unlock %s %d-%d", dname, (int)bus_number, (int)device_address); - -#ifdef WIN32 - LPSECURITY_ATTRIBUTES sec = NULL; - HANDLE usbMutex = NULL; - char name[64]; - - snprintf(name, sizeof(name), "cg-usb-%d-%d", (int)bus_number, (int)device_address); - - in_use_get_ress(bus_number, device_address, (void **)(&usbMutex), (void **)(&sec)); - - if (!usbMutex || !sec) - goto fila; - - if (!ReleaseMutex(usbMutex)) - applog(LOG_ERR, - "MTX: %s USB failed to release '%s' err (%d)", - dname, name, (int)GetLastError()); - -fila: - - if (usbMutex) - CloseHandle(usbMutex); - if (sec) - unsec(sec); - remove_in_use(bus_number, device_address); - return; -#else - char name[64]; - key_t *key = NULL; - int *sem = NULL; - - snprintf(name, sizeof(name), "/tmp/cgminer-usb-%d-%d", (int)bus_number, (int)device_address); - - in_use_get_ress(bus_number, device_address, (void **)(&key), (void **)(&sem)); - - if (!key || !sem) - goto fila; - - struct sembuf sops[] = { - { 0, -1, SEM_UNDO } - }; - - // Allow a 10ms timeout - // exceeding this timeout means it would probably never succeed anyway - struct timespec timeout = { 0, 10000000 }; - - if (semtimedop(*sem, sops, 1, &timeout)) { - applog(LOG_ERR, - "SEM: %s USB failed to release '%s' err (%d) %s", - dname, name, errno, strerror(errno)); - } - - if (semctl(*sem, 0, IPC_RMID)) { - applog(LOG_WARNING, - "SEM: %s USB failed to remove SEM '%s' err (%d) %s", - dname, name, errno, strerror(errno)); - } - -fila: - - free(sem); - free(key); - remove_in_use(bus_number, device_address); - return; -#endif -} - -static void resource_process() -{ - struct resource_work *res_work = NULL; - struct resource_reply *res_reply = NULL; - bool ok; - - applog(LOG_DEBUG, "RES: %s (%d:%d) lock=%d", - res_work_head->dname, - (int)res_work_head->bus_number, - (int)res_work_head->device_address, - res_work_head->lock); - - if (res_work_head->lock) { - ok = resource_lock(res_work_head->dname, - res_work_head->bus_number, - res_work_head->device_address); - - applog(LOG_DEBUG, "RES: %s (%d:%d) lock ok=%d", - res_work_head->dname, - (int)res_work_head->bus_number, - (int)res_work_head->device_address, - ok); - - res_reply = calloc(1, sizeof(*res_reply)); - if (unlikely(!res_reply)) - quit(1, "USB failed to calloc res_reply"); - - res_reply->bus_number = res_work_head->bus_number; - res_reply->device_address = res_work_head->device_address; - res_reply->got = ok; - res_reply->next = res_reply_head; - - res_reply_head = res_reply; - } - else - resource_unlock(res_work_head->dname, - res_work_head->bus_number, - res_work_head->device_address); - - res_work = res_work_head; - res_work_head = res_work_head->next; - free(res_work); -} - -void *usb_resource_thread(void __maybe_unused *userdata) -{ - pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); - - RenameThread("usbresource"); - - applog(LOG_DEBUG, "RES: thread starting"); - - while (42) { - /* Wait to be told we have work to do */ - cgsem_wait(&usb_resource_sem); - - mutex_lock(&cgusbres_lock); - while (res_work_head) - resource_process(); - mutex_unlock(&cgusbres_lock); - } - - return NULL; -} diff --git a/usbutils.h b/usbutils.h deleted file mode 100644 index 9a22247f..00000000 --- a/usbutils.h +++ /dev/null @@ -1,486 +0,0 @@ -/* - * Copyright 2012-2013 Andrew Smith - * Copyright 2013 Con Kolivas - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. See COPYING for more details. - */ - -#ifndef USBUTILS_H -#define USBUTILS_H - -#include - -#include "util.h" - -#define EPI(x) (LIBUSB_ENDPOINT_IN | (unsigned char)(x)) -#define EPO(x) (LIBUSB_ENDPOINT_OUT | (unsigned char)(x)) - - -// For 0x0403:0x6014/0x6001 FT232H (and possibly others?) - BFL, BAS, BLT, LLT, AVA -#define FTDI_TYPE_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT) -#define FTDI_TYPE_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_IN) - -#define FTDI_REQUEST_RESET ((uint8_t)0) -#define FTDI_REQUEST_MODEM ((uint8_t)1) -#define FTDI_REQUEST_FLOW ((uint8_t)2) -#define FTDI_REQUEST_BAUD ((uint8_t)3) -#define FTDI_REQUEST_DATA ((uint8_t)4) -#define FTDI_REQUEST_LATENCY ((uint8_t)9) - -#define FTDI_VALUE_RESET 0 -#define FTDI_VALUE_PURGE_RX 1 -#define FTDI_VALUE_PURGE_TX 2 -#define FTDI_VALUE_LATENCY 1 - -// Baud -#define FTDI_VALUE_BAUD_BFL 0xc068 -#define FTDI_INDEX_BAUD_BFL 0x0200 -#define FTDI_VALUE_BAUD_BAS FTDI_VALUE_BAUD_BFL -#define FTDI_INDEX_BAUD_BAS FTDI_INDEX_BAUD_BFL -// LLT = BLT (same code) -#define FTDI_VALUE_BAUD_BLT 0x001a -#define FTDI_INDEX_BAUD_BLT 0x0000 - -// Avalon -#define FTDI_VALUE_BAUD_AVA 0x001A -#define FTDI_INDEX_BAUD_AVA 0x0000 - -#define FTDI_VALUE_DATA_AVA 8 - -// BitBurner -#define BITBURNER_REQUEST ((uint8_t)0x42) -#define BITBURNER_VALUE 0x4242 -#define BITBURNER_INDEX_SET_VOLTAGE 1 -#define BITBURNER_INDEX_GET_VOLTAGE 2 -#define BITBURNER_INDEX_GET_VERSION 4 - -// CMR = 115200 & 57600 -#define FTDI_VALUE_BAUD_CMR_115 0xc068 -#define FTDI_INDEX_BAUD_CMR_115 0x0200 - -#define FTDI_VALUE_BAUD_CMR_57 0x80d0 -#define FTDI_INDEX_BAUD_CMR_57 0x0200 - -// Data control -#define FTDI_VALUE_DATA_BFL 0 -#define FTDI_VALUE_DATA_BAS FTDI_VALUE_DATA_BFL -// LLT = BLT (same code) -#define FTDI_VALUE_DATA_BLT 8 - -#define FTDI_VALUE_FLOW 0 -#define FTDI_VALUE_MODEM 0x0303 - - -// For 0x10c4:0xea60 USB cp210x chip - AMU -#define CP210X_TYPE_OUT 0x41 - -#define CP210X_REQUEST_IFC_ENABLE 0x00 -#define CP210X_REQUEST_DATA 0x07 -#define CP210X_REQUEST_BAUD 0x1e - -#define CP210X_VALUE_UART_ENABLE 0x0001 -#define CP210X_VALUE_DATA 0x0303 -#define CP210X_DATA_BAUD 0x0001c200 - - -// For 0x067b:0x2303 Prolific PL2303 - ICA -#define PL2303_CTRL_DTR 0x01 -#define PL2303_CTRL_RTS 0x02 - -#define PL2303_CTRL_OUT 0x21 -#define PL2303_VENDOR_OUT 0x40 - -#define PL2303_REQUEST_CTRL 0x22 -#define PL2303_REQUEST_LINE 0x20 -#define PL2303_REQUEST_VENDOR 0x01 - -#define PL2303_REPLY_CTRL 0x21 - -#define PL2303_VALUE_CTRL (PL2303_CTRL_DTR | PL2303_CTRL_RTS) -#define PL2303_VALUE_LINE 0 -#define PL2303_VALUE_LINE0 0x0001c200 -#define PL2303_VALUE_LINE1 0x080000 -#define PL2303_VALUE_LINE_SIZE 7 -#define PL2303_VALUE_VENDOR 0 - -// Use the device defined timeout -#define DEVTIMEOUT 0 - -// The default intinfo structure used is the first one -#define DEFAULT_INTINFO 0 - -// For endpoints defined in usb_find_devices.intinfos.epinfos, -// the first two must be the default IN and OUT and both must always exist -#define DEFAULT_EP_IN 0 -#define DEFAULT_EP_OUT 1 - -struct usb_epinfo { - uint8_t att; - uint16_t size; - unsigned char ep; - uint16_t wMaxPacketSize; - bool found; -}; - -struct usb_intinfo { - int interface; - int ctrl_transfer; - int epinfo_count; - struct usb_epinfo *epinfos; -}; - -enum sub_ident { - IDENT_UNK = 0, - IDENT_BAJ, - IDENT_BAL, - IDENT_BAS, - IDENT_BAM, - IDENT_BFL, - IDENT_BFU, - IDENT_MMQ, - IDENT_AVA, - IDENT_BTB, - IDENT_HFA, - IDENT_BBF, - IDENT_KLN, - IDENT_ICA, - IDENT_AMU, - IDENT_BLT, - IDENT_LLT, - IDENT_CMR1, - IDENT_CMR2, - IDENT_ZTX -}; - -struct usb_find_devices { - int drv; - const char *name; - enum sub_ident ident; - uint16_t idVendor; - uint16_t idProduct; - char *iManufacturer; - char *iProduct; - int config; - unsigned int timeout; - uint16_t latency; - int intinfo_count; - struct usb_intinfo *intinfos; -}; - -/* Latency is set to 32ms to prevent a transfer ever being more than 512 bytes - * +2 bytes of status such as the ftdi chip, when the chips emulate a 115200 - * baud rate, to avoid status bytes being interleaved in larger transfers. */ -#define LATENCY_UNUSED 0 -#define LATENCY_STD 32 - -enum usb_types { - USB_TYPE_STD = 0, - USB_TYPE_FTDI -}; - -#define USB_MAX_READ 8192 - -struct cg_usb_device { - struct usb_find_devices *found; - libusb_device_handle *handle; - pthread_mutex_t *mutex; - struct libusb_device_descriptor *descriptor; - enum usb_types usb_type; - enum sub_ident ident; - uint16_t usbver; - int cps; - bool usecps; - char *prod_string; - char *manuf_string; - char *serial_string; - unsigned char fwVersion; // ?? - unsigned char interfaceVersion; // ?? - char buffer[USB_MAX_READ]; - uint32_t bufsiz; - uint32_t bufamt; -}; - -#define USB_NOSTAT 0 - -#define USB_TMO_0 50 -#define USB_TMO_1 100 -#define USB_TMO_2 500 -#define USB_TMOS 3 - -struct cg_usb_tmo { - uint32_t count; - uint32_t min_tmo; - uint32_t max_tmo; - uint64_t total_over; - uint64_t total_tmo; -}; - -struct cg_usb_info { - uint8_t bus_number; - uint8_t device_address; - int usbstat; - bool nodev; - int nodev_count; - struct timeval last_nodev; - uint32_t ioerr_count; - uint32_t continuous_ioerr_count; - - /* - * for nodev and cgusb access (read and write) - * it's a pointer so MMQ can have it in multiple devices - * - * N.B. general mining code doesn't need to use the read - * lock for 'nodev' if it calls a usb_read/write/etc function - * that uses the lock - however, all usbutils code MUST use it - * to avoid devices disappearing while in use by multiple threads - */ - cglock_t devlock; - - time_t last_pipe; - uint64_t pipe_count; - uint64_t clear_err_count; - uint64_t retry_err_count; - uint64_t clear_fail_count; - - uint64_t read_delay_count; - double total_read_delay; - uint64_t write_delay_count; - double total_write_delay; - - /* - * We add 4: 1 for null, 2 for FTDI status and 1 to round to 4 bytes - * If a single device ever has multiple end points then it will need - * multiple of these - */ - unsigned char bulkbuf[USB_MAX_READ+4]; - - uint64_t tmo_count; - struct cg_usb_tmo usb_tmo[USB_TMOS]; -}; - -#define ENUMERATION(a,b) a, -#define JUMPTABLE(a,b) b, - -#define USB_PARSE_COMMANDS(USB_ADD_COMMAND) \ - USB_ADD_COMMAND(C_REJECTED, "RejectedNoDevice") \ - USB_ADD_COMMAND(C_PING, "Ping") \ - USB_ADD_COMMAND(C_CLEAR, "Clear") \ - USB_ADD_COMMAND(C_REQUESTVERSION, "RequestVersion") \ - USB_ADD_COMMAND(C_GETVERSION, "GetVersion") \ - USB_ADD_COMMAND(C_REQUESTFPGACOUNT, "RequestFPGACount") \ - USB_ADD_COMMAND(C_GETFPGACOUNT, "GetFPGACount") \ - USB_ADD_COMMAND(C_STARTPROGRAM, "StartProgram") \ - USB_ADD_COMMAND(C_STARTPROGRAMSTATUS, "StartProgramStatus") \ - USB_ADD_COMMAND(C_PROGRAM, "Program") \ - USB_ADD_COMMAND(C_PROGRAMSTATUS, "ProgramStatus") \ - USB_ADD_COMMAND(C_PROGRAMSTATUS2, "ProgramStatus2") \ - USB_ADD_COMMAND(C_FINALPROGRAMSTATUS, "FinalProgramStatus") \ - USB_ADD_COMMAND(C_SETCLOCK, "SetClock") \ - USB_ADD_COMMAND(C_REPLYSETCLOCK, "ReplySetClock") \ - USB_ADD_COMMAND(C_REQUESTUSERCODE, "RequestUserCode") \ - USB_ADD_COMMAND(C_GETUSERCODE, "GetUserCode") \ - USB_ADD_COMMAND(C_REQUESTTEMPERATURE, "RequestTemperature") \ - USB_ADD_COMMAND(C_GETTEMPERATURE, "GetTemperature") \ - USB_ADD_COMMAND(C_SENDWORK, "SendWork") \ - USB_ADD_COMMAND(C_SENDWORKSTATUS, "SendWorkStatus") \ - USB_ADD_COMMAND(C_REQUESTWORKSTATUS, "RequestWorkStatus") \ - USB_ADD_COMMAND(C_GETWORKSTATUS, "GetWorkStatus") \ - USB_ADD_COMMAND(C_REQUESTIDENTIFY, "RequestIdentify") \ - USB_ADD_COMMAND(C_GETIDENTIFY, "GetIdentify") \ - USB_ADD_COMMAND(C_REQUESTFLASH, "RequestFlash") \ - USB_ADD_COMMAND(C_REQUESTSENDWORK, "RequestSendWork") \ - USB_ADD_COMMAND(C_REQUESTSENDWORKSTATUS, "RequestSendWorkStatus") \ - USB_ADD_COMMAND(C_RESET, "Reset") \ - USB_ADD_COMMAND(C_SETBAUD, "SetBaud") \ - USB_ADD_COMMAND(C_SETDATA, "SetDataCtrl") \ - USB_ADD_COMMAND(C_SETFLOW, "SetFlowCtrl") \ - USB_ADD_COMMAND(C_SETMODEM, "SetModemCtrl") \ - USB_ADD_COMMAND(C_PURGERX, "PurgeRx") \ - USB_ADD_COMMAND(C_PURGETX, "PurgeTx") \ - USB_ADD_COMMAND(C_FLASHREPLY, "FlashReply") \ - USB_ADD_COMMAND(C_REQUESTDETAILS, "RequestDetails") \ - USB_ADD_COMMAND(C_GETDETAILS, "GetDetails") \ - USB_ADD_COMMAND(C_REQUESTRESULTS, "RequestResults") \ - USB_ADD_COMMAND(C_GETRESULTS, "GetResults") \ - USB_ADD_COMMAND(C_REQUESTQUEJOB, "RequestQueJob") \ - USB_ADD_COMMAND(C_REQUESTQUEJOBSTATUS, "RequestQueJobStatus") \ - USB_ADD_COMMAND(C_QUEJOB, "QueJob") \ - USB_ADD_COMMAND(C_QUEJOBSTATUS, "QueJobStatus") \ - USB_ADD_COMMAND(C_QUEFLUSH, "QueFlush") \ - USB_ADD_COMMAND(C_QUEFLUSHREPLY, "QueFlushReply") \ - USB_ADD_COMMAND(C_REQUESTVOLTS, "RequestVolts") \ - USB_ADD_COMMAND(C_GETVOLTS, "GetVolts") \ - USB_ADD_COMMAND(C_SENDTESTWORK, "SendTestWork") \ - USB_ADD_COMMAND(C_LATENCY, "SetLatency") \ - USB_ADD_COMMAND(C_SETLINE, "SetLine") \ - USB_ADD_COMMAND(C_VENDOR, "Vendor") \ - USB_ADD_COMMAND(C_SETFAN, "SetFan") \ - USB_ADD_COMMAND(C_FANREPLY, "GetFan") \ - USB_ADD_COMMAND(C_AVALON_TASK, "AvalonTask") \ - USB_ADD_COMMAND(C_AVALON_READ, "AvalonRead") \ - USB_ADD_COMMAND(C_GET_AVALON_READY, "AvalonReady") \ - USB_ADD_COMMAND(C_AVALON_RESET, "AvalonReset") \ - USB_ADD_COMMAND(C_GET_AVALON_RESET, "GetAvalonReset") \ - USB_ADD_COMMAND(C_FTDI_STATUS, "FTDIStatus") \ - USB_ADD_COMMAND(C_ENABLE_UART, "EnableUART") \ - USB_ADD_COMMAND(C_BB_SET_VOLTAGE, "SetCoreVoltage") \ - USB_ADD_COMMAND(C_BB_GET_VOLTAGE, "GetCoreVoltage") \ - USB_ADD_COMMAND(C_ATMEL_RESET, "AtmelReset") \ - USB_ADD_COMMAND(C_ATMEL_OPEN, "AtmelOpen") \ - USB_ADD_COMMAND(C_ATMEL_INIT, "AtmelInit") \ - USB_ADD_COMMAND(C_ATMEL_CLOSE, "AtmelClose") \ - USB_ADD_COMMAND(C_BF1_REQINFO, "BF1RequestInfo") \ - USB_ADD_COMMAND(C_BF1_GETINFO, "BF1GetInfo") \ - USB_ADD_COMMAND(C_BF1_REQRESET, "BF1RequestReset") \ - USB_ADD_COMMAND(C_BF1_GETRESET, "BF1GetReset") \ - USB_ADD_COMMAND(C_BF1_REQWORK, "BF1RequestWork") \ - USB_ADD_COMMAND(C_BF1_GETWORK, "BF1GetWork") \ - USB_ADD_COMMAND(C_BF1_GETRES, "BF1GetResults") \ - USB_ADD_COMMAND(C_BF1_FLUSH, "BF1Flush") \ - USB_ADD_COMMAND(C_BF1_IFLUSH, "BF1InterruptFlush") \ - USB_ADD_COMMAND(C_BF1_IDENTIFY, "BF1Identify") \ - USB_ADD_COMMAND(C_HF_RESET, "HFReset") \ - USB_ADD_COMMAND(C_HF_PLL_CONFIG, "HFPLLConfig") \ - USB_ADD_COMMAND(C_HF_ADDRESS, "HFAddress") \ - USB_ADD_COMMAND(C_HF_BAUD, "HFBaud") \ - USB_ADD_COMMAND(C_HF_HASH, "HFHash") \ - USB_ADD_COMMAND(C_HF_NONCE, "HFNonce") \ - USB_ADD_COMMAND(C_HF_ABORT, "HFAbort") \ - USB_ADD_COMMAND(C_HF_STATUS, "HFStatus") \ - USB_ADD_COMMAND(C_HF_CONFIG, "HFConfig") \ - USB_ADD_COMMAND(C_HF_STATISTICS, "HFStatistics") \ - USB_ADD_COMMAND(C_HF_CLOCKGATE, "HFClockGate") \ - USB_ADD_COMMAND(C_HF_USB_INIT, "HFUSBInit") \ - USB_ADD_COMMAND(C_HF_DIE_STATUS, "HFDieStatus") \ - USB_ADD_COMMAND(C_HF_GWQ_STATUS, "HFGWQStatus") \ - USB_ADD_COMMAND(C_HF_WORK_RESTART, "HFWorkRestart") \ - USB_ADD_COMMAND(C_HF_GWQSTATS, "HFGWQStats") \ - USB_ADD_COMMAND(C_HF_GETHEADER, "HFGetHeader") \ - USB_ADD_COMMAND(C_HF_GETDATA, "HFGetData") \ - USB_ADD_COMMAND(C_HF_CLEAR_READ, "HFClearRead") - -/* Create usb_cmds enum from USB_PARSE_COMMANDS macro */ -enum usb_cmds { - USB_PARSE_COMMANDS(ENUMERATION) - C_MAX -}; - -struct device_drv; -struct cgpu_info; - -bool async_usb_transfers(void); -void cancel_usb_transfers(void); -void usb_all(int level); -const char *usb_cmdname(enum usb_cmds cmd); -void usb_applog(struct cgpu_info *cgpu, enum usb_cmds cmd, char *msg, int amount, int err); -void usb_nodev(struct cgpu_info *cgpu); -struct cgpu_info *usb_copy_cgpu(struct cgpu_info *orig); -struct cgpu_info *usb_alloc_cgpu(struct device_drv *drv, int threads); -struct cgpu_info *usb_free_cgpu(struct cgpu_info *cgpu); -void usb_uninit(struct cgpu_info *cgpu); -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); -void update_usb_stats(struct cgpu_info *cgpu); -int _usb_read(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t bufsiz, int *processed, int timeout, const char *end, enum usb_cmds cmd, bool readonce, bool cancellable); -int _usb_write(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t bufsiz, int *processed, int timeout, enum usb_cmds); -int _usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint32_t *data, int siz, unsigned int timeout, enum usb_cmds cmd); -int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, char *buf, int bufsiz, int *amount, unsigned int timeout, enum usb_cmds cmd); -int usb_ftdi_cts(struct cgpu_info *cgpu); -int _usb_ftdi_set_latency(struct cgpu_info *cgpu, int intinfo); -#define usb_ftdi_set_latency(_cgpu) _usb_ftdi_set_latency(_cgpu, DEFAULT_INTINFO) -void usb_buffer_clear(struct cgpu_info *cgpu); -uint32_t usb_buffer_size(struct cgpu_info *cgpu); -void usb_set_cps(struct cgpu_info *cgpu, int cps); -void usb_enable_cps(struct cgpu_info *cgpu); -void usb_disable_cps(struct cgpu_info *cgpu); -int _usb_interface(struct cgpu_info *cgpu, int intinfo); -#define usb_interface(_cgpu) _usb_interface(_cgpu, DEFAULT_INTINFO) -enum sub_ident usb_ident(struct cgpu_info *cgpu); -void usb_set_dev_start(struct cgpu_info *cgpu); -void usb_cleanup(); -void usb_initialise(); -void *usb_resource_thread(void *userdata); - -#define usb_read(cgpu, buf, bufsiz, read, cmd) \ - _usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false, false) - -#define usb_read_cancellable(cgpu, buf, bufsiz, read, cmd) \ - _usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false, true) - -#define usb_read_ii(cgpu, intinfo, buf, bufsiz, read, cmd) \ - _usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false, false) - -#define usb_read_once(cgpu, buf, bufsiz, read, cmd) \ - _usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, true, false) - -#define usb_read_ii_once(cgpu, intinfo, buf, bufsiz, read, cmd) \ - _usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, true, false) - -#define usb_read_once_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \ - _usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, true, false) - -#define usb_read_once_timeout_cancellable(cgpu, buf, bufsiz, read, timeout, cmd) \ - _usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, true, true) - -#define usb_read_ii_once_timeout(cgpu, intinfo, buf, bufsiz, read, timeout, cmd) \ - _usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, true, false) - -#define usb_read_nl(cgpu, buf, bufsiz, read, cmd) \ - _usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, "\n", cmd, false, false) - -#define usb_read_nl_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \ - _usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, "\n", cmd, false, false) - -#define usb_read_ok(cgpu, buf, bufsiz, read, cmd) \ - _usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, "OK\n", cmd, false, false) - -#define usb_read_ok_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \ - _usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, "OK\n", cmd, false, false) - -#define usb_read_ep(cgpu, ep, buf, bufsiz, read, cmd) \ - _usb_read(cgpu, DEFAULT_INTINFO, ep, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false, false) - -#define usb_read_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \ - _usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, false, false) - -#define usb_read_timeout_cancellable(cgpu, buf, bufsiz, read, timeout, cmd) \ - _usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, false, true) - -#define usb_read_ii_timeout(cgpu, intinfo, buf, bufsiz, read, timeout, cmd) \ - _usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, false, false) - -#define usb_read_ii_timeout_cancellable(cgpu, intinfo, buf, bufsiz, read, timeout, cmd) \ - _usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, false, true) - -#define usb_read_ep_timeout(cgpu, ep, buf, bufsiz, read, timeout, cmd) \ - _usb_read(cgpu, DEFAULT_INTINFO, ep, buf, bufsiz, read, timeout, NULL, cmd, false, false) - -#define usb_write(cgpu, buf, bufsiz, wrote, cmd) \ - _usb_write(cgpu, DEFAULT_INTINFO, DEFAULT_EP_OUT, buf, bufsiz, wrote, DEVTIMEOUT, cmd) - -#define usb_write_ii(cgpu, intinfo, buf, bufsiz, wrote, cmd) \ - _usb_write(cgpu, intinfo, DEFAULT_EP_OUT, buf, bufsiz, wrote, DEVTIMEOUT, cmd) - -#define usb_write_ep(cgpu, ep, buf, bufsiz, wrote, cmd) \ - _usb_write(cgpu, DEFAULT_INTINFO, ep, buf, bufsiz, wrote, DEVTIMEOUT, cmd) - -#define usb_write_timeout(cgpu, buf, bufsiz, wrote, timeout, cmd) \ - _usb_write(cgpu, DEFAULT_INTINFO, DEFAULT_EP_OUT, buf, bufsiz, wrote, timeout, cmd) - -#define usb_write_ep_timeout(cgpu, ep, buf, bufsiz, wrote, timeout, cmd) \ - _usb_write(cgpu, DEFAULT_INTINFO, ep, buf, bufsiz, wrote, timeout, cmd) - -#define usb_transfer(cgpu, typ, req, val, idx, cmd) \ - _usb_transfer(cgpu, typ, req, val, idx, NULL, 0, DEVTIMEOUT, cmd) - -#define usb_transfer_data(cgpu, typ, req, val, idx, data, len, cmd) \ - _usb_transfer(cgpu, typ, req, val, idx, data, len, DEVTIMEOUT, cmd) - -#define usb_transfer_read(cgpu, typ, req, val, idx, buf, bufsiz, read, cmd) \ - _usb_transfer_read(cgpu, typ, req, val, idx, buf, bufsiz, read, DEVTIMEOUT, cmd) - -#endif