diff --git a/api-example.c b/api-example.c index 71b5b002..d14b6aab 100644 --- a/api-example.c +++ b/api-example.c @@ -8,7 +8,7 @@ */ /* Compile: - * gcc api-example.c -I compat/jansson -o cgminer-api + * gcc api-example.c -Icompat/jansson -Icompat/libusb-1.0/libusb -o cgminer-api */ #include "config.h" @@ -32,7 +32,6 @@ #include #include - #define SOCKETTYPE int #define SOCKETFAIL(a) ((a) < 0) #define INVSOCK -1 #define CLOSESOCKET close @@ -140,8 +139,6 @@ #endif #endif -#define RECVSIZE 65500 - static const char SEPARATOR = '|'; static const char COMMA = ','; static const char EQ = '='; diff --git a/api.c b/api.c index af575626..006e8f92 100644 --- a/api.c +++ b/api.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "compat.h" diff --git a/cgminer.c b/cgminer.c index e76a683f..ac7b07ac 100644 --- a/cgminer.c +++ b/cgminer.c @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef USE_USBUTILS #include @@ -42,7 +43,11 @@ #endif #include #include +#ifdef HAVE_LIBCURL #include +#else +char *curly = ":D"; +#endif #include #include @@ -1632,6 +1637,7 @@ static struct opt_table opt_cmdline_table[] = { OPT_ENDTABLE }; +#ifdef HAVE_LIBCURL static bool jobj_binary(const json_t *obj, const char *key, void *buf, size_t buflen, bool required) { @@ -1654,6 +1660,7 @@ static bool jobj_binary(const json_t *obj, const char *key, return true; } +#endif static void calc_midstate(struct work *work) { @@ -1702,7 +1709,10 @@ void free_work(struct work *work) } static void gen_hash(unsigned char *data, unsigned char *hash, int len); +static void calc_diff(struct work *work, int known); +char *workpadding = "000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000"; +#ifdef HAVE_LIBCURL /* Process transactions with GBT by storing the binary value of the first * transaction, and the hashes of the remaining transactions since these * remain constant with an altered coinbase when generating work. Must be @@ -1783,7 +1793,6 @@ static unsigned char *__gbt_merkleroot(struct pool *pool) return merkle_hash; } -static void calc_diff(struct work *work, int known); static bool work_decode(struct pool *pool, struct work *work, json_t *val); static void update_gbt(struct pool *pool) @@ -1822,8 +1831,6 @@ static void update_gbt(struct pool *pool) curl_easy_cleanup(curl); } -char *workpadding = "000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000"; - static void gen_gbt_work(struct pool *pool, struct work *work) { unsigned char *merkleroot; @@ -2030,6 +2037,13 @@ static bool work_decode(struct pool *pool, struct work *work, json_t *val) out: return ret; } +#else /* HAVE_LIBCURL */ +/* Always true with stratum */ +#define pool_localgen(pool) (true) +#define json_rpc_call(curl, url, userpass, rpc_req, probe, longpoll, rolltime, pool, share) (NULL) +#define work_decode(pool, work, val) (false) +#define gen_gbt_work(pool, work) {} +#endif /* HAVE_LIBCURL */ int dev_from_id(int thr_id) { @@ -2197,18 +2211,6 @@ static void get_statline(char *buf, size_t bufsiz, struct cgpu_info *cgpu) cgpu->drv->get_statline(buf, bufsiz, cgpu); } -static void text_print_status(int thr_id) -{ - struct cgpu_info *cgpu; - char logline[256]; - - cgpu = get_thr_cgpu(thr_id); - if (cgpu) { - get_statline(logline, sizeof(logline), cgpu); - printf("%s\n", logline); - } -} - #ifdef HAVE_CURSES #define CURBUFSIZ 256 #define cg_mvwprintw(win, y, x, fmt, ...) do { \ @@ -2348,12 +2350,6 @@ static void curses_print_devstatus(struct cgpu_info *cgpu, int count) } #endif -static void print_status(int thr_id) -{ - if (!curses_active) - text_print_status(thr_id); -} - #ifdef HAVE_CURSES /* Check for window resize. Called with curses mutex locked */ static inline void change_logwinsize(void) @@ -2645,6 +2641,25 @@ share_result(json_t *val, json_t *res, json_t *err, const struct work *work, } } +#ifdef HAVE_LIBCURL +static void text_print_status(int thr_id) +{ + struct cgpu_info *cgpu; + char logline[256]; + + cgpu = get_thr_cgpu(thr_id); + if (cgpu) { + get_statline(logline, sizeof(logline), cgpu); + printf("%s\n", logline); + } +} + +static void print_status(int thr_id) +{ + if (!curses_active) + text_print_status(thr_id); +} + static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit) { char *hexstr = NULL; @@ -2829,6 +2844,62 @@ out: return rc; } +static bool get_upstream_work(struct work *work, CURL *curl) +{ + struct pool *pool = work->pool; + struct cgminer_pool_stats *pool_stats = &(pool->cgminer_pool_stats); + struct timeval tv_elapsed; + json_t *val = NULL; + bool rc = false; + char *url; + + applog(LOG_DEBUG, "DBG: sending %s get RPC call: %s", pool->rpc_url, pool->rpc_req); + + url = pool->rpc_url; + + cgtime(&work->tv_getwork); + + val = json_rpc_call(curl, url, pool->rpc_userpass, pool->rpc_req, false, + false, &work->rolltime, pool, false); + pool_stats->getwork_attempts++; + + if (likely(val)) { + rc = work_decode(pool, work, val); + if (unlikely(!rc)) + applog(LOG_DEBUG, "Failed to decode work in get_upstream_work"); + } else + applog(LOG_DEBUG, "Failed json_rpc_call in get_upstream_work"); + + cgtime(&work->tv_getwork_reply); + timersub(&(work->tv_getwork_reply), &(work->tv_getwork), &tv_elapsed); + pool_stats->getwork_wait_rolling += ((double)tv_elapsed.tv_sec + ((double)tv_elapsed.tv_usec / 1000000)) * 0.63; + pool_stats->getwork_wait_rolling /= 1.63; + + timeradd(&tv_elapsed, &(pool_stats->getwork_wait), &(pool_stats->getwork_wait)); + if (timercmp(&tv_elapsed, &(pool_stats->getwork_wait_max), >)) { + pool_stats->getwork_wait_max.tv_sec = tv_elapsed.tv_sec; + pool_stats->getwork_wait_max.tv_usec = tv_elapsed.tv_usec; + } + if (timercmp(&tv_elapsed, &(pool_stats->getwork_wait_min), <)) { + pool_stats->getwork_wait_min.tv_sec = tv_elapsed.tv_sec; + pool_stats->getwork_wait_min.tv_usec = tv_elapsed.tv_usec; + } + pool_stats->getwork_calls++; + + work->pool = pool; + work->longpoll = false; + work->getwork_mode = GETWORK_MODE_POOL; + calc_diff(work, 0); + total_getworks++; + pool->getwork_requested++; + + if (likely(val)) + json_decref(val); + + return rc; +} +#endif /* HAVE_LIBCURL */ + /* Specifies whether we can use this pool for work or not. */ static bool pool_unworkable(struct pool *pool) { @@ -3017,61 +3088,6 @@ static void get_benchmark_work(struct work *work) calc_diff(work, 0); } -static bool get_upstream_work(struct work *work, CURL *curl) -{ - struct pool *pool = work->pool; - struct cgminer_pool_stats *pool_stats = &(pool->cgminer_pool_stats); - struct timeval tv_elapsed; - json_t *val = NULL; - bool rc = false; - char *url; - - applog(LOG_DEBUG, "DBG: sending %s get RPC call: %s", pool->rpc_url, pool->rpc_req); - - url = pool->rpc_url; - - cgtime(&work->tv_getwork); - - val = json_rpc_call(curl, url, pool->rpc_userpass, pool->rpc_req, false, - false, &work->rolltime, pool, false); - pool_stats->getwork_attempts++; - - if (likely(val)) { - rc = work_decode(pool, work, val); - if (unlikely(!rc)) - applog(LOG_DEBUG, "Failed to decode work in get_upstream_work"); - } else - applog(LOG_DEBUG, "Failed json_rpc_call in get_upstream_work"); - - cgtime(&work->tv_getwork_reply); - timersub(&(work->tv_getwork_reply), &(work->tv_getwork), &tv_elapsed); - pool_stats->getwork_wait_rolling += ((double)tv_elapsed.tv_sec + ((double)tv_elapsed.tv_usec / 1000000)) * 0.63; - pool_stats->getwork_wait_rolling /= 1.63; - - timeradd(&tv_elapsed, &(pool_stats->getwork_wait), &(pool_stats->getwork_wait)); - if (timercmp(&tv_elapsed, &(pool_stats->getwork_wait_max), >)) { - pool_stats->getwork_wait_max.tv_sec = tv_elapsed.tv_sec; - pool_stats->getwork_wait_max.tv_usec = tv_elapsed.tv_usec; - } - if (timercmp(&tv_elapsed, &(pool_stats->getwork_wait_min), <)) { - pool_stats->getwork_wait_min.tv_sec = tv_elapsed.tv_sec; - pool_stats->getwork_wait_min.tv_usec = tv_elapsed.tv_usec; - } - pool_stats->getwork_calls++; - - work->pool = pool; - work->longpoll = false; - work->getwork_mode = GETWORK_MODE_POOL; - calc_diff(work, 0); - total_getworks++; - pool->getwork_requested++; - - if (likely(val)) - json_decref(val); - - return rc; -} - #ifdef HAVE_CURSES static void disable_curses_windows(void) { @@ -3239,6 +3255,7 @@ static void sighandler(int __maybe_unused sig) kill_work(); } +#ifdef HAVE_LIBCURL /* Called with pool_lock held. Recruit an extra curl if none are available for * this pool. */ static void recruit_curl(struct pool *pool) @@ -3320,7 +3337,7 @@ static inline bool should_roll(struct work *work) cgtime(&now); if (now.tv_sec - work->tv_staged.tv_sec > expiry) return false; - + return true; } @@ -3351,36 +3368,47 @@ static void roll_work(struct work *work) work->id = total_work++; } -/* Duplicates any dynamically allocated arrays within the work struct to - * prevent a copied work struct from freeing ram belonging to another struct */ -void __copy_work(struct work *work, struct work *base_work) +static void *submit_work_thread(void *userdata) { - int id = work->id; + struct work *work = (struct work *)userdata; + struct pool *pool = work->pool; + bool resubmit = false; + struct curl_ent *ce; - clean_work(work); - memcpy(work, base_work, sizeof(struct work)); - /* Keep the unique new id assigned during make_work to prevent copied - * work from having the same id. */ - work->id = id; - if (base_work->job_id) - work->job_id = strdup(base_work->job_id); - if (base_work->nonce1) - work->nonce1 = strdup(base_work->nonce1); - if (base_work->ntime) - work->ntime = strdup(base_work->ntime); - if (base_work->coinbase) - work->coinbase = strdup(base_work->coinbase); -} + pthread_detach(pthread_self()); -/* Generates a copy of an existing work struct, creating fresh heap allocations - * for all dynamically allocated arrays within the struct */ -struct work *copy_work(struct work *base_work) -{ - struct work *work = make_work(); + RenameThread("submit_work"); - __copy_work(work, base_work); + applog(LOG_DEBUG, "Creating extra submit work thread"); - return work; + ce = pop_curl_entry(pool); + /* submit solution to bitcoin via JSON-RPC */ + while (!submit_upstream_work(work, ce->curl, resubmit)) { + if (opt_lowmem) { + applog(LOG_NOTICE, "Pool %d share being discarded to minimise memory cache", pool->pool_no); + break; + } + resubmit = true; + if (stale_work(work, true)) { + applog(LOG_NOTICE, "Pool %d share became stale while retrying submit, discarding", pool->pool_no); + + mutex_lock(&stats_lock); + total_stale++; + pool->stale_shares++; + total_diff_stale += work->work_difficulty; + pool->diff_stale += work->work_difficulty; + mutex_unlock(&stats_lock); + + free_work(work); + break; + } + + /* pause, then restart work-request loop */ + applog(LOG_INFO, "json_rpc_call failed on submit_work, retrying"); + } + push_curl_entry(ce, pool); + + return NULL; } static struct work *make_clone(struct work *work) @@ -3429,6 +3457,81 @@ out_unlock: return cloned; } +/* Clones work by rolling it if possible, and returning a clone instead of the + * original work item which gets staged again to possibly be rolled again in + * the future */ +static struct work *clone_work(struct work *work) +{ + int mrs = mining_threads + opt_queue - total_staged(); + struct work *work_clone; + bool cloned; + + if (mrs < 1) + return work; + + cloned = false; + work_clone = make_clone(work); + while (mrs-- > 0 && can_roll(work) && should_roll(work)) { + applog(LOG_DEBUG, "Pushing rolled converted work to stage thread"); + stage_work(work_clone); + roll_work(work); + work_clone = make_clone(work); + /* Roll it again to prevent duplicates should this be used + * directly later on */ + roll_work(work); + cloned = true; + } + + if (cloned) { + stage_work(work); + return work_clone; + } + + free_work(work_clone); + + return work; +} + +#else /* HAVE_LIBCURL */ +static void *submit_work_thread(void __maybe_unused *userdata) +{ + pthread_detach(pthread_self()); + return NULL; +} +#endif /* HAVE_LIBCURL */ + +/* Duplicates any dynamically allocated arrays within the work struct to + * prevent a copied work struct from freeing ram belonging to another struct */ +void __copy_work(struct work *work, struct work *base_work) +{ + int id = work->id; + + clean_work(work); + memcpy(work, base_work, sizeof(struct work)); + /* Keep the unique new id assigned during make_work to prevent copied + * work from having the same id. */ + work->id = id; + if (base_work->job_id) + work->job_id = strdup(base_work->job_id); + if (base_work->nonce1) + work->nonce1 = strdup(base_work->nonce1); + if (base_work->ntime) + work->ntime = strdup(base_work->ntime); + if (base_work->coinbase) + work->coinbase = strdup(base_work->coinbase); +} + +/* Generates a copy of an existing work struct, creating fresh heap allocations + * for all dynamically allocated arrays within the struct */ +struct work *copy_work(struct work *base_work) +{ + struct work *work = make_work(); + + __copy_work(work, base_work); + + return work; +} + static void pool_died(struct pool *pool) { if (!pool_tset(pool, &pool->idle)) { @@ -3572,49 +3675,6 @@ static void rebuild_hash(struct work *work) static bool cnx_needed(struct pool *pool); -static void *submit_work_thread(void *userdata) -{ - struct work *work = (struct work *)userdata; - struct pool *pool = work->pool; - bool resubmit = false; - struct curl_ent *ce; - - pthread_detach(pthread_self()); - - RenameThread("submit_work"); - - applog(LOG_DEBUG, "Creating extra submit work thread"); - - ce = pop_curl_entry(pool); - /* submit solution to bitcoin via JSON-RPC */ - while (!submit_upstream_work(work, ce->curl, resubmit)) { - if (opt_lowmem) { - applog(LOG_NOTICE, "Pool %d share being discarded to minimise memory cache", pool->pool_no); - break; - } - resubmit = true; - if (stale_work(work, true)) { - applog(LOG_NOTICE, "Pool %d share became stale while retrying submit, discarding", pool->pool_no); - - mutex_lock(&stats_lock); - total_stale++; - pool->stale_shares++; - total_diff_stale += work->work_difficulty; - pool->diff_stale += work->work_difficulty; - mutex_unlock(&stats_lock); - - free_work(work); - break; - } - - /* pause, then restart work-request loop */ - applog(LOG_INFO, "json_rpc_call failed on submit_work, retrying"); - } - push_curl_entry(ce, pool); - - return NULL; -} - /* Find the pool that currently has the highest priority */ static struct pool *priority_pool(int choice) { @@ -5761,41 +5821,6 @@ static struct work *hash_pop(void) return work; } -/* Clones work by rolling it if possible, and returning a clone instead of the - * original work item which gets staged again to possibly be rolled again in - * the future */ -static struct work *clone_work(struct work *work) -{ - int mrs = mining_threads + opt_queue - total_staged(); - struct work *work_clone; - bool cloned; - - if (mrs < 1) - return work; - - cloned = false; - work_clone = make_clone(work); - while (mrs-- > 0 && can_roll(work) && should_roll(work)) { - applog(LOG_DEBUG, "Pushing rolled converted work to stage thread"); - stage_work(work_clone); - roll_work(work); - work_clone = make_clone(work); - /* Roll it again to prevent duplicates should this be used - * directly later on */ - roll_work(work); - cloned = true; - } - - if (cloned) { - stage_work(work); - return work_clone; - } - - free_work(work_clone); - - return work; -} - static void gen_hash(unsigned char *data, unsigned char *hash, int len) { unsigned char hash1[32]; @@ -6468,6 +6493,7 @@ enum { FAILURE_INTERVAL = 30, }; +#ifdef HAVE_LIBCURL /* Stage another work item from the work returned in a longpoll */ static void convert_to_work(json_t *val, int rolltime, struct pool *pool, struct timeval *tv_lp, struct timeval *tv_lp_reply) { @@ -6538,6 +6564,7 @@ static struct pool *select_longpoll_pool(struct pool *cp) } return NULL; } +#endif /* HAVE_LIBCURL */ /* This will make the longpoll thread wait till it's the current pool, or it * has been flagged as rejecting, before attempting to open any connections. @@ -6553,6 +6580,7 @@ static void wait_lpcurrent(struct pool *pool) } } +#ifdef HAVE_LIBCURL static void *longpoll_thread(void *userdata) { struct pool *cp = (struct pool *)userdata; @@ -6680,6 +6708,13 @@ out: return NULL; } +#else /* HAVE_LIBCURL */ +static void *longpoll_thread(void __maybe_unused *userdata) +{ + pthread_detach(pthread_self()); + return NULL; +} +#endif /* HAVE_LIBCURL */ void reinit_device(struct cgpu_info *cgpu) { @@ -8160,7 +8195,6 @@ begin_bench: int ts, max_staged = opt_queue; struct pool *pool, *cp; bool lagging = false; - struct curl_ent *ce; struct work *work; cp = current_pool(); @@ -8211,6 +8245,16 @@ retry: continue; } + if (opt_benchmark) { + get_benchmark_work(work); + applog(LOG_DEBUG, "Generated benchmark work"); + stage_work(work); + continue; + } + +#ifdef HAVE_LIBCURL + struct curl_ent *ce; + if (pool->has_gbt) { while (pool->idle) { struct pool *altpool = select_pool(true); @@ -8233,13 +8277,6 @@ retry: continue; } - if (opt_benchmark) { - get_benchmark_work(work); - applog(LOG_DEBUG, "Generated benchmark work"); - stage_work(work); - continue; - } - work->pool = pool; ce = pop_curl_entry(pool); /* obtain new work from bitcoin via JSON-RPC */ @@ -8262,6 +8299,7 @@ retry: applog(LOG_DEBUG, "Generated getwork work"); stage_work(work); push_curl_entry(ce, pool); +#endif } return 0; diff --git a/compat/.gitignore b/compat/.gitignore new file mode 100644 index 00000000..8e687f87 --- /dev/null +++ b/compat/.gitignore @@ -0,0 +1,3 @@ +libusb-1.0/libusb/libusb-1.0.la +libusb-1.0/libusb/*.lo +libusb-1.0/libusb/os/*.lo diff --git a/configure.ac b/configure.ac index 0e05cdfa..0392ab3e 100644 --- a/configure.ac +++ b/configure.ac @@ -365,15 +365,26 @@ fi AC_SUBST(LIBUSB_LIBS) AC_SUBST(LIBUSB_CFLAGS) -if test "x$have_win32" != xtrue; then - PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.25.0], [AC_DEFINE([CURL_HAS_KEEPALIVE], [1], [Defined if version of curl supports keepalive.])], - [PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.18.2], ,[AC_MSG_ERROR([Missing required libcurl dev >= 7.18.2])])]) +AC_ARG_ENABLE([libcurl], + [AC_HELP_STRING([--disable-libcurl],[Disable building with libcurl for getwork and GBT support])], + [libcurl=$enableval] + ) + +if test "x$libcurl" != xno; then + if test "x$have_win32" != xtrue; then + PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.25.0], [AC_DEFINE([CURL_HAS_KEEPALIVE], [1], [Defined if version of curl supports keepalive.])], + [PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.18.2], ,[AC_MSG_ERROR([Missing required libcurl dev >= 7.18.2])])]) + else + PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.25.0], ,[AC_MSG_ERROR([Missing required libcurl dev >= 7.25.0])]) + AC_DEFINE([CURL_HAS_KEEPALIVE], [1]) + fi + AC_DEFINE([HAVE_LIBCURL], [1], [Defined to 1 if libcurl support built in]) else - PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.25.0], ,[AC_MSG_ERROR([Missing required libcurl dev >= 7.25.0])]) - AC_DEFINE([CURL_HAS_KEEPALIVE], [1]) + LIBCURL_LIBS="" fi AC_SUBST(LIBCURL_LIBS) + #check execv signature AC_COMPILE_IFELSE([AC_LANG_SOURCE([ #include @@ -462,8 +473,15 @@ echo echo "Configuration Options Summary:" echo +if test "x$libcurl" != xno; then + echo " libcurl(GBT+getwork).: Enabled: $LIBCURL_LIBS" +else + echo " libcurl(GBT+getwork).: Disabled" +fi + echo " curses.TUI...........: $cursesmsg" + if test "x$opencl" != xno; then if test $found_opencl = 1; then echo " OpenCL...............: FOUND. GPU mining support enabled" diff --git a/driver-avalon.c b/driver-avalon.c index 83cff74f..348a2aea 100644 --- a/driver-avalon.c +++ b/driver-avalon.c @@ -531,7 +531,7 @@ static void avalon_initialise(struct cgpu_info *avalon) if (avalon->usbinfo.nodev) return; - interface = avalon->usbdev->found->interface; + interface = usb_interface(avalon); // Reset err = usb_transfer(avalon, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_RESET, interface, C_RESET); diff --git a/driver-bflsc.c b/driver-bflsc.c index 570a65ad..48cadf23 100644 --- a/driver-bflsc.c +++ b/driver-bflsc.c @@ -452,7 +452,7 @@ static bool bflsc_qres(struct cgpu_info *bflsc, char *buf, size_t bufsiz, int de static void __bflsc_initialise(struct cgpu_info *bflsc) { - int err; + 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? @@ -460,9 +460,10 @@ static void __bflsc_initialise(struct cgpu_info *bflsc) if (bflsc->usbinfo.nodev) return; + interface = usb_interface(bflsc); // Reset err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, - FTDI_VALUE_RESET, bflsc->usbdev->found->interface, C_RESET); + FTDI_VALUE_RESET, interface, C_RESET); applog(LOG_DEBUG, "%s%i: reset got err %d", bflsc->drv->name, bflsc->device_id, err); @@ -477,7 +478,7 @@ static void __bflsc_initialise(struct cgpu_info *bflsc) // Set data control err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_DATA, - FTDI_VALUE_DATA_BAS, bflsc->usbdev->found->interface, C_SETDATA); + FTDI_VALUE_DATA_BAS, interface, C_SETDATA); applog(LOG_DEBUG, "%s%i: setdata got err %d", bflsc->drv->name, bflsc->device_id, err); @@ -487,7 +488,7 @@ static void __bflsc_initialise(struct cgpu_info *bflsc) // Set the baud err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, FTDI_VALUE_BAUD_BAS, - (FTDI_INDEX_BAUD_BAS & 0xff00) | bflsc->usbdev->found->interface, + (FTDI_INDEX_BAUD_BAS & 0xff00) | interface, C_SETBAUD); applog(LOG_DEBUG, "%s%i: setbaud got err %d", @@ -498,7 +499,7 @@ static void __bflsc_initialise(struct cgpu_info *bflsc) // Set Flow Control err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_FLOW, - FTDI_VALUE_FLOW, bflsc->usbdev->found->interface, C_SETFLOW); + FTDI_VALUE_FLOW, interface, C_SETFLOW); applog(LOG_DEBUG, "%s%i: setflowctrl got err %d", bflsc->drv->name, bflsc->device_id, err); @@ -508,7 +509,7 @@ static void __bflsc_initialise(struct cgpu_info *bflsc) // Set Modem Control err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_MODEM, - FTDI_VALUE_MODEM, bflsc->usbdev->found->interface, C_SETMODEM); + FTDI_VALUE_MODEM, interface, C_SETMODEM); applog(LOG_DEBUG, "%s%i: setmodemctrl got err %d", bflsc->drv->name, bflsc->device_id, err); @@ -518,7 +519,7 @@ static void __bflsc_initialise(struct cgpu_info *bflsc) // Clear any sent data err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, - FTDI_VALUE_PURGE_TX, bflsc->usbdev->found->interface, C_PURGETX); + FTDI_VALUE_PURGE_TX, interface, C_PURGETX); applog(LOG_DEBUG, "%s%i: purgetx got err %d", bflsc->drv->name, bflsc->device_id, err); @@ -528,7 +529,7 @@ static void __bflsc_initialise(struct cgpu_info *bflsc) // Clear any received data err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, - FTDI_VALUE_PURGE_RX, bflsc->usbdev->found->interface, C_PURGERX); + FTDI_VALUE_PURGE_RX, interface, C_PURGERX); applog(LOG_DEBUG, "%s%i: purgerx got err %d", bflsc->drv->name, bflsc->device_id, err); diff --git a/driver-bitforce.c b/driver-bitforce.c index 41deae39..30a6b2dd 100644 --- a/driver-bitforce.c +++ b/driver-bitforce.c @@ -81,7 +81,7 @@ struct device_drv bitforce_drv; static void bitforce_initialise(struct cgpu_info *bitforce, bool lock) { - int err; + int err, interface; if (lock) mutex_lock(&bitforce->device_mutex); @@ -89,9 +89,10 @@ static void bitforce_initialise(struct cgpu_info *bitforce, bool lock) if (bitforce->usbinfo.nodev) goto failed; + interface = usb_interface(bitforce); // Reset err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, - FTDI_VALUE_RESET, bitforce->usbdev->found->interface, C_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); @@ -101,7 +102,7 @@ static void bitforce_initialise(struct cgpu_info *bitforce, bool lock) // Set data control err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_DATA, - FTDI_VALUE_DATA_BFL, bitforce->usbdev->found->interface, C_SETDATA); + 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); @@ -111,7 +112,7 @@ static void bitforce_initialise(struct cgpu_info *bitforce, bool lock) // Set the baud err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, FTDI_VALUE_BAUD_BFL, - (FTDI_INDEX_BAUD_BFL & 0xff00) | bitforce->usbdev->found->interface, + (FTDI_INDEX_BAUD_BFL & 0xff00) | interface, C_SETBAUD); if (opt_debug) applog(LOG_DEBUG, "%s%i: setbaud got err %d", @@ -122,7 +123,7 @@ static void bitforce_initialise(struct cgpu_info *bitforce, bool lock) // Set Flow Control err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_FLOW, - FTDI_VALUE_FLOW, bitforce->usbdev->found->interface, C_SETFLOW); + 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); @@ -132,7 +133,7 @@ static void bitforce_initialise(struct cgpu_info *bitforce, bool lock) // Set Modem Control err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_MODEM, - FTDI_VALUE_MODEM, bitforce->usbdev->found->interface, C_SETMODEM); + 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); @@ -142,7 +143,7 @@ static void bitforce_initialise(struct cgpu_info *bitforce, bool lock) // Clear any sent data err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, - FTDI_VALUE_PURGE_TX, bitforce->usbdev->found->interface, C_PURGETX); + 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); @@ -152,7 +153,7 @@ static void bitforce_initialise(struct cgpu_info *bitforce, bool lock) // Clear any received data err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, - FTDI_VALUE_PURGE_RX, bitforce->usbdev->found->interface, C_PURGERX); + 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); diff --git a/driver-icarus.c b/driver-icarus.c index 647c9d14..42814a12 100644 --- a/driver-icarus.c +++ b/driver-icarus.c @@ -102,7 +102,9 @@ ASSERT1(sizeof(uint32_t) == 4); #define LANCELOT_HASH_TIME 0.0000000025000 #define ASICMINERUSB_HASH_TIME 0.0000000029761 // TODO: What is it? -#define CAIRNSMORE1_HASH_TIME 0.0000000026316 +#define CAIRNSMORE1_HASH_TIME 0.0000000027000 +// Per FPGA +#define CAIRNSMORE2_HASH_TIME 0.0000000066600 #define NANOSEC 1000000000.0 // Icarus Rev3 doesn't send a completion message when it finishes @@ -208,6 +210,8 @@ struct ICARUS_INFO { int work_division; int fpga_count; uint32_t nonce_mask; + + bool initialised; }; #define END_CONDITION 0x0000ffff @@ -262,6 +266,7 @@ static void _transfer(struct cgpu_info *icarus, uint8_t request_type, uint8_t bR 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; @@ -282,6 +287,9 @@ static void icarus_initialise(struct cgpu_info *icarus, int baud) case IDENT_CMR2: usb_set_pps(icarus, BLT_PREF_PACKET); + if (ident == IDENT_CMR2) // Chip hack + interface++; + // Reset transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_RESET, interface, C_RESET); @@ -403,6 +411,8 @@ static void icarus_initialise(struct cgpu_info *icarus, int baud) quit(1, "icarus_intialise() called with invalid %s cgid %i ident=%d", icarus->drv->name, icarus->cgminer_id, ident); } + + info->initialised = true; } static void rev(unsigned char *s, size_t l) @@ -537,11 +547,12 @@ static void set_timing_mode(int this_option_offset, struct cgpu_info *icarus) case IDENT_AMU: info->Hs = ASICMINERUSB_HASH_TIME; break; - // TODO: ? case IDENT_CMR1: - case IDENT_CMR2: 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); @@ -701,13 +712,16 @@ static void get_options(int this_option_offset, struct cgpu_info *icarus, int *b *work_division = 1; *fpga_count = 1; break; - // TODO: ? case IDENT_CMR1: - case IDENT_CMR2: *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); @@ -795,6 +809,11 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices hex2bin(ob_bin, golden_ob, sizeof(ob_bin)); + 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; + tries = 2; ok = false; while (!ok && tries-- > 0) { @@ -844,15 +863,6 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices 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 = (struct ICARUS_INFO *)malloc(sizeof(struct ICARUS_INFO)); - if (unlikely(!info)) - quit(1, "Failed to malloc ICARUS_INFO"); - - icarus->device_data = (void *)info; - - // Initialise everything to zero for a new device - memset(info, 0, sizeof(struct ICARUS_INFO)); - info->baud = baud; info->work_division = work_division; info->fpga_count = fpga_count; @@ -862,12 +872,47 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices timersub(&tv_finish, &tv_start, &(info->golden_tv)); set_timing_mode(this_option_offset, icarus); + + if (usb_ident(icarus) == IDENT_CMR2) { + int i; + for (i = 1; i < icarus->usbdev->found->intinfo_count; i++) { + struct cgpu_info *cgtmp; + struct ICARUS_INFO *intmp; + + cgtmp = usb_init_intinfo(icarus, i); + if (!cgtmp) { + applog(LOG_ERR, "%s%d: Init failed initinfo %d", + icarus->drv->name, icarus->device_id, i); + continue; + } + + cgtmp->usbinfo.usbstat = USB_NOSTAT; + + if (!add_cgpu(cgtmp)) { + usb_uninit(cgtmp); + continue; + } + + update_usb_stats(cgtmp); + + 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)); + } + } return true; unshin: usb_uninit(icarus); + free(info); + icarus->device_data = NULL; shin: @@ -917,6 +962,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, if (icarus->usbinfo.nodev) return -1; + if (!info->initialised) + icarus_initialise(icarus, info->baud); + elapsed.tv_sec = elapsed.tv_usec = 0; memset(ob_bin, 0, sizeof(ob_bin)); diff --git a/miner.h b/miner.h index 850e6333..be33daa8 100644 --- a/miner.h +++ b/miner.h @@ -8,7 +8,17 @@ #include #include #include +#ifdef HAVE_LIBCURL #include +#else +typedef char CURL; +extern char *curly; +#define curl_easy_init(curl) (curly) +#define curl_easy_cleanup(curl) {} +#define curl_global_cleanup() {} +#define CURL_GLOBAL_ALL 0 +#define curl_global_init(X) (0) +#endif #include #include "elist.h" @@ -913,10 +923,12 @@ extern int swork_id; extern pthread_rwlock_t netacc_lock; extern const uint32_t sha256_init_state[]; +#ifdef HAVE_LIBCURL extern json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass, const char *rpc_req, bool, bool, int *, struct pool *pool, bool); -extern const char *proxytype(curl_proxytype proxytype); +#endif +extern const char *proxytype(proxytypes_t proxytype); extern char *get_proxy(char *url, struct pool *pool); extern char *bin2hex(const unsigned char *p, size_t len); extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len); @@ -1156,7 +1168,7 @@ struct pool { char *rpc_url; char *rpc_userpass; char *rpc_user, *rpc_pass; - curl_proxytype rpc_proxytype; + proxytypes_t rpc_proxytype; char *rpc_proxy; pthread_mutex_t pool_lock; diff --git a/ocl.c b/ocl.c index 27ef1e9d..f7184dbb 100644 --- a/ocl.c +++ b/ocl.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #ifdef WIN32 diff --git a/usbutils.c b/usbutils.c index 1c84eeff..534b903d 100644 --- a/usbutils.c +++ b/usbutils.c @@ -25,7 +25,23 @@ #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 DEVLOCK(cgpu, _pth_state) do { \ + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &_pth_state); \ + wr_lock(cgpu->usbinfo.devlock); \ + } while (0) + +#define DEVUNLOCK(cgpu, _pth_state) do { \ + wr_unlock(cgpu->usbinfo.devlock); \ + pthread_setcancelstate(_pth_state, NULL); \ + } while (0) + #ifdef USE_BFLSC #define DRV_BFLSC 1 #endif @@ -74,74 +90,136 @@ #define USB_READ_MINPOLL 40 +#define USB_EPS(_intx, _epinfosx) { \ + .interface = _intx, \ + .epinfo_count = ARRAY_SIZE(_epinfosx), \ + .epinfos = _epinfosx \ + } + #ifdef USE_BFLSC // N.B. transfer size is 512 with USB2.0, but only 64 with USB1.1 -static struct usb_endpoints bas_eps[] = { +static struct usb_epinfo bas_epinfos[] = { { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(1), 0 }, { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(2), 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_endpoints bfl_eps[] = { +static struct usb_epinfo bfl_epinfos[] = { { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(1), 0 }, { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(2), 0 } }; + +static struct usb_intinfo bfl_ints[] = { + USB_EPS(0, bfl_epinfos) +}; #endif #ifdef USE_MODMINER -static struct usb_endpoints mmq_eps[] = { +static struct usb_epinfo mmq_epinfos[] = { { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(3), 0 }, { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(3), 0 } }; + +static struct usb_intinfo mmq_ints[] = { + USB_EPS(1, mmq_epinfos) +}; #endif #ifdef USE_AVALON -static struct usb_endpoints ava_eps[] = { +static struct usb_epinfo ava_epinfos[] = { { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(1), 0 }, { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(2), 0 } }; + +static struct usb_intinfo ava_ints[] = { + USB_EPS(0, ava_epinfos) +}; #endif #ifdef USE_ICARUS -static struct usb_endpoints ica_eps[] = { +static struct usb_epinfo ica_epinfos[] = { { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(3), 0 }, { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(2), 0 } }; -static struct usb_endpoints amu_eps[] = { + +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 }, { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(1), 0 } }; -static struct usb_endpoints llt_eps[] = { + +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 }, { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(2), 0 } }; -static struct usb_endpoints cmr1_eps[] = { + +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 }, { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(2), 0 } -/* - Interface 1 +}; + +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 }, + { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(2), 0 } +}; +#ifndef WIN32 +static struct usb_epinfo cmr2_epinfos1[] = { { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(3), 0 }, { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(4), 0 }, - - Interface 2 +}; +static struct usb_epinfo cmr2_epinfos2[] = { { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(5), 0 }, { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(6), 0 }, - - Interface 3 +}; +static struct usb_epinfo cmr2_epinfos3[] = { { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(7), 0 }, { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(8), 0 } -*/ }; -static struct usb_endpoints cmr2_eps[] = { - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(1), 0 }, - { LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(2), 0 } +#endif + +static struct usb_intinfo cmr2_ints[] = { + USB_EPS(0, cmr2_epinfos0) +#ifndef WIN32 + , + USB_EPS(1, cmr2_epinfos1), + USB_EPS(2, cmr2_epinfos2), + USB_EPS(3, cmr2_epinfos3) +#endif }; #endif #define IDVENDOR_FTDI 0x0403 +#define INTINFO(_ints) \ + .which_intinfo = 0, \ + .intinfo_count = ARRAY_SIZE(_ints), \ + .intinfos = _ints + +#define USBEP(_usbdev, _epinfo) (_usbdev->found->intinfos[_usbdev->found->which_intinfo].epinfos[_epinfo].ep) +#define FOUNDIF(_found) (_found->intinfos[_found->which_intinfo].interface) +#define USBIF(_usbdev) FOUNDIF(_usbdev->found) + // TODO: Add support for (at least) Isochronous endpoints static struct usb_find_devices find_dev[] = { #ifdef USE_BFLSC @@ -153,13 +231,10 @@ static struct usb_find_devices find_dev[] = { .idProduct = 0x6014, //.iManufacturer = "Butterfly Labs", .iProduct = "BitFORCE SHA256 SC", - .kernel = 0, .config = 1, - .interface = 0, .timeout = BFLSC_TIMEOUT_MS, .latency = LATENCY_STD, - .epcount = ARRAY_SIZE(bas_eps), - .eps = bas_eps }, + INTINFO(bas_ints) }, #endif #ifdef USE_BITFORCE { @@ -170,13 +245,10 @@ static struct usb_find_devices find_dev[] = { .idProduct = 0x6014, .iManufacturer = "Butterfly Labs Inc.", .iProduct = "BitFORCE SHA256", - .kernel = 0, .config = 1, - .interface = 0, .timeout = BITFORCE_TIMEOUT_MS, .latency = LATENCY_STD, - .epcount = ARRAY_SIZE(bfl_eps), - .eps = bfl_eps }, + INTINFO(bfl_ints) }, #endif #ifdef USE_MODMINER { @@ -185,13 +257,10 @@ static struct usb_find_devices find_dev[] = { .ident = IDENT_MMQ, .idVendor = 0x1fc9, .idProduct = 0x0003, - .kernel = 0, .config = 1, - .interface = 1, .timeout = MODMINER_TIMEOUT_MS, .latency = LATENCY_UNUSED, - .epcount = ARRAY_SIZE(mmq_eps), - .eps = mmq_eps }, + INTINFO(mmq_ints) }, #endif #ifdef USE_AVALON { @@ -202,26 +271,20 @@ static struct usb_find_devices find_dev[] = { .idProduct = 0x6001, .iManufacturer = "Burnin Electronics", .iProduct = "BitBurner", - .kernel = 0, .config = 1, - .interface = 0, .timeout = AVALON_TIMEOUT_MS, .latency = 10, - .epcount = ARRAY_SIZE(ava_eps), - .eps = ava_eps }, + INTINFO(ava_ints) }, { .drv = DRV_AVALON, .name = "AVA", .ident = IDENT_AVA, .idVendor = IDVENDOR_FTDI, .idProduct = 0x6001, - .kernel = 0, .config = 1, - .interface = 0, .timeout = AVALON_TIMEOUT_MS, .latency = 10, - .epcount = ARRAY_SIZE(ava_eps), - .eps = ava_eps }, + INTINFO(ava_ints) }, #endif #ifdef USE_HASHFAST { @@ -237,26 +300,20 @@ static struct usb_find_devices find_dev[] = { .ident = IDENT_ICA, .idVendor = 0x067b, .idProduct = 0x2303, - .kernel = 0, .config = 1, - .interface = 0, .timeout = ICARUS_TIMEOUT_MS, .latency = LATENCY_UNUSED, - .epcount = ARRAY_SIZE(ica_eps), - .eps = ica_eps }, + INTINFO(ica_ints) }, { .drv = DRV_ICARUS, .name = "AMU", .ident = IDENT_AMU, .idVendor = 0x10c4, .idProduct = 0xea60, - .kernel = 0, .config = 1, - .interface = 0, .timeout = ICARUS_TIMEOUT_MS, .latency = LATENCY_UNUSED, - .epcount = ARRAY_SIZE(amu_eps), - .eps = amu_eps }, + INTINFO(amu_ints) }, { .drv = DRV_ICARUS, .name = "BLT", @@ -264,13 +321,10 @@ static struct usb_find_devices find_dev[] = { .idVendor = IDVENDOR_FTDI, .idProduct = 0x6001, .iProduct = "FT232R USB UART", - .kernel = 0, .config = 1, - .interface = 0, .timeout = ICARUS_TIMEOUT_MS, .latency = LATENCY_STD, - .epcount = ARRAY_SIZE(llt_eps), - .eps = llt_eps }, + INTINFO(llt_ints) }, // For any that don't match the above "BLT" { .drv = DRV_ICARUS, @@ -278,41 +332,32 @@ static struct usb_find_devices find_dev[] = { .ident = IDENT_LLT, .idVendor = IDVENDOR_FTDI, .idProduct = 0x6001, - .kernel = 0, .config = 1, - .interface = 0, .timeout = ICARUS_TIMEOUT_MS, .latency = LATENCY_STD, - .epcount = ARRAY_SIZE(llt_eps), - .eps = llt_eps }, + INTINFO(llt_ints) }, { .drv = DRV_ICARUS, .name = "CMR", .ident = IDENT_CMR1, .idVendor = IDVENDOR_FTDI, - .idProduct = 0x8350, + .idProduct = 0x6014, .iProduct = "Cairnsmore1", - .kernel = 0, .config = 1, - .interface = 0, .timeout = ICARUS_TIMEOUT_MS, .latency = LATENCY_STD, - .epcount = ARRAY_SIZE(cmr1_eps), - .eps = cmr1_eps }, + INTINFO(cmr1_ints) }, { .drv = DRV_ICARUS, .name = "CMR", .ident = IDENT_CMR2, .idVendor = IDVENDOR_FTDI, - .idProduct = 0x6014, + .idProduct = 0x8350, .iProduct = "Cairnsmore1", - .kernel = 0, .config = 1, - .interface = 0, .timeout = ICARUS_TIMEOUT_MS, .latency = LATENCY_STD, - .epcount = ARRAY_SIZE(cmr2_eps), - .eps = cmr2_eps }, + INTINFO(cmr2_ints) }, #endif #ifdef USE_ZTEX // This is here so cgminer -n shows them @@ -323,15 +368,14 @@ static struct usb_find_devices find_dev[] = { .ident = IDENT_ZTX, .idVendor = 0x221a, .idProduct = 0x0100, - .kernel = 0, .config = 1, - .interface = 1, .timeout = 100, .latency = LATENCY_UNUSED, - .epcount = 0, - .eps = NULL }, + .which_intinfo = 0, + .intinfo_count = 0, + .intinfos = NULL }, #endif - { DRV_LAST, NULL, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, NULL } + { DRV_LAST, NULL, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, NULL } }; #ifdef USE_BFLSC @@ -1375,7 +1419,8 @@ static struct cg_usb_device *free_cgusb(struct cg_usb_device *cgusb) if (cgusb->prod_string && cgusb->prod_string != BLANK) free(cgusb->prod_string); - free(cgusb->descriptor); + if (cgusb->descriptor) + free(cgusb->descriptor); free(cgusb->found); @@ -1387,7 +1432,7 @@ static struct cg_usb_device *free_cgusb(struct cg_usb_device *cgusb) return NULL; } -void usb_uninit(struct cgpu_info *cgpu) +static void _usb_uninit(struct cgpu_info *cgpu) { applog(LOG_DEBUG, "USB uninit %s%i", cgpu->drv->name, cgpu->device_id); @@ -1396,14 +1441,28 @@ void usb_uninit(struct cgpu_info *cgpu) // if release_cgpu() was called due to a USB NODEV(err) if (!cgpu->usbdev) return; - if (!libusb_release_interface(cgpu->usbdev->handle, cgpu->usbdev->found->interface)) { + + if (cgpu->usbdev->handle) { + libusb_release_interface(cgpu->usbdev->handle, USBIF(cgpu->usbdev)); 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; + + DEVLOCK(cgpu, pstate); + + _usb_uninit(cgpu); + + DEVUNLOCK(cgpu, pstate); +} + /* * N.B. this is always called inside * DEVLOCK(cgpu, pstate); @@ -1412,7 +1471,7 @@ static void release_cgpu(struct cgpu_info *cgpu) { struct cg_usb_device *cgusb = cgpu->usbdev; struct cgpu_info *lookcgpu; - int i; + int which_intinfo, i; applog(LOG_DEBUG, "USB release %s%i", cgpu->drv->name, cgpu->device_id); @@ -1445,16 +1504,24 @@ static void release_cgpu(struct cgpu_info *cgpu) } } - usb_uninit(cgpu); - - cgminer_usb_unlock_bd(cgpu->drv, cgpu->usbinfo.bus_number, cgpu->usbinfo.device_address); + which_intinfo = cgpu->usbdev->found->which_intinfo; + _usb_uninit(cgpu); + if (which_intinfo == 0) + cgminer_usb_unlock_bd(cgpu->drv, cgpu->usbinfo.bus_number, cgpu->usbinfo.device_address); } -// Currently only used by MMQ +/* + * Used by MMQ - use the same usbdev thus locking is across all 4 related devices + * since they must use the same USB handle since they use the same interface + */ struct cgpu_info *usb_copy_cgpu(struct cgpu_info *orig) { - struct cgpu_info *copy = calloc(1, sizeof(*copy)); + struct cgpu_info *copy; + int pstate; + + DEVLOCK(orig, pstate); + copy = calloc(1, sizeof(*copy)); if (unlikely(!copy)) quit(1, "Failed to calloc cgpu for %s in usb_copy_cgpu", orig->drv->dname); @@ -1471,6 +1538,75 @@ struct cgpu_info *usb_copy_cgpu(struct cgpu_info *orig) copy->usbinfo.devlock = orig->usbinfo.devlock; + DEVUNLOCK(orig, pstate); + + return copy; +} + +/* + * Used by CMR - use a different usbdev - since they must use a different + * USB handle due to using different interfaces (libusb requirement) + * N.B. multiple interfaces don't as yet work in windows libusb + * so the CMR defines above that use them are defined out in windows + * Nothing else uses multiple interfaces as at 20130922 + */ +static struct cgpu_info *usb_dup_cgpu(struct cgpu_info *orig, int intinfo) +{ + struct cgpu_info *copy; + + copy = calloc(1, sizeof(*copy)); + if (unlikely(!copy)) + quit(1, "Failed to calloc cgpu for %s in usb_dup_cgpu", orig->drv->dname); + + copy->name = orig->name; + copy->drv = copy_drv(orig->drv); + copy->deven = orig->deven; + copy->threads = orig->threads; + + if (orig->usbdev) { + copy->usbdev = calloc(1, sizeof(*(copy->usbdev))); + if (unlikely(!copy->usbdev)) + quit(1, "Failed to calloc usbdev for %s in usb_dup_cgpu", orig->drv->dname); + + copy->usbdev->found = malloc(sizeof(*(copy->usbdev->found))); + if (unlikely(!copy->usbdev->found)) + quit(1, "Failed to malloc found for %s in usb_dup_cgpu", orig->drv->dname); + memcpy(copy->usbdev->found, orig->usbdev->found, sizeof(*(copy->usbdev->found))); + + copy->usbdev->found->which_intinfo = intinfo; + + copy->usbdev->descriptor = NULL; // don't need it + copy->usbdev->usb_type = orig->usbdev->usb_type; + copy->usbdev->ident = orig->usbdev->ident; + copy->usbdev->usbver = orig->usbdev->usbver; + copy->usbdev->cps = orig->usbdev->cps; + copy->usbdev->usecps = orig->usbdev->usecps; + if (orig->usbdev->prod_string == BLANK) + copy->usbdev->prod_string = (char *)BLANK; + else + copy->usbdev->prod_string = strdup(orig->usbdev->prod_string); + if (orig->usbdev->manuf_string == BLANK) + copy->usbdev->manuf_string = (char *)BLANK; + else + copy->usbdev->manuf_string = strdup(orig->usbdev->manuf_string); + if (orig->usbdev->serial_string == BLANK) + copy->usbdev->serial_string = (char *)BLANK; + else + copy->usbdev->serial_string = strdup(orig->usbdev->serial_string); + copy->usbdev->fwVersion = orig->usbdev->fwVersion; + copy->usbdev->interfaceVersion = orig->usbdev->interfaceVersion; + } + + memcpy(&(copy->usbinfo), &(orig->usbinfo), sizeof(copy->usbinfo)); + + copy->usbinfo.nodev = (copy->usbdev == NULL); + + copy->usbinfo.devlock = calloc(1, sizeof(*(copy->usbinfo.devlock))); + if (unlikely(!copy->usbinfo.devlock)) + quit(1, "Failed to calloc devlock for %s in usb_dup_cgpu", orig->drv->dname); + + rwlock_init(copy->usbinfo.devlock); + return copy; } @@ -1515,23 +1651,6 @@ struct cgpu_info *usb_free_cgpu_devlock(struct cgpu_info *cgpu, bool free_devloc #define USB_INIT_OK 1 #define USB_INIT_IGNORE 2 -/* - * 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 DEVLOCK(cgpu, _pth_state) do { \ - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &_pth_state); \ - wr_lock(cgpu->usbinfo.devlock); \ - } while (0) - -#define DEVUNLOCK(cgpu, _pth_state) do { \ - wr_unlock(cgpu->usbinfo.devlock); \ - pthread_setcancelstate(_pth_state, NULL); \ - } while (0) - static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found) { struct cg_usb_device *cgusb = NULL; @@ -1541,7 +1660,7 @@ static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct u unsigned char strbuf[STRBUFLEN+1]; char devpath[32]; char devstr[STRBUFLEN+1]; - int err, i, j, k, pstate; + int err, ifinfo, epinfo, alt, epnum, pstate; int bad = USB_INIT_FAIL; int cfg; @@ -1550,9 +1669,16 @@ static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct u cgpu->usbinfo.bus_number = libusb_get_bus_number(dev); cgpu->usbinfo.device_address = libusb_get_device_address(dev); - snprintf(devpath, sizeof(devpath), "%d:%d", - (int)(cgpu->usbinfo.bus_number), - (int)(cgpu->usbinfo.device_address)); + if (found->intinfo_count > 1) { + snprintf(devpath, sizeof(devpath), "%d:%d-i%d", + (int)(cgpu->usbinfo.bus_number), + (int)(cgpu->usbinfo.device_address), + FOUNDIF(found)); + } else { + snprintf(devpath, sizeof(devpath), "%d:%d", + (int)(cgpu->usbinfo.bus_number), + (int)(cgpu->usbinfo.device_address)); + } cgpu->device_path = strdup(devpath); @@ -1609,17 +1735,17 @@ static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct u } #ifndef WIN32 - if (libusb_kernel_driver_active(cgusb->handle, found->kernel) == 1) { + if (libusb_kernel_driver_active(cgusb->handle, FOUNDIF(found)) == 1) { applog(LOG_DEBUG, "USB init, kernel attached ... %s", devstr); - err = libusb_detach_kernel_driver(cgusb->handle, found->kernel); + err = libusb_detach_kernel_driver(cgusb->handle, FOUNDIF(found)); if (err == 0) { applog(LOG_DEBUG, - "USB init, kernel detached successfully %s", - devstr); + "USB init, kernel detached interface %d successfully %s", + FOUNDIF(found), devstr); } else { applog(LOG_WARNING, - "USB init, kernel detach failed, err %d in use? %s", - err, devstr); + "USB init, kernel detach interface %d failed, err %d in use? %s", + FOUNDIF(found), err, devstr); goto cldame; } } @@ -1697,55 +1823,66 @@ static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct u goto cldame; } - if ((int)(config->bNumInterfaces) <= found->interface) { - applog(LOG_DEBUG, "USB init bNumInterfaces <= interface %s", - devstr); + 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 (i = 0; i < found->epcount; i++) - found->eps[i].found = false; - - for (i = 0; i < config->interface[found->interface].num_altsetting; i++) { - idesc = &(config->interface[found->interface].altsetting[i]); - for (j = 0; j < (int)(idesc->bNumEndpoints); j++) { - epdesc = &(idesc->endpoint[j]); - for (k = 0; k < found->epcount; k++) { - if (!found->eps[k].found) { - if (epdesc->bmAttributes == found->eps[k].att - && epdesc->wMaxPacketSize >= found->eps[k].size - && epdesc->bEndpointAddress == found->eps[k].ep) { - found->eps[k].found = true; - found->wMaxPacketSize = epdesc->wMaxPacketSize; - break; + 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; + // TODO: it's an ep (not device) attribute + found->wMaxPacketSize = epdesc->wMaxPacketSize; + break; + } } } } } } - for (i = 0; i < found->epcount; i++) { - if (found->eps[i].found == false) { - applog(LOG_DEBUG, "USB init found == false %s", - devstr); - goto cldame; - } - } + 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; + } - err = libusb_claim_interface(cgusb->handle, found->interface); + err = libusb_claim_interface(cgusb->handle, FOUNDIF(found)); if (err) { switch(err) { case LIBUSB_ERROR_BUSY: applog(LOG_WARNING, "USB init, claim interface %d in use %s", - found->interface, devstr); + FOUNDIF(found), devstr); break; default: applog(LOG_DEBUG, "USB init, claim interface %d failed, err %d %s", - found->interface, err, devstr); + FOUNDIF(found), err, devstr); } - goto cldame; + goto reldame; } cfg = -1; @@ -1812,12 +1949,13 @@ static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct u reldame: - libusb_release_interface(cgusb->handle, found->interface); + libusb_release_interface(cgusb->handle, FOUNDIF(found)); cldame: cg_wlock(&cgusb_fd_lock); libusb_close(cgusb->handle); + cgusb->handle = NULL; cg_wunlock(&cgusb_fd_lock); dame: @@ -1833,6 +1971,144 @@ out_unlock: return bad; } +// To get the extra interfaces on a multi interface device +struct cgpu_info *usb_init_intinfo(struct cgpu_info *orig, int intinfo) +{ + struct usb_find_devices *found; + struct libusb_device *dev; + struct cgpu_info *copy = NULL; + char msgstr[STRBUFLEN+1]; + char devstr[STRBUFLEN+1]; + char devpath[32]; + int err, pstate; + + DEVLOCK(orig, pstate); + + snprintf(msgstr, sizeof(msgstr), "USB %s init_intinfo (%d:%d-i%d)", + orig->drv->dname, + (int)(orig->usbinfo.bus_number), + (int)(orig->usbinfo.device_address), + orig->usbdev->found->which_intinfo); + + if (orig->usbinfo.nodev) { + applog(LOG_ERR, "%s cgpu has nodev", msgstr); + goto Hitagi; + } + + if (orig->usbdev->found->which_intinfo != 0) { + applog(LOG_ERR, "%s incorrect cgpu (must be i0)", msgstr); + goto Hitagi; + } + + if (orig->usbdev->found->intinfo_count < 2) { + applog(LOG_ERR, "%s cgpu only has 1 interface", msgstr); + goto Hitagi; + } + + if (intinfo < 1 || intinfo >= orig->usbdev->found->intinfo_count) { + applog(LOG_ERR, "%s invalid intinfo (%d) must be > 0 && < %d", + msgstr, intinfo, orig->usbdev->found->intinfo_count); + goto Hitagi; + } + + dev = libusb_get_device(orig->usbdev->handle); + + copy = usb_dup_cgpu(orig, intinfo); + if (!copy) + goto Hitagi; + + found = copy->usbdev->found; + + snprintf(devpath, sizeof(devpath), "%d:%d-i%d", + (int)(copy->usbinfo.bus_number), + (int)(copy->usbinfo.device_address), + FOUNDIF(found)); + + copy->device_path = strdup(devpath); + + snprintf(devstr, sizeof(devstr), "- %s device %s", found->name, devpath); + + cg_wlock(&cgusb_fd_lock); + err = libusb_open(dev, &(copy->usbdev->handle)); + cg_wunlock(&cgusb_fd_lock); + if (err) { + switch (err) { + case LIBUSB_ERROR_ACCESS: + applog(LOG_ERR, + "USB init_intinfo, open device failed, err %d, " + "you don't have privilege to access %s", + err, devstr); + break; +#ifdef WIN32 + // Windows specific message + case LIBUSB_ERROR_NOT_SUPPORTED: + applog(LOG_ERR, + "USB init_intinfo, open device failed, err %d, " + "you need to install a WinUSB driver for %s", + err, devstr); + break; +#endif + default: + applog(LOG_DEBUG, + "USB init_intinfo, open failed, err %d %s", + err, devstr); + } + goto Hitagi; + } + +#ifndef WIN32 + if (libusb_kernel_driver_active(copy->usbdev->handle, FOUNDIF(found)) == 1) { + applog(LOG_DEBUG, "USB init_intinfo, kernel attached ... %s", devstr); + err = libusb_detach_kernel_driver(copy->usbdev->handle, FOUNDIF(found)); + if (err == 0) { + applog(LOG_DEBUG, + "USB init_intinfo, kernel detached interface %d successfully %s", + FOUNDIF(found), devstr); + } else { + applog(LOG_WARNING, + "USB init_intinfo, kernel detach interface %d failed, err %d in use? %s", + FOUNDIF(found), err, devstr); + goto HitagiClose; + } + } +#endif + + err = libusb_claim_interface(copy->usbdev->handle, FOUNDIF(found)); + if (err) { + switch(err) { + case LIBUSB_ERROR_BUSY: + applog(LOG_WARNING, + "USB init_intinfo, claim interface %d in use %s", + FOUNDIF(found), devstr); + break; + default: + applog(LOG_DEBUG, + "USB init_intinfo, claim interface %d failed, err %d %s", + FOUNDIF(found), err, devstr); + } + goto HitagiClose; + } + + goto Hitagi; + +HitagiClose: + + cg_wlock(&cgusb_fd_lock); + libusb_close(copy->usbdev->handle); + copy->usbdev->handle = NULL; + cg_wunlock(&cgusb_fd_lock); + + copy->usbdev = free_cgusb(copy->usbdev); + + copy = usb_free_cgpu(copy); + +Hitagi: + + DEVUNLOCK(orig, pstate); + + return copy; +} + bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found_match) { struct usb_find_devices *found_use = NULL; @@ -2391,7 +2667,7 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, return err; } -int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, const char *end, enum usb_cmds cmd, bool readonce) +int _usb_read(struct cgpu_info *cgpu, int epinfo, char *buf, size_t bufsiz, int *processed, unsigned int timeout, const char *end, enum usb_cmds cmd, bool readonce) { struct cg_usb_device *usbdev; bool ftdi; @@ -2419,7 +2695,7 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro usbdev = cgpu->usbdev; ftdi = (usbdev->usb_type == USB_TYPE_FTDI); - USBDEBUG("USB debug: _usb_read(%s (nodev=%s),ep=%d,buf=%p,bufsiz=%zu,proc=%p,timeout=%u,end=%s,cmd=%s,ftdi=%s,readonce=%s)", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), ep, buf, bufsiz, processed, timeout, end ? (char *)str_text((char *)end) : "NULL", usb_cmdname(cmd), bool_str(ftdi), bool_str(readonce)); + USBDEBUG("USB debug: _usb_read(%s (nodev=%s),epinfo=%d,buf=%p,bufsiz=%zu,proc=%p,timeout=%u,end=%s,cmd=%s,ftdi=%s,readonce=%s)", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), epinfo, buf, 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); @@ -2473,7 +2749,7 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro } } err = usb_bulk_transfer(usbdev->handle, - usbdev->found->eps[ep].ep, + USBEP(usbdev, epinfo), ptr, usbbufread, &got, timeout, cgpu, MODE_BULK_READ, cmd, first ? SEQ0 : SEQ1); cgtime(&tv_finish); @@ -2516,7 +2792,7 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro // N.B. usbdev->buffer was emptied before the while() loop if (usbdev->buffer && tot > (int)bufsiz) { usbdev->bufamt = tot - bufsiz; - memcpy(usbdev->buffer, ptr + bufsiz, usbdev->bufamt); + memcpy(usbdev->buffer, usbbuf + bufsiz, usbdev->bufamt); tot -= usbdev->bufamt; usbbuf[tot] = '\0'; applog(LOG_ERR, "USB: %s%i read1 buffering %d extra bytes", @@ -2577,7 +2853,7 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro } } err = usb_bulk_transfer(usbdev->handle, - usbdev->found->eps[ep].ep, ptr, + USBEP(usbdev, epinfo), ptr, usbbufread, &got, timeout, cgpu, MODE_BULK_READ, cmd, first ? SEQ0 : SEQ1); cgtime(&tv_finish); @@ -2664,7 +2940,7 @@ out_unlock: return err; } -int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, enum usb_cmds cmd) +int _usb_write(struct cgpu_info *cgpu, int epinfo, char *buf, size_t bufsiz, int *processed, unsigned int timeout, enum usb_cmds cmd) { struct cg_usb_device *usbdev; struct timeval read_start, tv_finish; @@ -2675,7 +2951,7 @@ int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pr DEVLOCK(cgpu, pstate); - USBDEBUG("USB debug: _usb_write(%s (nodev=%s),ep=%d,buf='%s',bufsiz=%zu,proc=%p,timeout=%u,cmd=%s)", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), ep, (char *)str_text(buf), bufsiz, processed, timeout, usb_cmdname(cmd)); + USBDEBUG("USB debug: _usb_write(%s (nodev=%s),epinfo=%d,buf='%s',bufsiz=%zu,proc=%p,timeout=%u,cmd=%s)", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), epinfo, (char *)str_text(buf), bufsiz, processed, timeout, usb_cmdname(cmd)); *processed = 0; @@ -2718,7 +2994,7 @@ int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pr usbdev->last_write_siz = bufsiz; } err = usb_bulk_transfer(usbdev->handle, - usbdev->found->eps[ep].ep, + USBEP(usbdev, epinfo), (unsigned char *)buf, bufsiz, &sent, timeout, cgpu, MODE_BULK_WRITE, cmd, first ? SEQ0 : SEQ1); cgtime(&tv_finish); @@ -2956,7 +3232,7 @@ int usb_ftdi_set_latency(struct cgpu_info *cgpu) if (!err) err = __usb_transfer(cgpu, FTDI_TYPE_OUT, FTDI_REQUEST_LATENCY, cgpu->usbdev->found->latency, - cgpu->usbdev->found->interface, + USBIF(cgpu->usbdev), NULL, 0, DEVTIMEOUT, C_LATENCY); } @@ -3083,7 +3359,7 @@ int usb_interface(struct cgpu_info *cgpu) DEVLOCK(cgpu, pstate); if (cgpu->usbdev) - interface = cgpu->usbdev->found->interface; + interface = USBIF(cgpu->usbdev); DEVUNLOCK(cgpu, pstate); diff --git a/usbutils.h b/usbutils.h index d02766f9..742930e3 100644 --- a/usbutils.h +++ b/usbutils.h @@ -109,18 +109,24 @@ // Use the device defined timeout #define DEVTIMEOUT 0 -// For endpoints defined in usb_find_devices.eps, -// the first two must be the default IN and OUT +// 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_endpoints { +struct usb_epinfo { uint8_t att; uint16_t size; unsigned char ep; bool found; }; +struct usb_intinfo { + int interface; + int epinfo_count; + struct usb_epinfo *epinfos; +}; + enum sub_ident { IDENT_UNK = 0, IDENT_BAJ, @@ -149,14 +155,13 @@ struct usb_find_devices { uint16_t idProduct; char *iManufacturer; char *iProduct; - int kernel; int config; - int interface; unsigned int timeout; uint16_t wMaxPacketSize; uint16_t latency; - int epcount; - struct usb_endpoints *eps; + int which_intinfo; + int intinfo_count; + struct usb_intinfo *intinfos; }; /* Latency is set to 32ms to prevent a transfer ever being more than 512 bytes @@ -343,6 +348,7 @@ struct cgpu_info *usb_alloc_cgpu(struct device_drv *drv, int threads); struct cgpu_info *usb_free_cgpu_devlock(struct cgpu_info *cgpu, bool free_devlock); #define usb_free_cgpu(cgpu) usb_free_cgpu_devlock(cgpu, true) void usb_uninit(struct cgpu_info *cgpu); +struct cgpu_info *usb_init_intinfo(struct cgpu_info *orig, int intinfo); bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found); void usb_detect(struct device_drv *drv, bool (*device_detect)(struct libusb_device *, struct usb_find_devices *)); struct api_data *api_usb_stats(int *count); diff --git a/util.c b/util.c index 2df54391..c0feaafd 100644 --- a/util.c +++ b/util.c @@ -16,7 +16,9 @@ #include #include #include +#ifdef HAVE_LIBCURL #include +#endif #include #include #include @@ -45,6 +47,44 @@ #define DEFAULT_SOCKWAIT 60 bool successful_connect = false; +static void keep_sockalive(SOCKETTYPE fd) +{ + const int tcp_one = 1; +#ifndef WIN32 + const int tcp_keepidle = 45; + const int tcp_keepintvl = 30; + int flags = fcntl(fd, F_GETFL, 0); + + fcntl(fd, F_SETFL, O_NONBLOCK | flags); +#else + u_long flags = 1; + + ioctlsocket(fd, FIONBIO, &flags); +#endif + + setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const void *)&tcp_one, sizeof(tcp_one)); + if (!opt_delaynet) +#ifndef __linux + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void *)&tcp_one, sizeof(tcp_one)); +#else /* __linux */ + setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&tcp_one, sizeof(tcp_one)); + setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &tcp_one, sizeof(tcp_one)); + setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &tcp_keepidle, sizeof(tcp_keepidle)); + setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &tcp_keepintvl, sizeof(tcp_keepintvl)); +#endif /* __linux */ + +#ifdef __APPLE_CC__ + setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &tcp_keepintvl, sizeof(tcp_keepintvl)); +#endif /* __APPLE_CC__ */ + +} + +struct tq_ent { + void *data; + struct list_head q_node; +}; + +#ifdef HAVE_LIBCURL struct timeval nettime; struct data_buffer { @@ -67,11 +107,6 @@ struct header_info { bool hadexpire; }; -struct tq_ent { - void *data; - struct list_head q_node; -}; - static void databuf_free(struct data_buffer *db) { if (!db) @@ -202,36 +237,19 @@ out: return ptrlen; } -static void keep_sockalive(SOCKETTYPE fd) +static void last_nettime(struct timeval *last) { - const int tcp_one = 1; -#ifndef WIN32 - const int tcp_keepidle = 45; - const int tcp_keepintvl = 30; - int flags = fcntl(fd, F_GETFL, 0); - - fcntl(fd, F_SETFL, O_NONBLOCK | flags); -#else - u_long flags = 1; - - ioctlsocket(fd, FIONBIO, &flags); -#endif - - setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const void *)&tcp_one, sizeof(tcp_one)); - if (!opt_delaynet) -#ifndef __linux - setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void *)&tcp_one, sizeof(tcp_one)); -#else /* __linux */ - setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&tcp_one, sizeof(tcp_one)); - setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &tcp_one, sizeof(tcp_one)); - setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &tcp_keepidle, sizeof(tcp_keepidle)); - setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &tcp_keepintvl, sizeof(tcp_keepintvl)); -#endif /* __linux */ - -#ifdef __APPLE_CC__ - setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &tcp_keepintvl, sizeof(tcp_keepintvl)); -#endif /* __APPLE_CC__ */ + rd_lock(&netacc_lock); + last->tv_sec = nettime.tv_sec; + last->tv_usec = nettime.tv_usec; + rd_unlock(&netacc_lock); +} +static void set_nettime(void) +{ + wr_lock(&netacc_lock); + cgtime(&nettime); + wr_unlock(&netacc_lock); } #if CURL_HAS_KEEPALIVE @@ -255,21 +273,6 @@ static void keep_curlalive(CURL *curl) } #endif -static void last_nettime(struct timeval *last) -{ - rd_lock(&netacc_lock); - last->tv_sec = nettime.tv_sec; - last->tv_usec = nettime.tv_usec; - rd_unlock(&netacc_lock); -} - -static void set_nettime(void) -{ - wr_lock(&netacc_lock); - cgtime(&nettime); - wr_unlock(&netacc_lock); -} - static int curl_debug_cb(__maybe_unused CURL *handle, curl_infotype type, __maybe_unused char *data, size_t size, void *userdata) { @@ -513,29 +516,35 @@ err_out: curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1); return NULL; } +#define PROXY_HTTP CURLPROXY_HTTP +#define PROXY_HTTP_1_0 CURLPROXY_HTTP_1_0 +#define PROXY_SOCKS4 CURLPROXY_SOCKS4 +#define PROXY_SOCKS5 CURLPROXY_SOCKS5 +#define PROXY_SOCKS4A CURLPROXY_SOCKS4A +#define PROXY_SOCKS5H CURLPROXY_SOCKS5_HOSTNAME +#else /* HAVE_LIBCURL */ +#define PROXY_HTTP 0 +#define PROXY_HTTP_1_0 1 +#define PROXY_SOCKS4 2 +#define PROXY_SOCKS5 3 +#define PROXY_SOCKS4A 4 +#define PROXY_SOCKS5H 5 +#endif /* HAVE_LIBCURL */ -#if (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 10) || (LIBCURL_VERSION_MAJOR > 7) static struct { const char *name; - curl_proxytype proxytype; + proxytypes_t proxytype; } proxynames[] = { - { "http:", CURLPROXY_HTTP }, -#if (LIBCURL_VERSION_MAJOR > 7) || (LIBCURL_VERSION_MINOR > 19) || (LIBCURL_VERSION_MINOR == 19 && LIBCURL_VERSION_PATCH >= 4) - { "http0:", CURLPROXY_HTTP_1_0 }, -#endif -#if (LIBCURL_VERSION_MAJOR > 7) || (LIBCURL_VERSION_MINOR > 15) || (LIBCURL_VERSION_MINOR == 15 && LIBCURL_VERSION_PATCH >= 2) - { "socks4:", CURLPROXY_SOCKS4 }, -#endif - { "socks5:", CURLPROXY_SOCKS5 }, -#if (LIBCURL_VERSION_MAJOR > 7) || (LIBCURL_VERSION_MINOR >= 18) - { "socks4a:", CURLPROXY_SOCKS4A }, - { "socks5h:", CURLPROXY_SOCKS5_HOSTNAME }, -#endif + { "http:", PROXY_HTTP }, + { "http0:", PROXY_HTTP_1_0 }, + { "socks4:", PROXY_SOCKS4 }, + { "socks5:", PROXY_SOCKS5 }, + { "socks4a:", PROXY_SOCKS4A }, + { "socks5h:", PROXY_SOCKS5H }, { NULL, 0 } }; -#endif -const char *proxytype(curl_proxytype proxytype) +const char *proxytype(proxytypes_t proxytype) { int i; @@ -550,7 +559,6 @@ char *get_proxy(char *url, struct pool *pool) { pool->rpc_proxy = NULL; -#if (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 10) || (LIBCURL_VERSION_MAJOR > 7) char *split; int plen, len, i; @@ -573,7 +581,6 @@ char *get_proxy(char *url, struct pool *pool) break; } } -#endif return url; } @@ -1948,7 +1955,7 @@ static bool setup_stratum_socket(struct pool *pool) if (!pool->rpc_proxy && opt_socks_proxy) { pool->rpc_proxy = opt_socks_proxy; extract_sockaddr(pool->rpc_proxy, &pool->sockaddr_proxy_url, &pool->sockaddr_proxy_port); - pool->rpc_proxytype = CURLPROXY_SOCKS5; + pool->rpc_proxytype = PROXY_SOCKS5; } if (pool->rpc_proxy) { @@ -1995,24 +2002,24 @@ static bool setup_stratum_socket(struct pool *pool) if (pool->rpc_proxy) { switch (pool->rpc_proxytype) { - case CURLPROXY_HTTP_1_0: + case PROXY_HTTP_1_0: if (!http_negotiate(pool, sockd, true)) return false; break; - case CURLPROXY_HTTP: + case PROXY_HTTP: if (!http_negotiate(pool, sockd, false)) return false; break; - case CURLPROXY_SOCKS5: - case CURLPROXY_SOCKS5_HOSTNAME: + case PROXY_SOCKS5: + case PROXY_SOCKS5H: if (!socks5_negotiate(pool, sockd)) return false; break; - case CURLPROXY_SOCKS4: + case PROXY_SOCKS4: if (!socks4_negotiate(pool, sockd, false)) return false; break; - case CURLPROXY_SOCKS4A: + case PROXY_SOCKS4A: if (!socks4_negotiate(pool, sockd, true)) return false; break; diff --git a/util.h b/util.h index 8c864295..96157fa4 100644 --- a/util.h +++ b/util.h @@ -52,6 +52,12 @@ #define JSON_LOADS(str, err_ptr) json_loads((str), (err_ptr)) #endif +#ifdef HAVE_LIBCURL +typedef curl_proxytype proxytypes_t; +#else +typedef int proxytypes_t; +#endif /* HAVE_LIBCURL */ + /* cgminer specific unnamed semaphore implementations to cope with osx not * implementing them. */ #ifdef __APPLE__