Browse Source

Merge pull request #456 from kanoi/master

cps and usbdev locking
kanoi 12 years ago
parent
commit
4e16560749
7 changed files with 247 additions and 37 deletions
  1. 1 1
      FPGA-README
  2. 13 4
      api.c
  3. 1 1
      driver-bflsc.c
  4. 38 31
      driver-icarus.c
  5. 3 0
      driver-modminer.c
  6. 177 0
      usbutils.c
  7. 14 0
      usbutils.h

+ 1 - 1
FPGA-README

@@ -9,7 +9,7 @@ When mining on windows, the driver being used will determine if mining will work
 
 
 If the driver doesn't allow mining, you will get a "USB init," error message
 If the driver doesn't allow mining, you will get a "USB init," error message
 i.e. one of:
 i.e. one of:
- open device failed, err %d, you need to install a Windows USB driver for the device
+ open device failed, err %d, you need to install a WinUSB driver for the device
 or
 or
  claim interface %d failed, err %d
  claim interface %d failed, err %d
 
 

+ 13 - 4
api.c

@@ -3023,10 +3023,10 @@ static int itemstats(struct io_data *io_data, int i, char *id, struct cgminer_st
 
 
 	if (cgpu) {
 	if (cgpu) {
 #ifdef USE_USBUTILS
 #ifdef USE_USBUTILS
-		char pipe_details[128];
+		char details[128];
 
 
 		if (cgpu->usbinfo.pipe_count)
 		if (cgpu->usbinfo.pipe_count)
-			snprintf(pipe_details, sizeof(pipe_details),
+			snprintf(details, sizeof(details),
 				 "%"PRIu64" %"PRIu64"/%"PRIu64"/%"PRIu64" %lu",
 				 "%"PRIu64" %"PRIu64"/%"PRIu64"/%"PRIu64" %lu",
 				 cgpu->usbinfo.pipe_count,
 				 cgpu->usbinfo.pipe_count,
 				 cgpu->usbinfo.clear_err_count,
 				 cgpu->usbinfo.clear_err_count,
@@ -3034,9 +3034,18 @@ static int itemstats(struct io_data *io_data, int i, char *id, struct cgminer_st
 				 cgpu->usbinfo.clear_fail_count,
 				 cgpu->usbinfo.clear_fail_count,
 				 (unsigned long)(cgpu->usbinfo.last_pipe));
 				 (unsigned long)(cgpu->usbinfo.last_pipe));
 		else
 		else
-			strcpy(pipe_details, "0");
+			strcpy(details, "0");
 
 
-		root = api_add_string(root, "USB Pipe", pipe_details, true);
+		root = api_add_string(root, "USB Pipe", details, true);
+
+		snprintf(details, sizeof(details),
+			 "r%"PRIu64" %.6f w%"PRIu64" %.6f",
+			 cgpu->usbinfo.read_delay_count,
+			 cgpu->usbinfo.total_read_delay,
+			 cgpu->usbinfo.write_delay_count,
+			 cgpu->usbinfo.total_write_delay);
+
+		root = api_add_string(root, "USB Delay", details, true);
 #endif
 #endif
 	}
 	}
 
 

+ 1 - 1
driver-bflsc.c

@@ -157,8 +157,8 @@ struct bflsc_info {
 
 
 struct DataForwardToChain {
 struct DataForwardToChain {
 	uint8_t header;
 	uint8_t header;
-	uint8_t deviceAddress;
 	uint8_t payloadSize;
 	uint8_t payloadSize;
+	uint8_t deviceAddress;
 	uint8_t payloadData[BFLSC_MAXPAYLOAD];
 	uint8_t payloadData[BFLSC_MAXPAYLOAD];
 };
 };
 
 

+ 38 - 31
driver-icarus.c

@@ -251,18 +251,28 @@ static void _transfer(struct cgpu_info *icarus, uint8_t request_type, uint8_t bR
 static void icarus_initialise(struct cgpu_info *icarus, int baud)
 static void icarus_initialise(struct cgpu_info *icarus, int baud)
 {
 {
 	uint16_t wValue, wIndex;
 	uint16_t wValue, wIndex;
+	enum sub_ident ident;
+	int interface;
 
 
 	if (icarus->usbinfo.nodev)
 	if (icarus->usbinfo.nodev)
 		return;
 		return;
 
 
-	switch (icarus->usbdev->ident) {
+	usb_set_cps(icarus, baud / 10);
+	usb_enable_cps(icarus);
+
+	interface = usb_interface(icarus);
+	ident = usb_ident(icarus);
+
+	switch (ident) {
 		case IDENT_BLT:
 		case IDENT_BLT:
 		case IDENT_LLT:
 		case IDENT_LLT:
 		case IDENT_CMR1:
 		case IDENT_CMR1:
 		case IDENT_CMR2:
 		case IDENT_CMR2:
+			usb_set_pps(icarus, BLT_PREF_PACKET);
+
 			// Reset
 			// Reset
 			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_RESET,
 			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_RESET,
-				 icarus->usbdev->found->interface, C_RESET);
+				 interface, C_RESET);
 
 
 			if (icarus->usbinfo.nodev)
 			if (icarus->usbinfo.nodev)
 				return;
 				return;
@@ -275,7 +285,7 @@ static void icarus_initialise(struct cgpu_info *icarus, int baud)
 
 
 			// Set data control
 			// Set data control
 			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_DATA, FTDI_VALUE_DATA_BLT,
 			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_DATA, FTDI_VALUE_DATA_BLT,
-				 icarus->usbdev->found->interface, C_SETDATA);
+				 interface, C_SETDATA);
 
 
 			if (icarus->usbinfo.nodev)
 			if (icarus->usbinfo.nodev)
 				return;
 				return;
@@ -284,8 +294,7 @@ static void icarus_initialise(struct cgpu_info *icarus, int baud)
 			wValue = FTDI_VALUE_BAUD_BLT;
 			wValue = FTDI_VALUE_BAUD_BLT;
 			wIndex = FTDI_INDEX_BAUD_BLT;
 			wIndex = FTDI_INDEX_BAUD_BLT;
 
 
-			if (icarus->usbdev->ident == IDENT_CMR1 ||
-			    icarus->usbdev->ident == IDENT_CMR2) {
+			if (ident == IDENT_CMR1 || ident == IDENT_CMR2) {
 				switch (baud) {
 				switch (baud) {
 					case 115200:
 					case 115200:
 						wValue = FTDI_VALUE_BAUD_CMR_115;
 						wValue = FTDI_VALUE_BAUD_CMR_115;
@@ -303,43 +312,42 @@ static void icarus_initialise(struct cgpu_info *icarus, int baud)
 
 
 			// Set the baud
 			// Set the baud
 			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, wValue,
 			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, wValue,
-				 (wIndex & 0xff00) | icarus->usbdev->found->interface,
-				 C_SETBAUD);
+				 (wIndex & 0xff00) | interface, C_SETBAUD);
 
 
 			if (icarus->usbinfo.nodev)
 			if (icarus->usbinfo.nodev)
 				return;
 				return;
 
 
 			// Set Modem Control
 			// Set Modem Control
 			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_MODEM, FTDI_VALUE_MODEM,
 			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_MODEM, FTDI_VALUE_MODEM,
-				 icarus->usbdev->found->interface, C_SETMODEM);
+				 interface, C_SETMODEM);
 
 
 			if (icarus->usbinfo.nodev)
 			if (icarus->usbinfo.nodev)
 				return;
 				return;
 
 
 			// Set Flow Control
 			// Set Flow Control
 			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_FLOW, FTDI_VALUE_FLOW,
 			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_FLOW, FTDI_VALUE_FLOW,
-				 icarus->usbdev->found->interface, C_SETFLOW);
+				 interface, C_SETFLOW);
 
 
 			if (icarus->usbinfo.nodev)
 			if (icarus->usbinfo.nodev)
 				return;
 				return;
 
 
 			// Clear any sent data
 			// Clear any sent data
 			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_PURGE_TX,
 			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_PURGE_TX,
-				 icarus->usbdev->found->interface, C_PURGETX);
+				 interface, C_PURGETX);
 
 
 			if (icarus->usbinfo.nodev)
 			if (icarus->usbinfo.nodev)
 				return;
 				return;
 
 
 			// Clear any received data
 			// Clear any received data
 			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_PURGE_RX,
 			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_PURGE_RX,
-				 icarus->usbdev->found->interface, C_PURGERX);
-
-			icarus->usbdev->PrefPacketSize = BLT_PREF_PACKET;
+				 interface, C_PURGERX);
 			break;
 			break;
 		case IDENT_ICA:
 		case IDENT_ICA:
+			usb_set_pps(icarus, ICA_PREF_PACKET);
+
 			// Set Data Control
 			// Set Data Control
 			transfer(icarus, PL2303_CTRL_OUT, PL2303_REQUEST_CTRL, PL2303_VALUE_CTRL,
 			transfer(icarus, PL2303_CTRL_OUT, PL2303_REQUEST_CTRL, PL2303_VALUE_CTRL,
-				 icarus->usbdev->found->interface, C_SETDATA);
+				 interface, C_SETDATA);
 
 
 			if (icarus->usbinfo.nodev)
 			if (icarus->usbinfo.nodev)
 				return;
 				return;
@@ -347,30 +355,29 @@ static void icarus_initialise(struct cgpu_info *icarus, int baud)
 			// Set Line Control
 			// Set Line Control
 			uint32_t ica_data[2] = { PL2303_VALUE_LINE0, PL2303_VALUE_LINE1 };
 			uint32_t ica_data[2] = { PL2303_VALUE_LINE0, PL2303_VALUE_LINE1 };
 			_transfer(icarus, PL2303_CTRL_OUT, PL2303_REQUEST_LINE, PL2303_VALUE_LINE,
 			_transfer(icarus, PL2303_CTRL_OUT, PL2303_REQUEST_LINE, PL2303_VALUE_LINE,
-				 icarus->usbdev->found->interface,
-				 &ica_data[0], PL2303_VALUE_LINE_SIZE, C_SETLINE);
+				 interface, &ica_data[0], PL2303_VALUE_LINE_SIZE, C_SETLINE);
 
 
 			if (icarus->usbinfo.nodev)
 			if (icarus->usbinfo.nodev)
 				return;
 				return;
 
 
 			// Vendor
 			// Vendor
 			transfer(icarus, PL2303_VENDOR_OUT, PL2303_REQUEST_VENDOR, PL2303_VALUE_VENDOR,
 			transfer(icarus, PL2303_VENDOR_OUT, PL2303_REQUEST_VENDOR, PL2303_VALUE_VENDOR,
-				 icarus->usbdev->found->interface, C_VENDOR);
-
-			icarus->usbdev->PrefPacketSize = ICA_PREF_PACKET;
+				 interface, C_VENDOR);
 			break;
 			break;
 		case IDENT_AMU:
 		case IDENT_AMU:
+			usb_set_pps(icarus, AMU_PREF_PACKET);
+
 			// Enable the UART
 			// Enable the UART
 			transfer(icarus, CP210X_TYPE_OUT, CP210X_REQUEST_IFC_ENABLE,
 			transfer(icarus, CP210X_TYPE_OUT, CP210X_REQUEST_IFC_ENABLE,
 				 CP210X_VALUE_UART_ENABLE,
 				 CP210X_VALUE_UART_ENABLE,
-				 icarus->usbdev->found->interface, C_ENABLE_UART);
+				 interface, C_ENABLE_UART);
 
 
 			if (icarus->usbinfo.nodev)
 			if (icarus->usbinfo.nodev)
 				return;
 				return;
 
 
 			// Set data control
 			// Set data control
 			transfer(icarus, CP210X_TYPE_OUT, CP210X_REQUEST_DATA, CP210X_VALUE_DATA,
 			transfer(icarus, CP210X_TYPE_OUT, CP210X_REQUEST_DATA, CP210X_VALUE_DATA,
-				 icarus->usbdev->found->interface, C_SETDATA);
+				 interface, C_SETDATA);
 
 
 			if (icarus->usbinfo.nodev)
 			if (icarus->usbinfo.nodev)
 				return;
 				return;
@@ -378,15 +385,11 @@ static void icarus_initialise(struct cgpu_info *icarus, int baud)
 			// Set the baud
 			// Set the baud
 			uint32_t data = CP210X_DATA_BAUD;
 			uint32_t data = CP210X_DATA_BAUD;
 			_transfer(icarus, CP210X_TYPE_OUT, CP210X_REQUEST_BAUD, 0,
 			_transfer(icarus, CP210X_TYPE_OUT, CP210X_REQUEST_BAUD, 0,
-				 icarus->usbdev->found->interface,
-				 &data, sizeof(data), C_SETBAUD);
-
-			icarus->usbdev->PrefPacketSize = AMU_PREF_PACKET;
+				 interface, &data, sizeof(data), C_SETBAUD);
 			break;
 			break;
 		default:
 		default:
 			quit(1, "icarus_intialise() called with invalid %s cgid %i ident=%d",
 			quit(1, "icarus_intialise() called with invalid %s cgid %i ident=%d",
-				icarus->drv->name, icarus->cgminer_id,
-				icarus->usbdev->ident);
+				icarus->drv->name, icarus->cgminer_id, ident);
 	}
 	}
 }
 }
 
 
@@ -480,6 +483,7 @@ static const char *timing_mode_str(enum timing_mode timing_mode)
 static void set_timing_mode(int this_option_offset, struct cgpu_info *icarus)
 static void set_timing_mode(int this_option_offset, struct cgpu_info *icarus)
 {
 {
 	struct ICARUS_INFO *info = (struct ICARUS_INFO *)(icarus->device_data);
 	struct ICARUS_INFO *info = (struct ICARUS_INFO *)(icarus->device_data);
+	enum sub_ident ident;
 	double Hs;
 	double Hs;
 	char buf[BUFSIZ+1];
 	char buf[BUFSIZ+1];
 	char *ptr, *comma, *eq;
 	char *ptr, *comma, *eq;
@@ -509,7 +513,8 @@ static void set_timing_mode(int this_option_offset, struct cgpu_info *icarus)
 		buf[max] = '\0';
 		buf[max] = '\0';
 	}
 	}
 
 
-	switch (icarus->usbdev->ident) {
+	ident = usb_ident(icarus);
+	switch (ident) {
 		case IDENT_ICA:
 		case IDENT_ICA:
 			info->Hs = ICARUS_REV3_HASH_TIME;
 			info->Hs = ICARUS_REV3_HASH_TIME;
 			break;
 			break;
@@ -527,7 +532,7 @@ static void set_timing_mode(int this_option_offset, struct cgpu_info *icarus)
 			break;
 			break;
 		default:
 		default:
 			quit(1, "Icarus get_options() called with invalid %s ident=%d",
 			quit(1, "Icarus get_options() called with invalid %s ident=%d",
-				icarus->drv->name, icarus->usbdev->ident);
+				icarus->drv->name, ident);
 	}
 	}
 
 
 	info->read_time = 0;
 	info->read_time = 0;
@@ -613,6 +618,7 @@ static void get_options(int this_option_offset, struct cgpu_info *icarus, int *b
 {
 {
 	char buf[BUFSIZ+1];
 	char buf[BUFSIZ+1];
 	char *ptr, *comma, *colon, *colon2;
 	char *ptr, *comma, *colon, *colon2;
+	enum sub_ident ident;
 	size_t max;
 	size_t max;
 	int i, tmp;
 	int i, tmp;
 
 
@@ -639,7 +645,8 @@ static void get_options(int this_option_offset, struct cgpu_info *icarus, int *b
 		buf[max] = '\0';
 		buf[max] = '\0';
 	}
 	}
 
 
-	switch (icarus->usbdev->ident) {
+	ident = usb_ident(icarus);
+	switch (ident) {
 		case IDENT_ICA:
 		case IDENT_ICA:
 		case IDENT_BLT:
 		case IDENT_BLT:
 		case IDENT_LLT:
 		case IDENT_LLT:
@@ -661,7 +668,7 @@ static void get_options(int this_option_offset, struct cgpu_info *icarus, int *b
 			break;
 			break;
 		default:
 		default:
 			quit(1, "Icarus get_options() called with invalid %s ident=%d",
 			quit(1, "Icarus get_options() called with invalid %s ident=%d",
-				icarus->drv->name, icarus->usbdev->ident);
+				icarus->drv->name, ident);
 	}
 	}
 
 
 	if (*buf) {
 	if (*buf) {

+ 3 - 0
driver-modminer.c

@@ -128,6 +128,9 @@ static bool modminer_detect_one(struct libusb_device *dev, struct usb_find_devic
 	if (!usb_init(modminer, dev, found))
 	if (!usb_init(modminer, dev, found))
 		goto shin;
 		goto shin;
 
 
+	usb_set_cps(modminer, 11520);
+	usb_enable_cps(modminer);
+
 	do_ping(modminer);
 	do_ping(modminer);
 
 
 	if ((err = usb_write(modminer, MODMINER_GET_VERSION, 1, &amount, C_REQUESTVERSION)) < 0 || amount != 1) {
 	if ((err = usb_write(modminer, MODMINER_GET_VERSION, 1, &amount, C_REQUESTVERSION)) < 0 || amount != 1) {

+ 177 - 0
usbutils.c

@@ -2312,6 +2312,24 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro
 			}
 			}
 			got = 0;
 			got = 0;
 
 
+			if (first && usbdev->usecps) {
+				if (usbdev->last_write_tv.tv_sec && usbdev->last_write_siz) {
+					struct timeval now;
+					double need;
+
+					cgtime(&now);
+					need = (double)(usbdev->last_write_siz) /
+						(double)(usbdev->cps) -
+						tdiff(&now, &(usbdev->last_write_tv));
+
+					// Simple error condition check/avoidance '< 1.0'
+					if (need > 0.0 && need < 1.0) {
+						cgpu->usbinfo.read_delay_count++;
+						cgpu->usbinfo.total_read_delay += need;
+						nmsleep((unsigned int)(need * 1000.0));
+					}
+				}
+			}
 			STATS_TIMEVAL(&tv_start);
 			STATS_TIMEVAL(&tv_start);
 			err = usb_bulk_transfer(usbdev->handle,
 			err = usb_bulk_transfer(usbdev->handle,
 						usbdev->found->eps[ep].ep,
 						usbdev->found->eps[ep].ep,
@@ -2403,6 +2421,24 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro
 				usbbufread = bufleft;
 				usbbufread = bufleft;
 		}
 		}
 		got = 0;
 		got = 0;
+		if (first && usbdev->usecps) {
+			if (usbdev->last_write_tv.tv_sec && usbdev->last_write_siz) {
+				struct timeval now;
+				double need;
+
+				cgtime(&now);
+				need = (double)(usbdev->last_write_siz) /
+					(double)(usbdev->cps) -
+					tdiff(&now, &(usbdev->last_write_tv));
+
+				// Simple error condition check/avoidance '< 1.0'
+				if (need > 0.0 && need < 1.0) {
+					cgpu->usbinfo.read_delay_count++;
+					cgpu->usbinfo.total_read_delay += need;
+					nmsleep((unsigned int)(need * 1000.0));
+				}
+			}
+		}
 		STATS_TIMEVAL(&tv_start);
 		STATS_TIMEVAL(&tv_start);
 		err = usb_bulk_transfer(usbdev->handle,
 		err = usb_bulk_transfer(usbdev->handle,
 					usbdev->found->eps[ep].ep, ptr,
 					usbdev->found->eps[ep].ep, ptr,
@@ -2531,6 +2567,26 @@ int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pr
 	cgtime(&read_start);
 	cgtime(&read_start);
 	while (bufsiz > 0) {
 	while (bufsiz > 0) {
 		sent = 0;
 		sent = 0;
+		if (usbdev->usecps) {
+			if (usbdev->last_write_tv.tv_sec && usbdev->last_write_siz) {
+				struct timeval now;
+				double need;
+
+				cgtime(&now);
+				need = (double)(usbdev->last_write_siz) /
+					(double)(usbdev->cps) -
+					tdiff(&now, &(usbdev->last_write_tv));
+
+				// Simple error condition check/avoidance '< 1.0'
+				if (need > 0.0 && need < 1.0) {
+					cgpu->usbinfo.write_delay_count++;
+					cgpu->usbinfo.total_write_delay += need;
+					nmsleep((unsigned int)(need * 1000.0));
+				}
+			}
+			cgtime(&(usbdev->last_write_tv));
+			usbdev->last_write_siz = bufsiz;
+		}
 		STATS_TIMEVAL(&tv_start);
 		STATS_TIMEVAL(&tv_start);
 		err = usb_bulk_transfer(usbdev->handle,
 		err = usb_bulk_transfer(usbdev->handle,
 					usbdev->found->eps[ep].ep,
 					usbdev->found->eps[ep].ep,
@@ -2608,6 +2664,26 @@ int __usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bReques
 
 
 	USBDEBUG("USB debug: @_usb_transfer() buf=%s", bin2hex((unsigned char *)buf, (size_t)siz));
 	USBDEBUG("USB debug: @_usb_transfer() buf=%s", bin2hex((unsigned char *)buf, (size_t)siz));
 
 
+	if (usbdev->usecps) {
+		if (usbdev->last_write_tv.tv_sec && usbdev->last_write_siz) {
+			struct timeval now;
+			double need;
+
+			cgtime(&now);
+			need = (double)(usbdev->last_write_siz) /
+				(double)(usbdev->cps) -
+				tdiff(&now, &(usbdev->last_write_tv));
+
+			// Simple error condition check/avoidance '< 1.0'
+			if (need > 0.0 && need < 1.0) {
+				cgpu->usbinfo.write_delay_count++;
+				cgpu->usbinfo.total_write_delay += need;
+				nmsleep((unsigned int)(need * 1000.0));
+			}
+		}
+		cgtime(&(usbdev->last_write_tv));
+		usbdev->last_write_siz = siz;
+	}
 	STATS_TIMEVAL(&tv_start);
 	STATS_TIMEVAL(&tv_start);
 	cg_rlock(&cgusb_fd_lock);
 	cg_rlock(&cgusb_fd_lock);
 	err = libusb_control_transfer(usbdev->handle, request_type,
 	err = libusb_control_transfer(usbdev->handle, request_type,
@@ -2665,6 +2741,24 @@ int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRe
 
 
 	*amount = 0;
 	*amount = 0;
 
 
+	if (usbdev->usecps) {
+		if (usbdev->last_write_tv.tv_sec && usbdev->last_write_siz) {
+			struct timeval now;
+			double need;
+
+			cgtime(&now);
+			need = (double)(usbdev->last_write_siz) /
+				(double)(usbdev->cps) -
+				tdiff(&now, &(usbdev->last_write_tv));
+
+			// Simple error condition check/avoidance '< 1.0'
+			if (need > 0.0 && need < 1.0) {
+				cgpu->usbinfo.read_delay_count++;
+				cgpu->usbinfo.total_read_delay += need;
+				nmsleep((unsigned int)(need * 1000.0));
+			}
+		}
+	}
 	STATS_TIMEVAL(&tv_start);
 	STATS_TIMEVAL(&tv_start);
 	cg_rlock(&cgusb_fd_lock);
 	cg_rlock(&cgusb_fd_lock);
 	err = libusb_control_transfer(usbdev->handle, request_type,
 	err = libusb_control_transfer(usbdev->handle, request_type,
@@ -2814,6 +2908,89 @@ uint32_t usb_buffer_size(struct cgpu_info *cgpu)
 	return ret;
 	return ret;
 }
 }
 
 
+void usb_set_cps(struct cgpu_info *cgpu, int cps)
+{
+	int pstate;
+
+	DEVLOCK(cgpu, pstate);
+
+	if (cgpu->usbdev)
+		cgpu->usbdev->cps = cps;
+
+	DEVUNLOCK(cgpu, pstate);
+}
+
+void usb_enable_cps(struct cgpu_info *cgpu)
+{
+	int pstate;
+
+	DEVLOCK(cgpu, pstate);
+
+	if (cgpu->usbdev)
+		cgpu->usbdev->usecps = true;
+
+	DEVUNLOCK(cgpu, pstate);
+}
+
+void usb_disable_cps(struct cgpu_info *cgpu)
+{
+	int pstate;
+
+	DEVLOCK(cgpu, pstate);
+
+	if (cgpu->usbdev)
+		cgpu->usbdev->usecps = false;
+
+	DEVUNLOCK(cgpu, pstate);
+}
+
+/*
+ * The value returned (0) when usbdev is NULL
+ * doesn't matter since it also means the next call to
+ * any usbutils function will fail with a nodev
+ */
+int usb_interface(struct cgpu_info *cgpu)
+{
+	int interface = 0;
+	int pstate;
+
+	DEVLOCK(cgpu, pstate);
+
+	if (cgpu->usbdev)
+		interface = cgpu->usbdev->found->interface;
+
+	DEVUNLOCK(cgpu, pstate);
+
+	return interface;
+}
+
+enum sub_ident usb_ident(struct cgpu_info *cgpu)
+{
+	enum sub_ident ident = IDENT_UNK;
+	int pstate;
+
+	DEVLOCK(cgpu, pstate);
+
+	if (cgpu->usbdev)
+		ident = cgpu->usbdev->ident;
+
+	DEVUNLOCK(cgpu, pstate);
+
+	return ident;
+}
+
+void usb_set_pps(struct cgpu_info *cgpu, uint16_t PrefPacketSize)
+{
+	int pstate;
+
+	DEVLOCK(cgpu, pstate);
+
+	if (cgpu->usbdev)
+		cgpu->usbdev->PrefPacketSize = PrefPacketSize;
+
+	DEVUNLOCK(cgpu, pstate);
+}
+
 // Need to set all devices with matching usbdev
 // Need to set all devices with matching usbdev
 void usb_set_dev_start(struct cgpu_info *cgpu)
 void usb_set_dev_start(struct cgpu_info *cgpu)
 {
 {

+ 14 - 0
usbutils.h

@@ -168,6 +168,7 @@ struct cg_usb_device {
 	enum sub_ident ident;
 	enum sub_ident ident;
 	uint16_t usbver;
 	uint16_t usbver;
 	int cps;
 	int cps;
+	bool usecps;
 	char *prod_string;
 	char *prod_string;
 	char *manuf_string;
 	char *manuf_string;
 	char *serial_string;
 	char *serial_string;
@@ -177,6 +178,8 @@ struct cg_usb_device {
 	uint32_t bufsiz;
 	uint32_t bufsiz;
 	uint32_t bufamt;
 	uint32_t bufamt;
 	uint16_t PrefPacketSize;
 	uint16_t PrefPacketSize;
+	struct timeval last_write_tv;
+	size_t last_write_siz;
 };
 };
 
 
 #define USB_NOSTAT 0
 #define USB_NOSTAT 0
@@ -207,6 +210,11 @@ struct cg_usb_info {
 	uint64_t clear_err_count;
 	uint64_t clear_err_count;
 	uint64_t retry_err_count;
 	uint64_t retry_err_count;
 	uint64_t clear_fail_count;
 	uint64_t clear_fail_count;
+
+	uint64_t read_delay_count;
+	double total_read_delay;
+	uint64_t write_delay_count;
+	double total_write_delay;
 };
 };
 
 
 enum usb_cmds {
 enum usb_cmds {
@@ -298,6 +306,12 @@ void usb_buffer_enable(struct cgpu_info *cgpu);
 void usb_buffer_disable(struct cgpu_info *cgpu);
 void usb_buffer_disable(struct cgpu_info *cgpu);
 void usb_buffer_clear(struct cgpu_info *cgpu);
 void usb_buffer_clear(struct cgpu_info *cgpu);
 uint32_t usb_buffer_size(struct cgpu_info *cgpu);
 uint32_t usb_buffer_size(struct cgpu_info *cgpu);
+void usb_set_cps(struct cgpu_info *cgpu, int cps);
+void usb_enable_cps(struct cgpu_info *cgpu);
+void usb_disable_cps(struct cgpu_info *cgpu);
+int usb_interface(struct cgpu_info *cgpu);
+enum sub_ident usb_ident(struct cgpu_info *cgpu);
+void usb_set_pps(struct cgpu_info *cgpu, uint16_t PrefPacketSize);
 void usb_set_dev_start(struct cgpu_info *cgpu);
 void usb_set_dev_start(struct cgpu_info *cgpu);
 void usb_cleanup();
 void usb_cleanup();
 void usb_initialise();
 void usb_initialise();