Commit 6a7ccd3293c50dc49070291c3c192bb257e492fa

Kano 2014-02-14T15:26:11

Merge remote-tracking branch 'conman/master'

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
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
diff --git a/api.c b/api.c
index 692d0b3..4e0247b 100644
--- a/api.c
+++ b/api.c
@@ -4479,7 +4479,7 @@ void api(int api_thr_id)
 	json_t *json_config = NULL;
 	json_t *json_val;
 	bool isjson;
-	bool did, isjoin, firstjoin;
+	bool did, isjoin = false, firstjoin;
 	int i;
 
 	SOCKETTYPE *apisock;
diff --git a/cgminer.c b/cgminer.c
index cc6e28b..88212be 100644
--- a/cgminer.c
+++ b/cgminer.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2011-2013 Con Kolivas
+ * Copyright 2011-2014 Con Kolivas
  * Copyright 2011-2012 Luke Dashjr
  * Copyright 2010 Jeff Garzik
  *
@@ -1212,7 +1212,7 @@ static struct opt_table opt_config_table[] = {
 		     set_balance, &pool_strategy,
 		     "Change multipool strategy from failover to even share balance"),
 	OPT_WITH_ARG("--benchfile",
-			opt_set_charp, opt_show_charp, &opt_benchfile,
+			opt_set_charp, NULL, &opt_benchfile,
 			"Run cgminer in benchmark mode using a work file - produces no shares"),
 	OPT_WITHOUT_ARG("--benchfile-display",
 			opt_set_bool, &opt_benchfile_display,
@@ -2319,7 +2319,11 @@ static void curses_print_status(void)
 		     prev_block, block_diff, blocktime, best_share);
 	mvwhline(statuswin, 6, 0, '-', 90);
 	mvwhline(statuswin, statusy - 1, 0, '-', 90);
+#ifdef USE_USBUTILS
+	cg_mvwprintw(statuswin, devcursor - 1, 1, "[U]SB device management [P]ool management [S]ettings [D]isplay options [Q]uit");
+#else
 	cg_mvwprintw(statuswin, devcursor - 1, 1, "[P]ool management [S]ettings [D]isplay options [Q]uit");
+#endif
 }
 
 static void adj_width(int var, int *length)
@@ -2336,7 +2340,7 @@ static void adj_fwidth(float var, int *length)
 
 static int dev_width;
 
-static void curses_print_devstatus(struct cgpu_info *cgpu, int count)
+static void curses_print_devstatus(struct cgpu_info *cgpu, int devno, int count)
 {
 	static int dawidth = 1, drwidth = 1, hwwidth = 1, wuwidth = 1;
 	char logline[256];
@@ -2368,7 +2372,7 @@ static void curses_print_devstatus(struct cgpu_info *cgpu, int count)
 	wu = cgpu->diff1 / dev_runtime * 60;
 
 	wmove(statuswin,devcursor + count, 0);
-	cg_wprintw(statuswin, " %s %*d: ", cgpu->drv->name, dev_width, cgpu->device_id);
+	cg_wprintw(statuswin, " %03d: %s %*d: ", devno, cgpu->drv->name, dev_width, cgpu->device_id);
 	logline[0] = '\0';
 	cgpu->drv->get_statline_before(logline, sizeof(logline), cgpu);
 	cg_wprintw(statuswin, "%s", logline);
@@ -5138,6 +5142,162 @@ retry:
 	opt_loginput = false;
 }
 
+#ifdef USE_USBUTILS
+static void mt_enable(struct thr_info *mythr)
+{
+	cgsem_post(&mythr->sem);
+}
+
+static void set_usb(void)
+{
+	int selected, i, mt, enabled = 0, disabled = 0, zombie = 0, total = 0;
+	struct cgpu_info *cgpu;
+	struct thr_info *thr;
+	double val;
+	char input;
+
+	opt_loginput = true;
+	immedok(logwin, true);
+	clear_logwin();
+
+retry:
+	rd_lock(&mining_thr_lock);
+	mt = mining_threads;
+	rd_unlock(&mining_thr_lock);
+
+	for (i = 0; i < mt; i++) {
+		cgpu = mining_thr[i]->cgpu;
+		if (unlikely(!cgpu))
+			continue;
+		if (cgpu->usbinfo.nodev)
+			zombie++;
+		else if  (cgpu->deven == DEV_DISABLED)
+			disabled++;
+		else
+			enabled++;
+		total++;
+	}
+	wlogprint("Hotplug interval:%d\n", hotplug_time);
+	wlogprint("%d USB devices, %d enabled, %d disabled, %d zombie\n",
+		  total, enabled, disabled, zombie);
+	wlogprint("[S]ummary of device information\n");
+	wlogprint("[E]nable device\n");
+	wlogprint("[D]isable device\n");
+	wlogprint("[U]nplug to allow hotplug restart\n");
+	wlogprint("[R]eset device USB\n");
+	wlogprint("[L]ist all known devices\n");
+	wlogprint("[B]lacklist current device from cgminer\n");
+	wlogprint("Select an option or any other key to return\n");
+	logwin_update();
+	input = getch();
+
+	if (!strncasecmp(&input, "s", 1)) {
+		selected = curses_int("Select device number");
+		if (selected < 0 || selected >= mt)  {
+			wlogprint("Invalid selection\n");
+			goto retry;
+		}
+		cgpu = mining_thr[selected]->cgpu;
+		wlogprint("Device %03u:%03u\n", cgpu->usbinfo.bus_number, cgpu->usbinfo.device_address);
+		wlogprint("Name %s\n", cgpu->drv->name);
+		wlogprint("ID %d\n", cgpu->device_id);
+		wlogprint("Enabled: %s\n", cgpu->deven != DEV_DISABLED ? "Yes" : "No");
+		wlogprint("Temperature %.1f\n", cgpu->temp);
+		wlogprint("MHS av %.0f\n", cgpu->total_mhashes / cgpu_runtime(cgpu));
+		wlogprint("Accepted %d\n", cgpu->accepted);
+		wlogprint("Rejected %d\n", cgpu->rejected);
+		wlogprint("Hardware Errors %d\n", cgpu->hw_errors);
+		wlogprint("Last Share Pool %d\n", cgpu->last_share_pool_time > 0 ? cgpu->last_share_pool : -1);
+		wlogprint("Total MH %.1f\n", cgpu->total_mhashes);
+		wlogprint("Diff1 Work %d\n", cgpu->diff1);
+		wlogprint("Difficulty Accepted %.1f\n", cgpu->diff_accepted);
+		wlogprint("Difficulty Rejected %.1f\n", cgpu->diff_rejected);
+		wlogprint("Last Share Difficulty %.1f\n", cgpu->last_share_diff);
+		wlogprint("No Device: %s\n", cgpu->usbinfo.nodev ? "True" : "False");
+		wlogprint("Last Valid Work %"PRIu64"\n", (uint64_t)cgpu->last_device_valid_work);
+		val = 0;
+		if (cgpu->hw_errors + cgpu->diff1)
+			val = cgpu->hw_errors / (cgpu->hw_errors + cgpu->diff1);
+		wlogprint("Device Hardware %.1f%%\n", val);
+		val = 0;
+		if (cgpu->diff1)
+			val = cgpu->diff_rejected / cgpu->diff1;
+		wlogprint("Device Rejected %.1f%%\n", val);
+		goto retry;
+	} else if (!strncasecmp(&input, "e", 1)) {
+		selected = curses_int("Select device number");
+		if (selected < 0 || selected >= mt)  {
+			wlogprint("Invalid selection\n");
+			goto retry;
+		}
+		cgpu = mining_thr[selected]->cgpu;
+		if (cgpu->usbinfo.nodev) {
+			wlogprint("Device removed, unable to re-enable!\n");
+			goto retry;
+		}
+		thr = get_thread(selected);
+		cgpu->deven = DEV_ENABLED;
+		mt_enable(thr);
+		goto retry;
+	} else if (!strncasecmp(&input, "d", 1)) {
+		selected = curses_int("Select device number");
+		if (selected < 0 || selected >= mt)  {
+			wlogprint("Invalid selection\n");
+			goto retry;
+		}
+		cgpu = mining_thr[selected]->cgpu;
+		cgpu->deven = DEV_DISABLED;
+		goto retry;
+	} else if (!strncasecmp(&input, "u", 1)) {
+		selected = curses_int("Select device number");
+		if (selected < 0 || selected >= mt)  {
+			wlogprint("Invalid selection\n");
+			goto retry;
+		}
+		cgpu = mining_thr[selected]->cgpu;
+		if (cgpu->usbinfo.nodev) {
+			wlogprint("Device already removed, unable to unplug!\n");
+			goto retry;
+		}
+		usb_nodev(cgpu);
+		goto retry;
+	} else if (!strncasecmp(&input, "r", 1)) {
+		selected = curses_int("Select device number");
+		if (selected < 0 || selected >= mt)  {
+			wlogprint("Invalid selection\n");
+			goto retry;
+		}
+		cgpu = mining_thr[selected]->cgpu;
+		if (cgpu->usbinfo.nodev) {
+			wlogprint("Device already removed, unable to reset!\n");
+			goto retry;
+		}
+		usb_reset(cgpu);
+		goto retry;
+	} else if (!strncasecmp(&input, "b", 1)) {
+		selected = curses_int("Select device number");
+		if (selected < 0 || selected >= mt)  {
+			wlogprint("Invalid selection\n");
+			goto retry;
+		}
+		cgpu = mining_thr[selected]->cgpu;
+		if (cgpu->usbinfo.nodev) {
+			wlogprint("Device already removed, unable to blacklist!\n");
+			goto retry;
+		}
+		blacklist_cgpu(cgpu);
+		goto retry;
+	} else if (!strncasecmp(&input, "l", 1)) {
+		usb_all(0);
+		goto retry;
+	} else
+		clear_logwin();
+
+	immedok(logwin, false);
+	opt_loginput = false;
+}
+#endif
+
 static void *input_thread(void __maybe_unused *userdata)
 {
 	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
@@ -5160,6 +5320,10 @@ static void *input_thread(void __maybe_unused *userdata)
 			display_pools();
 		else if (!strncasecmp(&input, "s", 1))
 			set_options();
+#ifdef USE_USBUTILS
+		else if (!strncasecmp(&input, "u", 1))
+			set_usb();
+#endif
 		if (opt_realquiet) {
 			disable_curses();
 			break;
@@ -7320,13 +7484,13 @@ static void *watchdog_thread(void __maybe_unused *userdata)
 #else
 				if (cgpu && !cgpu->usbinfo.nodev)
 #endif
-					curses_print_devstatus(cgpu, count++);
+					curses_print_devstatus(cgpu, i, count++);
 			}
 #ifdef USE_USBUTILS
 			for (i = 0; i < total_devices; i++) {
 				cgpu = get_devices(i);
 				if (cgpu && cgpu->usbinfo.nodev)
-					curses_print_devstatus(cgpu, count++);
+					curses_print_devstatus(cgpu, i, count++);
 			}
 #endif
 			touchwin(statuswin);
diff --git a/driver-avalon.c b/driver-avalon.c
index bb6121e..3f862ed 100644
--- a/driver-avalon.c
+++ b/driver-avalon.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013 Con Kolivas <kernel@kolivas.org>
+ * Copyright 2013-2014 Con Kolivas <kernel@kolivas.org>
  * Copyright 2012-2013 Xiangfu <xiangfu@openmobilefree.com>
  * Copyright 2012 Luke Dashjr
  * Copyright 2012 Andrew Smith
@@ -843,7 +843,6 @@ static struct cgpu_info *avalon_detect_one(libusb_device *dev, struct usb_find_d
 	}
 
 	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 * (AVALON_A3256 / info->asic) * ((float)1.67/0x32))) + 1;
@@ -1344,8 +1343,11 @@ static bool avalon_prepare(struct thr_info *thr)
 	return true;
 }
 
-static inline void record_temp_fan(struct avalon_info *info, struct avalon_result *ar, float *temp_avg)
+static inline void record_temp_fan(struct cgpu_info *avalon, struct avalon_info *info,
+				   struct avalon_result *ar)
 {
+	double temp_max;
+
 	info->fan0 = ar->fan0 * AVALON_FAN_FACTOR;
 	info->fan1 = ar->fan1 * AVALON_FAN_FACTOR;
 	info->fan2 = ar->fan2 * AVALON_FAN_FACTOR;
@@ -1366,14 +1368,12 @@ static inline void record_temp_fan(struct avalon_info *info, struct avalon_resul
 		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;
+	temp_max = info->temp0;
+	if (info->temp1 > temp_max)
+		temp_max = info->temp1;
+	if (info->temp2 > temp_max)
+		temp_max = info->temp2;
+	avalon->temp = avalon->temp * 0.63 + temp_max * 0.37;
 }
 
 static void temp_rise(struct avalon_info *info, int temp)
@@ -1439,12 +1439,12 @@ static inline void adjust_fan(struct avalon_info *info)
 static void avalon_update_temps(struct cgpu_info *avalon, struct avalon_info *info,
 				struct avalon_result *ar)
 {
-	record_temp_fan(info, ar, &(avalon->temp));
+	record_temp_fan(avalon, info, ar);
 	applog(LOG_INFO,
 		"Avalon: Fan1: %d/m, Fan2: %d/m, Fan3: %d/m\t"
-		"Temp1: %dC, Temp2: %dC, Temp3: %dC, TempMAX: %dC",
+		"Temp1: %dC, Temp2: %dC, Temp3: %dC, TempMAX: %.0fC",
 		info->fan0, info->fan1, info->fan2,
-		info->temp0, info->temp1, info->temp2, info->temp_max);
+		info->temp0, info->temp1, info->temp2, avalon->temp);
 	info->temp_history_index++;
 	info->temp_sum += avalon->temp;
 	applog(LOG_DEBUG, "Avalon: temp_index: %d, temp_count: %d, temp_old: %d",
@@ -1603,7 +1603,7 @@ static struct api_data *avalon_api_stats(struct cgpu_info *cgpu)
 	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_double(root, "temp_max", &cgpu->temp, false);
 
 	root = api_add_percent(root, "Device Hardware%", &hwp, true);
 	root = api_add_int(root, "no_matching_work", &(info->no_matching_work), false);
diff --git a/driver-avalon.h b/driver-avalon.h
index e2b944d..c718366 100644
--- a/driver-avalon.h
+++ b/driver-avalon.h
@@ -1,6 +1,6 @@
 /*
  * Copyright 2013 Avalon project
- * Copyright 2013 Con Kolivas <kernel@kolivas.org>
+ * Copyright 2013-2014 Con Kolivas <kernel@kolivas.org>
  *
  * 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
@@ -128,7 +128,6 @@ struct avalon_info {
 	int temp0;
 	int temp1;
 	int temp2;
-	int temp_max;
 	int temp_history_count;
 	int temp_history_index;
 	int temp_sum;
diff --git a/driver-bitfury.c b/driver-bitfury.c
index 9ff7cc1..17da3e2 100644
--- a/driver-bitfury.c
+++ b/driver-bitfury.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013 Con Kolivas
+ * Copyright 2013-2014 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
@@ -562,7 +562,7 @@ static void parse_bxf_temp(struct cgpu_info *bitfury, struct bitfury_info *info,
 	}
 
 	mutex_lock(&info->lock);
-	info->temperature = (double)decitemp / 10;
+	bitfury->temp = (double)decitemp / 10;
 	if (decitemp > info->max_decitemp) {
 		info->max_decitemp = decitemp;
 		applog(LOG_DEBUG, "%s %d: New max decitemp %d", bitfury->drv->name,
@@ -1039,7 +1039,7 @@ static struct api_data *bf1_api_stats(struct bitfury_info *info)
 	return root;
 }
 
-static struct api_data *bxf_api_stats(struct bitfury_info *info)
+static struct api_data *bxf_api_stats(struct cgpu_info *bitfury, struct bitfury_info *info)
 {
 	struct api_data *root = NULL;
 	double nonce_rate;
@@ -1052,7 +1052,7 @@ static struct api_data *bxf_api_stats(struct bitfury_info *info)
 	nonce_rate = (double)info->total_nonces / (double)info->cycles;
 	root = api_add_double(root, "NonceRate", &nonce_rate, true);
 	root = api_add_int(root, "NoMatchingWork", &info->no_matching_work, false);
-	root = api_add_double(root, "Temperature", &info->temperature, false);
+	root = api_add_double(root, "Temperature", &bitfury->temp, false);
 	root = api_add_int(root, "Max DeciTemp", &info->max_decitemp, false);
 	root = api_add_uint8(root, "Clock", &info->clocks, false);
 	root = api_add_int(root, "Core0 hwerror", &info->filtered_hw[0], false);
@@ -1074,7 +1074,7 @@ static struct api_data *bitfury_api_stats(struct cgpu_info *cgpu)
 			return bf1_api_stats(info);
 			break;
 		case IDENT_BXF:
-			return bxf_api_stats(info);
+			return bxf_api_stats(cgpu, info);
 			break;
 		default:
 			break;
@@ -1088,7 +1088,7 @@ static void bitfury_get_statline_before(char *buf, size_t bufsiz, struct cgpu_in
 
 	switch(info->ident) {
 		case IDENT_BXF:
-			tailsprintf(buf, bufsiz, "%5.1fC         | ", info->temperature);
+			tailsprintf(buf, bufsiz, "%5.1fC         | ", cgpu->temp);
 			break;
 		case IDENT_BF1:
 		default:
diff --git a/driver-bitfury.h b/driver-bitfury.h
index d3a3435..2257ecf 100644
--- a/driver-bitfury.h
+++ b/driver-bitfury.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013 Con Kolivas
+ * Copyright 2013-2014 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
@@ -61,7 +61,6 @@ struct bitfury_info {
 	/* BXF specific data */
 	pthread_mutex_t lock;
 	pthread_t read_thr;
-	double temperature;
 	int last_decitemp;
 	int max_decitemp;
 	int temp_target;
diff --git a/driver-cointerra.c b/driver-cointerra.c
index 27993d8..48fcccf 100644
--- a/driver-cointerra.c
+++ b/driver-cointerra.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013 Con Kolivas <kernel@kolivas.org>
+ * Copyright 2013-2014 Con Kolivas <kernel@kolivas.org>
  *
  * 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
@@ -435,8 +435,12 @@ static void u16array_from_msg(uint16_t *u16, int entries, int var, char *buf)
 		u16[i] = hu16_from_msg(buf, var + j);
 }
 
-static void cta_parse_statread(struct cointerra_info *info, char *buf)
+static void cta_parse_statread(struct cgpu_info *cointerra, struct cointerra_info *info,
+			       char *buf)
 {
+	float max_temp = 0;
+	int i;
+
 	mutex_lock(&info->lock);
 	u16array_from_msg(info->coretemp, CTA_CORES, CTA_STAT_CORETEMPS, buf);
 	info->ambtemp_low = hu16_from_msg(buf, CTA_STAT_AMBTEMP_LOW);
@@ -450,6 +454,15 @@ static void cta_parse_statread(struct cointerra_info *info, char *buf)
 	info->inactive = hu16_from_msg(buf, CTA_STAT_INACTIVE);
 	info->active = hu16_from_msg(buf, CTA_STAT_ACTIVE);
 	mutex_unlock(&info->lock);
+
+	for (i = 0; i < CTA_CORES; i++) {
+		if (info->coretemp[i] > max_temp)
+			max_temp = info->coretemp[i];
+	}
+	max_temp /= 100.0;
+	/* Store the max temperature in the cgpu struct as an exponentially
+	 * changing value. */
+	cointerra->temp = cointerra->temp * 0.63 + max_temp * 0.37;
 }
 
 static void u8array_from_msg(uint8_t *u8, int entries, int var, char *buf)
@@ -561,7 +574,7 @@ static void cta_parse_msg(struct thr_info *thr, struct cgpu_info *cointerra,
 		case CTA_RECV_STATREAD:
 			applog(LOG_DEBUG, "%s %d: Status readings message received",
 			       cointerra->drv->name, cointerra->device_id);
-			cta_parse_statread(info, buf);
+			cta_parse_statread(cointerra, info, buf);
 			break;
 		case CTA_RECV_STATSET:
 			applog(LOG_DEBUG, "%s %d: Status settings message received",
@@ -1074,21 +1087,18 @@ static struct api_data *cta_api_stats(struct cgpu_info *cgpu)
 static void cta_statline_before(char *buf, size_t bufsiz, struct cgpu_info *cointerra)
 {
 	struct cointerra_info *info = cointerra->device_data;
-	double max_temp = 0, max_volt = 0;
+	double max_volt = 0;
 	int freq = 0, i;
 
 	for (i = 0; i < CTA_CORES; i++) {
-		if (info->coretemp[i] > max_temp)
-			max_temp = info->coretemp[i];
 		if (info->corevolts[i] > max_volt)
 			max_volt = info->corevolts[i];
 		if (info->corefreqs[i] > freq)
 			freq = info->corefreqs[i];
 	}
-	max_temp /= 100;
 	max_volt /= 100;
 
-	tailsprintf(buf, bufsiz, "%3d %3.1fC %2.1fV | ", freq, max_temp, max_volt);
+	tailsprintf(buf, bufsiz, "%3d %3.1fC %2.1fV | ", freq, cointerra->temp, max_volt);
 }
 
 struct device_drv cointerra_drv = {
diff --git a/driver-cointerra.h b/driver-cointerra.h
index 5205f7c..9bab1a5 100644
--- a/driver-cointerra.h
+++ b/driver-cointerra.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013 Con Kolivas <kernel@kolivas.org>
+ * Copyright 2013-2014 Con Kolivas <kernel@kolivas.org>
  *
  * 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
diff --git a/driver-hashfast.c b/driver-hashfast.c
index b313179..9313873 100644
--- a/driver-hashfast.c
+++ b/driver-hashfast.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013 Con Kolivas <kernel@kolivas.org>
+ * Copyright 2013-2014 Con Kolivas <kernel@kolivas.org>
  * Copyright 2013 Hashfast Inc.
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -752,15 +752,14 @@ static void hfa_update_die_status(struct cgpu_info *hashfast, struct hashfast_in
 				die_temperature = info->die_data[die].temp;
 		}
 		/* Exponentially change the max_temp to smooth out troughs. */
-		info->max_temp = info->max_temp * 0.63 + die_temperature * 0.37;
-		hashfast->temp = info->max_temp;
+		hashfast->temp = hashfast->temp * 0.63 + die_temperature * 0.37;
 	}
 
-	if (unlikely(info->max_temp >= opt_hfa_overheat)) {
+	if (unlikely(hashfast->temp >= opt_hfa_overheat)) {
 		/* -1 means new overheat condition */
 		if (!info->overheat)
 			info->overheat = -1;
-	} else if (unlikely(info->overheat && info->max_temp < opt_hfa_overheat - HFA_TEMP_HYSTERESIS))
+	} else if (unlikely(info->overheat && hashfast->temp < opt_hfa_overheat - HFA_TEMP_HYSTERESIS))
 		info->overheat = 0;
 }
 
@@ -1009,7 +1008,7 @@ static int hfa_jobs(struct cgpu_info *hashfast, struct hashfast_info *info)
 		/* Acknowledge and notify of new condition.*/
 		if (info->overheat < 0) {
 			applog(LOG_WARNING, "%s %d: Hit overheat temp %.1f, throttling!",
-			       hashfast->drv->name, hashfast->device_id, info->max_temp);
+			       hashfast->drv->name, hashfast->device_id, hashfast->temp);
 			/* Value of 1 means acknowledged overheat */
 			info->overheat = 1;
 		}
@@ -1156,13 +1155,13 @@ static void hfa_temp_clock(struct cgpu_info *hashfast, struct hashfast_info *inf
 	if (info->temp_updates < 5)
 		goto dies_only;
 	info->temp_updates = 0;
-	temp_change = info->max_temp - info->last_max_temp;
-	info->last_max_temp = info->max_temp;
+	temp_change = hashfast->temp - info->last_max_temp;
+	info->last_max_temp = hashfast->temp;
 
 	/* Adjust fanspeeds first if possible before die speeds, increasing
 	 * speed quickly and lowering speed slowly */
-	if (info->max_temp > opt_hfa_target ||
-	    (throttled && info->max_temp >= opt_hfa_target - HFA_TEMP_HYSTERESIS)) {
+	if (hashfast->temp > opt_hfa_target ||
+	    (throttled && hashfast->temp >= opt_hfa_target - HFA_TEMP_HYSTERESIS)) {
 		/* We should be trying to decrease temperature, if it's not on
 		 * its way down. */
 		if (info->fanspeed < opt_hfa_fan_max) {
@@ -1171,7 +1170,7 @@ static void hfa_temp_clock(struct cgpu_info *hashfast, struct hashfast_info *inf
 			else if (temp_change > 0)
 				hfa_set_fanspeed(hashfast, info, 10);
 		}
-	} else if (info->max_temp >= opt_hfa_target - HFA_TEMP_HYSTERESIS) {
+	} else if (hashfast->temp >= opt_hfa_target - HFA_TEMP_HYSTERESIS) {
 		/* In optimal range, try and maintain the same temp */
 		if (temp_change > 0) {
 			/* Temp rising, tweak fanspeed up */
@@ -1488,7 +1487,7 @@ static void hfa_statline_before(char *buf, size_t bufsiz, struct cgpu_info *hash
 		}
 	}
 
-	tailsprintf(buf, bufsiz, " max%3.0fC %3.2fV | ", info->max_temp, max_volt);
+	tailsprintf(buf, bufsiz, " max%3.0fC %3.2fV | ", hashfast->temp, max_volt);
 }
 
 static void hfa_init(struct cgpu_info __maybe_unused *hashfast)
diff --git a/driver-hashfast.h b/driver-hashfast.h
index 7e160b6..9a2aa61 100644
--- a/driver-hashfast.h
+++ b/driver-hashfast.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013 Con Kolivas <kernel@kolivas.org>
+ * Copyright 2013-2014 Con Kolivas <kernel@kolivas.org>
  * Copyright 2013 Hashfast
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -125,7 +125,6 @@ struct hashfast_info {
 	int no_matching_work;
 	int resets;
 	int overheat;
-	double max_temp;
 	int last_max_temp;
 	int temp_updates;
 	int fanspeed;                               // Fanspeed in percent
diff --git a/driver-icarus.c b/driver-icarus.c
index 49a61a7..b441078 100644
--- a/driver-icarus.c
+++ b/driver-icarus.c
@@ -1,7 +1,7 @@
 /*
  * Copyright 2012-2013 Andrew Smith
  * Copyright 2012 Xiangfu <xiangfu@openmobilefree.com>
- * Copyright 2013 Con Kolivas <kernel@kolivas.org>
+ * Copyright 2013-2014 Con Kolivas <kernel@kolivas.org>
  *
  * 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
diff --git a/miner.h b/miner.h
index cfbf836..dc12443 100644
--- a/miner.h
+++ b/miner.h
@@ -472,7 +472,7 @@ struct cgpu_info {
 
 	bool new_work;
 
-	float temp;
+	double temp;
 	int cutofftemp;
 
 	int diff1;
diff --git a/usbutils.c b/usbutils.c
index a940f1b..325a18a 100644
--- a/usbutils.c
+++ b/usbutils.c
@@ -1,6 +1,6 @@
 /*
  * Copyright 2012-2013 Andrew Smith
- * Copyright 2013 Con Kolivas <kernel@kolivas.org>
+ * Copyright 2013-2014 Con Kolivas <kernel@kolivas.org>
  *
  * 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
@@ -636,6 +636,7 @@ struct usb_in_use_list {
 
 // List of in use devices
 static struct usb_in_use_list *in_use_head = NULL;
+static struct usb_in_use_list *blacklist_head = NULL;
 
 struct resource_work {
 	bool lock;
@@ -1243,6 +1244,15 @@ static bool __is_in_use(uint8_t bus_number, uint8_t device_address)
 		}
 		in_use_tmp = in_use_tmp->next;
 	}
+	in_use_tmp = blacklist_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;
 }
@@ -1262,16 +1272,20 @@ 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)
+static void add_in_use(uint8_t bus_number, uint8_t device_address, bool blacklist)
 {
-	struct usb_in_use_list *in_use_tmp;
+	struct usb_in_use_list *in_use_tmp, **head;
 	bool found = false;
 
 	mutex_lock(&cgusb_lock);
-	if (unlikely(__is_in_use(bus_number, device_address))) {
+	if (unlikely(!blacklist && __is_in_use(bus_number, device_address))) {
 		found = true;
 		goto nofway;
 	}
+	if (blacklist)
+		head = &blacklist_head;
+	else
+		head = &in_use_head;
 
 	in_use_tmp = calloc(1, sizeof(*in_use_tmp));
 	if (unlikely(!in_use_tmp))
@@ -1279,9 +1293,9 @@ static void add_in_use(uint8_t bus_number, uint8_t device_address)
 	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;
+	if (*head)
+		(*head)->prev = in_use_tmp;
+	*head = in_use_tmp;
 nofway:
 	mutex_unlock(&cgusb_lock);
 
@@ -1478,7 +1492,7 @@ void usb_uninit(struct cgpu_info *cgpu)
 /* 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)
+static bool __release_cgpu(struct cgpu_info *cgpu)
 {
 	struct cg_usb_device *cgusb = cgpu->usbdev;
 	bool initted = cgpu->usbinfo.initialised;
@@ -1487,7 +1501,7 @@ static void release_cgpu(struct cgpu_info *cgpu)
 
 	// It has already been done
 	if (cgpu->usbinfo.nodev)
-		return;
+		return false;
 
 	applog(LOG_DEBUG, "USB release %s%i",
 			cgpu->drv->name, cgpu->device_id);
@@ -1520,7 +1534,20 @@ 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);
+	return true;
+}
+
+static void release_cgpu(struct cgpu_info *cgpu)
+{
+	if (__release_cgpu(cgpu))
+		cgminer_usb_unlock_bd(cgpu->drv, cgpu->usbinfo.bus_number, cgpu->usbinfo.device_address);
+}
+
+void blacklist_cgpu(struct cgpu_info *cgpu)
+{
+	if (__release_cgpu(cgpu))
+		cgminer_usb_unlock_bd(cgpu->drv, cgpu->usbinfo.bus_number, cgpu->usbinfo.device_address);
+	add_in_use(cgpu->usbinfo.bus_number, cgpu->usbinfo.device_address, true);
 }
 
 /*
@@ -2623,6 +2650,24 @@ err_retry:
 	return err;
 }
 
+void usb_reset(struct cgpu_info *cgpu)
+{
+	int pstate, err = 0;
+
+	DEVRLOCK(cgpu, pstate);
+	if (!cgpu->usbinfo.nodev) {
+		err = libusb_reset_device(cgpu->usbdev->handle);
+		applog(LOG_WARNING, "%s %i attempted reset got err:(%d) %s",
+			cgpu->drv->name, cgpu->device_id, err, libusb_error_name(err));
+	}
+	if (NODEV(err)) {
+		cg_ruwlock(&cgpu->usbinfo.devlock);
+		release_cgpu(cgpu);
+		DEVWUNLOCK(cgpu, pstate);
+	} else
+		DEVRUNLOCK(cgpu, pstate);
+}
+
 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)
 {
@@ -3508,7 +3553,7 @@ static bool resource_lock(const char *dname, uint8_t bus_number, uint8_t device_
 			goto fail;
 	}
 
-	add_in_use(bus_number, device_address);
+	add_in_use(bus_number, device_address, false);
 	in_use_store_ress(bus_number, device_address, (void *)usbMutex, (void *)sec);
 
 	return true;
@@ -3604,7 +3649,7 @@ fail:
 		goto free_out;
 	}
 
-	add_in_use(bus_number, device_address);
+	add_in_use(bus_number, device_address, false);
 	in_use_store_ress(bus_number, device_address, (void *)key, (void *)sem);
 	return true;
 
diff --git a/usbutils.h b/usbutils.h
index d53d98e..5802943 100644
--- a/usbutils.h
+++ b/usbutils.h
@@ -1,6 +1,6 @@
 /*
  * Copyright 2012-2013 Andrew Smith
- * Copyright 2013 Con Kolivas <kernel@kolivas.org>
+ * Copyright 2013-2014 Con Kolivas <kernel@kolivas.org>
  *
  * 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
@@ -420,6 +420,7 @@ 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 blacklist_cgpu(struct cgpu_info *cgpu);
 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);
@@ -429,6 +430,7 @@ bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find
 void usb_detect(struct device_drv *drv, struct cgpu_info *(*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);
+void usb_reset(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);