Commit 3f50e878a2b1b145f9be9d1777caecef086cc96a

Kano 2013-03-11T10:58:28

USB add --usb options to limit USB device selection v0.1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
diff --git a/README b/README
index 7bb9d3a..4a2c304 100644
--- a/README
+++ b/README
@@ -221,10 +221,57 @@ SCRYPT only options:
 See SCRYPT-README for more information regarding litecoin mining.
 
 
-FPGA mining boards (BitForce, Icarus, ModMiner, Ztex) only options:
+ASIC and FPGA mining boards (BFL ASIC, BitForce, Icarus, ModMiner, Ztex)
+only options:
+
+Cgminer will automatically find all of your BFL ASIC, BitForce FPGAs,
+ModMiner FPGAs or Ztex FPGAs
+The --usb option can restrict how many BFL ASIC, BitForce FPGAs or
+ModMiner FPGAs it finds:
+
+  --usb 1:2,1:3,1:4,1:*
+or
+  --usb BAS:1,BFL:1,MMQ:0
+or
+  --usb :10
+
+You can only use one of the above 3
+
+The first version
+  --usb 1:2,1:3,1:4,1:*
+allows you to select which devices to mine on with a list of USB
+ bus_number:device_address
+All other USB devices will be ignored
+Hotplug will also only look at the devices matching the list specified and
+find nothing new if they are all in use
+You can specify just the USB bus_number to find all devices like 1:*
+which means any devices on USB bus_number 1
+This is useful if you unplug a device then plug it back in the same port,
+it usually reappears with the same bus_number but a different device_address
+
+You can see the list of USB devices on linux with 'sudo lsusb'
+Cgminer will list the USB devices with the '--usb-dump 1' option
+The '--usb-dump N' option with a value of N greater than 1 will dump a lot
+of details about each USB device
+
+The second version
+  --usb BAS:1,BFL:1,MMQ:0
+allows you to specify how many devices to choose based on each device
+driver cgminer has - there are currently 3 USB drivers: BAS, BFL & MMQ
+N.B. you can only specify which device driver to limit, not the type of
+each device, e.g. with BAS:n you can limit how many BFL ASIC devices will
+be checked, but you cannot limit the number of each type of BFL ASIC
+Also note that the MMQ count is the number of MMQ backplanes you have
+not the number of MMQ FPGAs
+
+The third version
+  --usb :10
+means only use a maximum of 10 devices of any supported USB devices
+Once cgminer has 10 devices it will not configure any more and hotplug will
+not scan for any more
+If one of the 10 devices stops working, hotplug - if enabled, as is default
+- will scan normally again until it has 10 devices
 
-cgminer will automatically find your ModMiner, BitForce or Ztex FPGAs
-independent of the --scan-serial options specified below
 
 --scan-serial|-S <arg> Serial port to probe for Icarus mining device
 
diff --git a/cgminer.c b/cgminer.c
index cad7719..7b29b7c 100644
--- a/cgminer.c
+++ b/cgminer.c
@@ -136,7 +136,8 @@ bool opt_disable_pool;
 char *opt_icarus_options = NULL;
 char *opt_icarus_timing = NULL;
 bool opt_worktime;
-#ifdef HAVE_LIBUSB
+#ifdef USE_USBUTILS
+char *opt_usb_select = NULL;
 int opt_usbdump = -1;
 #endif
 
@@ -169,7 +170,7 @@ static int new_threads;
 static int start_devices;
 int hotplug_time = 5;
 
-#ifdef HAVE_LIBUSB
+#ifdef USE_USBUTILS
 pthread_mutex_t cgusb_lock;
 #endif
 
@@ -823,6 +824,15 @@ static char *set_icarus_timing(const char *arg)
 }
 #endif
 
+#ifdef USE_USBUTILS
+static char *set_usb_select(const char *arg)
+{
+	opt_set_charp(arg, &opt_usb_select);
+
+	return NULL;
+}
+#endif
+
 static char *set_null(const char __maybe_unused *arg)
 {
 	return NULL;
@@ -1154,7 +1164,10 @@ static struct opt_table opt_config_table[] = {
 	OPT_WITH_ARG("--user|-u",
 		     set_user, NULL, NULL,
 		     "Username for bitcoin JSON-RPC server"),
-#ifdef HAVE_LIBUSB
+#ifdef USE_USBUTILS
+	OPT_WITH_ARG("--usb",
+		     set_usb_select, NULL, NULL,
+		     "USB device selection"),
 	OPT_WITH_ARG("--usb-dump",
 		     set_int_0_to_10, opt_show_intval, &opt_usbdump,
 		     opt_hidden),
@@ -4088,6 +4101,10 @@ void write_config(FILE *fcfg)
 		fprintf(fcfg, ",\n\"icarus-options\" : \"%s\"", json_escape(opt_icarus_options));
 	if (opt_icarus_timing)
 		fprintf(fcfg, ",\n\"icarus-timing\" : \"%s\"", json_escape(opt_icarus_timing));
+#ifdef USE_USBUTILS
+	if (opt_usb_select)
+		fprintf(fcfg, ",\n\"usb\" : \"%s\"", json_escape(opt_usb_select));
+#endif
 	fputs("\n}\n", fcfg);
 
 	json_escape_free();
@@ -7031,7 +7048,6 @@ int main(int argc, char *argv[])
 		fflush(stderr);
 		quit(1, "libusb_init() failed");
 	}
-	mutex_init(&cgusb_lock);
 #endif
 
 	mutex_init(&hash_lock);
@@ -7119,6 +7135,11 @@ int main(int argc, char *argv[])
 	if (argc != 1)
 		quit(1, "Unexpected extra commandline arguments");
 
+#ifdef USE_USBUTILS
+	mutex_init(&cgusb_lock);
+	usb_initialise();
+#endif
+
 	if (!config_loaded)
 		load_default_config();
 
diff --git a/miner.h b/miner.h
index bd24305..9dceee1 100644
--- a/miner.h
+++ b/miner.h
@@ -197,13 +197,14 @@ static inline int fsync (int fd)
 #endif
 
 enum drv_driver {
-	DRIVER_OPENCL,
+	DRIVER_OPENCL = 0,
 	DRIVER_ICARUS,
 	DRIVER_BITFORCE,
 	DRIVER_MODMINER,
 	DRIVER_ZTEX,
 	DRIVER_CPU,
 	DRIVER_BFLSC,
+	DRIVER_MAX
 };
 
 enum alive {
@@ -718,7 +719,8 @@ extern bool opt_restart;
 extern char *opt_icarus_options;
 extern char *opt_icarus_timing;
 extern bool opt_worktime;
-#ifdef HAVE_LIBUSB
+#ifdef USE_USBUTILS
+extern char *opt_usb_select;
 extern int opt_usbdump;
 #endif
 #ifdef USE_BITFORCE
@@ -751,7 +753,7 @@ extern int opt_queue;
 extern int opt_scantime;
 extern int opt_expiry;
 
-#ifdef HAVE_LIBUSB
+#ifdef USE_USBUTILS
 extern pthread_mutex_t cgusb_lock;
 #endif
 
diff --git a/usbutils.c b/usbutils.c
index 7aed305..c1e5776 100644
--- a/usbutils.c
+++ b/usbutils.c
@@ -9,6 +9,7 @@
 
 #include "config.h"
 
+#include <ctype.h>
 #include <stdint.h>
 #include <stdbool.h>
 
@@ -146,6 +147,24 @@ extern struct device_drv icarus_drv;
 #define STRBUFLEN 256
 static const char *BLANK = "";
 
+// 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;
+} *busdev;
+
+static int busdev_count = 0;
+
+// Total device limit
+static int total_count = 0;
+static int total_limit = 999999;
+
 static bool stats_initialised = false;
 
 struct cg_usb_stats_item {
@@ -894,6 +913,9 @@ static void release_cgpu(struct cgpu_info *cgpu)
 	if (cgpu->usbinfo.nodev)
 		return;
 
+	total_count--;
+	drv_count[cgpu->drv->drv_id].count--;
+
 	cgpu->usbinfo.nodev = true;
 	cgpu->usbinfo.nodev_count++;
 	gettimeofday(&(cgpu->usbinfo.last_nodev), NULL);
@@ -903,6 +925,9 @@ static void release_cgpu(struct cgpu_info *cgpu)
 	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),
@@ -1121,7 +1146,9 @@ dame:
 static bool usb_check_device(struct device_drv *drv, struct libusb_device *dev, struct usb_find_devices *look)
 {
 	struct libusb_device_descriptor desc;
-	int err;
+	int bus_number, device_address;
+	int err, i;
+	bool ok;
 
 	err = libusb_get_device_descriptor(dev, &desc);
 	if (err) {
@@ -1136,6 +1163,27 @@ static bool usb_check_device(struct device_drv *drv, struct libusb_device *dev, 
 		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);
 
@@ -1161,6 +1209,13 @@ static struct usb_find_devices *usb_check_each(int drvnum, struct device_drv *dr
 
 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;
+	}
+
 #ifdef USE_BFLSC
 	if (drv->drv_id == DRIVER_BFLSC)
 		return usb_check_each(DRV_BFLSC, drv, dev);
@@ -1190,7 +1245,19 @@ void usb_detect(struct device_drv *drv, bool (*device_detect)(struct libusb_devi
 	ssize_t count, i;
 	struct usb_find_devices *found;
 
-	cgusb_check_init();
+	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) {
@@ -1202,6 +1269,18 @@ void usb_detect(struct device_drv *drv, bool (*device_detect)(struct libusb_devi
 		applog(LOG_DEBUG, "USB scan devices: found no devices");
 
 	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 (cgminer_usb_lock(drv, list[i]) == false)
@@ -1209,6 +1288,10 @@ void usb_detect(struct device_drv *drv, bool (*device_detect)(struct libusb_devi
 			else {
 				if (!device_detect(list[i], found))
 					cgminer_usb_unlock(drv, list[i]);
+				else {
+					total_count++;
+					drv_count[drv->drv_id].count++;
+				}
 			}
 		}
 	}
@@ -1240,8 +1323,6 @@ struct api_data *api_usb_stats(__maybe_unused int *count)
 	int device;
 	int cmdseq;
 
-	cgusb_check_init();
-
 	if (next_stat == 0)
 		return NULL;
 
@@ -1312,9 +1393,12 @@ static void newstats(struct cgpu_info *cgpu)
 {
 	int i;
 
+	mutex_lock(&cgusb_lock);
 	cgpu->usbinfo.usbstat = ++next_stat;
+	mutex_unlock(&cgusb_lock);
 
 	usb_stats = realloc(usb_stats, sizeof(*usb_stats) * next_stat);
+
 	usb_stats[next_stat-1].name = cgpu->drv->name;
 	usb_stats[next_stat-1].device_id = -1;
 	usb_stats[next_stat-1].details = calloc(1, sizeof(struct cg_usb_stats_details) * C_MAX * 2);
@@ -1584,3 +1668,112 @@ void usb_cleanup()
 		}
 	}
 }
+
+void usb_initialise()
+{
+	char *fre, *ptr, *comma, *colon;
+	int bus, dev, lim, i;
+	bool found;
+
+	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));
+
+				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;
+#ifdef USE_BFLSC
+				if (strcasecmp(ptr, bflsc_drv.name) == 0) {
+					drv_count[bflsrc_drv.drv_id].limit = lim;
+					found = true;
+				}
+#endif
+#ifdef USE_BITFORCE
+				if (!found && strcasecmp(ptr, bitforce_drv.name) == 0) {
+					drv_count[bitforce_drv.drv_id].limit = lim;
+					found = true;
+				}
+#endif
+#ifdef USE_MODMINER
+				if (!found && strcasecmp(ptr, modminer_drv.name) == 0) {
+					drv_count[modminer_drv.drv_id].limit = lim;
+					found = true;
+				}
+#endif
+				if (!found)
+					quit(1, "Invalid --usb DRV:limit - unknown DRV='%s'", ptr);
+
+				ptr = comma;
+			} while (ptr);
+			free(fre);
+		}
+	}
+}
diff --git a/usbutils.h b/usbutils.h
index fc6340f..8a364c9 100644
--- a/usbutils.h
+++ b/usbutils.h
@@ -138,6 +138,7 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro
 int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned 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, unsigned int timeout, enum usb_cmds cmd);
 void usb_cleanup();
+void usb_initialise();
 
 #define usb_read(cgpu, buf, bufsiz, read, cmd) \
 	_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, -1, cmd, false)