Browse Source

Merge branch 'icarus-dev' into usbdev

Conflicts:
	usbutils.h
Con Kolivas 13 years ago
parent
commit
876e7e5893
5 changed files with 674 additions and 261 deletions
  1. 33 15
      cgminer.c
  2. 36 9
      driver-icarus.c
  3. 1 0
      miner.h
  4. 593 236
      usbutils.c
  5. 11 1
      usbutils.h

+ 33 - 15
cgminer.c

@@ -166,6 +166,7 @@ static int input_thr_id;
 int gpur_thr_id;
 int gpur_thr_id;
 static int api_thr_id;
 static int api_thr_id;
 #ifdef USE_USBUTILS
 #ifdef USE_USBUTILS
+static int usbres_thr_id;
 static int hotplug_thr_id;
 static int hotplug_thr_id;
 #endif
 #endif
 static int total_control_threads;
 static int total_control_threads;
@@ -177,6 +178,7 @@ int hotplug_time = 5;
 
 
 #ifdef USE_USBUTILS
 #ifdef USE_USBUTILS
 pthread_mutex_t cgusb_lock;
 pthread_mutex_t cgusb_lock;
+pthread_mutex_t cgusbres_lock;
 #endif
 #endif
 
 
 pthread_mutex_t hash_lock;
 pthread_mutex_t hash_lock;
@@ -2846,6 +2848,10 @@ static void __kill_work(void)
 	if (!opt_scrypt) {
 	if (!opt_scrypt) {
 		applog(LOG_DEBUG, "Releasing all USB devices");
 		applog(LOG_DEBUG, "Releasing all USB devices");
 		usb_cleanup();
 		usb_cleanup();
+
+		applog(LOG_DEBUG, "Killing off usbres thread");
+		thr = &control_thr[usbres_thr_id];
+		thr_info_cancel(thr);
 	}
 	}
 #endif
 #endif
 
 
@@ -7197,6 +7203,7 @@ int main(int argc, char *argv[])
 	}
 	}
 #ifdef USE_USBUTILS
 #ifdef USE_USBUTILS
 	mutex_init(&cgusb_lock);
 	mutex_init(&cgusb_lock);
+	mutex_init(&cgusbres_lock);
 #endif
 #endif
 #endif
 #endif
 
 
@@ -7323,8 +7330,25 @@ int main(int argc, char *argv[])
 	/* Use a shorter scantime for scrypt */
 	/* Use a shorter scantime for scrypt */
 	if (opt_scantime < 0)
 	if (opt_scantime < 0)
 		opt_scantime = opt_scrypt ? 30 : 60;
 		opt_scantime = opt_scrypt ? 30 : 60;
+
+	total_control_threads = 9;
+	control_thr = calloc(total_control_threads, sizeof(*thr));
+	if (!control_thr)
+		quit(1, "Failed to calloc control_thr");
+
+	gwsched_thr_id = 0;
+
 #ifdef USE_USBUTILS
 #ifdef USE_USBUTILS
 	usb_initialise();
 	usb_initialise();
+
+	// before device detection
+	if (!opt_scrypt) {
+		usbres_thr_id = 1;
+		thr = &control_thr[usbres_thr_id];
+		if (thr_info_create(thr, NULL, usb_resource_thread, thr))
+			quit(1, "usb resource thread create failed");
+		pthread_detach(thr->pth);
+	}
 #endif
 #endif
 
 
 #ifdef HAVE_OPENCL
 #ifdef HAVE_OPENCL
@@ -7464,13 +7488,7 @@ int main(int argc, char *argv[])
 			quit(1, "Failed to calloc mining_thr[%d]", i);
 			quit(1, "Failed to calloc mining_thr[%d]", i);
 	}
 	}
 
 
-	total_control_threads = 8;
-	control_thr = calloc(total_control_threads, sizeof(*thr));
-	if (!control_thr)
-		quit(1, "Failed to calloc control_thr");
-
-	gwsched_thr_id = 0;
-	stage_thr_id = 1;
+	stage_thr_id = 2;
 	thr = &control_thr[stage_thr_id];
 	thr = &control_thr[stage_thr_id];
 	thr->q = tq_new();
 	thr->q = tq_new();
 	if (!thr->q)
 	if (!thr->q)
@@ -7591,14 +7609,14 @@ begin_bench:
 	cgtime(&total_tv_start);
 	cgtime(&total_tv_start);
 	cgtime(&total_tv_end);
 	cgtime(&total_tv_end);
 
 
-	watchpool_thr_id = 2;
+	watchpool_thr_id = 3;
 	thr = &control_thr[watchpool_thr_id];
 	thr = &control_thr[watchpool_thr_id];
 	/* start watchpool thread */
 	/* start watchpool thread */
 	if (thr_info_create(thr, NULL, watchpool_thread, NULL))
 	if (thr_info_create(thr, NULL, watchpool_thread, NULL))
 		quit(1, "watchpool thread create failed");
 		quit(1, "watchpool thread create failed");
 	pthread_detach(thr->pth);
 	pthread_detach(thr->pth);
 
 
-	watchdog_thr_id = 3;
+	watchdog_thr_id = 4;
 	thr = &control_thr[watchdog_thr_id];
 	thr = &control_thr[watchdog_thr_id];
 	/* start watchdog thread */
 	/* start watchdog thread */
 	if (thr_info_create(thr, NULL, watchdog_thread, NULL))
 	if (thr_info_create(thr, NULL, watchdog_thread, NULL))
@@ -7607,7 +7625,7 @@ begin_bench:
 
 
 #ifdef HAVE_OPENCL
 #ifdef HAVE_OPENCL
 	/* Create reinit gpu thread */
 	/* Create reinit gpu thread */
-	gpur_thr_id = 4;
+	gpur_thr_id = 5;
 	thr = &control_thr[gpur_thr_id];
 	thr = &control_thr[gpur_thr_id];
 	thr->q = tq_new();
 	thr->q = tq_new();
 	if (!thr->q)
 	if (!thr->q)
@@ -7617,14 +7635,14 @@ begin_bench:
 #endif	
 #endif	
 
 
 	/* Create API socket thread */
 	/* Create API socket thread */
-	api_thr_id = 5;
+	api_thr_id = 6;
 	thr = &control_thr[api_thr_id];
 	thr = &control_thr[api_thr_id];
 	if (thr_info_create(thr, NULL, api_thread, thr))
 	if (thr_info_create(thr, NULL, api_thread, thr))
 		quit(1, "API thread create failed");
 		quit(1, "API thread create failed");
 
 
 #ifdef USE_USBUTILS
 #ifdef USE_USBUTILS
 	if (!opt_scrypt) {
 	if (!opt_scrypt) {
-		hotplug_thr_id = 6;
+		hotplug_thr_id = 7;
 		thr = &control_thr[hotplug_thr_id];
 		thr = &control_thr[hotplug_thr_id];
 		if (thr_info_create(thr, NULL, hotplug_thread, thr))
 		if (thr_info_create(thr, NULL, hotplug_thread, thr))
 			quit(1, "hotplug thread create failed");
 			quit(1, "hotplug thread create failed");
@@ -7636,7 +7654,7 @@ begin_bench:
 	/* Create curses input thread for keyboard input. Create this last so
 	/* Create curses input thread for keyboard input. Create this last so
 	 * that we know all threads are created since this can call kill_work
 	 * that we know all threads are created since this can call kill_work
 	 * to try and shut down all previous threads. */
 	 * to try and shut down all previous threads. */
-	input_thr_id = 7;
+	input_thr_id = 8;
 	thr = &control_thr[input_thr_id];
 	thr = &control_thr[input_thr_id];
 	if (thr_info_create(thr, NULL, input_thread, thr))
 	if (thr_info_create(thr, NULL, input_thread, thr))
 		quit(1, "input thread create failed");
 		quit(1, "input thread create failed");
@@ -7644,8 +7662,8 @@ begin_bench:
 #endif
 #endif
 
 
 	/* Just to be sure */
 	/* Just to be sure */
-	if (total_control_threads != 8)
-		quit(1, "incorrect total_control_threads (%d) should be 8", total_control_threads);
+	if (total_control_threads != 9)
+		quit(1, "incorrect total_control_threads (%d) should be 9", total_control_threads);
 
 
 	/* Once everything is set up, main() becomes the getwork scheduler */
 	/* Once everything is set up, main() becomes the getwork scheduler */
 	while (42) {
 	while (42) {

+ 36 - 9
driver-icarus.c

@@ -244,16 +244,18 @@ static void _transfer(struct cgpu_info *icarus, uint8_t request_type, uint8_t bR
 #define transfer(icarus, request_type, bRequest, wValue, wIndex, cmd) \
 #define transfer(icarus, request_type, bRequest, wValue, wIndex, cmd) \
 		_transfer(icarus, request_type, bRequest, wValue, wIndex, NULL, 0, cmd)
 		_transfer(icarus, request_type, bRequest, wValue, wIndex, NULL, 0, cmd)
 
 
-// TODO: handle baud
-static void icarus_initialise(struct cgpu_info *icarus, __maybe_unused int baud)
+static void icarus_initialise(struct cgpu_info *icarus, int baud)
 {
 {
+	uint16_t wValue, wIndex;
+
 	if (icarus->usbinfo.nodev)
 	if (icarus->usbinfo.nodev)
 		return;
 		return;
 
 
 	switch (icarus->usbdev->ident) {
 	switch (icarus->usbdev->ident) {
 		case IDENT_BLT:
 		case IDENT_BLT:
 		case IDENT_LLT:
 		case IDENT_LLT:
-		case IDENT_CMR:
+		case IDENT_CMR1:
+		case IDENT_CMR2:
 			// Latency
 			// Latency
 			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_LATENCY, FTDI_VALUE_LATENCY,
 			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_LATENCY, FTDI_VALUE_LATENCY,
 				 icarus->usbdev->found->interface, C_LATENCY);
 				 icarus->usbdev->found->interface, C_LATENCY);
@@ -275,9 +277,30 @@ static void icarus_initialise(struct cgpu_info *icarus, __maybe_unused int baud)
 			if (icarus->usbinfo.nodev)
 			if (icarus->usbinfo.nodev)
 				return;
 				return;
 
 
+			// default to BLT/LLT 115200
+			wValue = FTDI_VALUE_BAUD_BLT;
+			wIndex = FTDI_INDEX_BAUD_BLT;
+
+			if (icarus->usbdev->ident == IDENT_CMR1 ||
+			    icarus->usbdev->ident == IDENT_CMR2) {
+				switch (baud) {
+					case 115200:
+						wValue = FTDI_VALUE_BAUD_CMR_115;
+						wIndex = FTDI_INDEX_BAUD_CMR_115;
+						break;
+					case 57600:
+						wValue = FTDI_VALUE_BAUD_CMR_57;
+						wIndex = FTDI_INDEX_BAUD_CMR_57;
+						break;
+					default:
+						quit(1, "icarus_intialise() invalid baud (%d) for Cairnsmore1", baud);
+						break;
+				}
+			}
+
 			// Set the baud
 			// Set the baud
-			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, FTDI_VALUE_BAUD_BLT,
-				 (FTDI_INDEX_BAUD_BLT & 0xff00) | icarus->usbdev->found->interface,
+			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, wValue,
+				 (wIndex & 0xff00) | icarus->usbdev->found->interface,
 				 C_SETBAUD);
 				 C_SETBAUD);
 
 
 			if (icarus->usbinfo.nodev)
 			if (icarus->usbinfo.nodev)
@@ -387,7 +410,7 @@ static int icarus_get_nonce(struct cgpu_info *icarus, unsigned char *buf, struct
 		err = usb_read_timeout(icarus, (char *)buf, read_amount, &amt, ICARUS_WAIT_TIMEOUT, C_GETRESULTS);
 		err = usb_read_timeout(icarus, (char *)buf, read_amount, &amt, ICARUS_WAIT_TIMEOUT, C_GETRESULTS);
 		cgtime(&read_finish);
 		cgtime(&read_finish);
 		if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) {
 		if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) {
-			applog(LOG_ERR, "%s%i: Comms error (err=%d amt=%d)",
+			applog(LOG_ERR, "%s%i: Comms error (rerr=%d amt=%d)",
 					icarus->drv->name, icarus->device_id, err, amt);
 					icarus->drv->name, icarus->device_id, err, amt);
 			dev_error(icarus, REASON_DEV_COMMS_ERROR);
 			dev_error(icarus, REASON_DEV_COMMS_ERROR);
 			return ICA_NONCE_ERROR;
 			return ICA_NONCE_ERROR;
@@ -484,7 +507,9 @@ static void set_timing_mode(int this_option_offset, struct cgpu_info *icarus)
 		case IDENT_AMU:
 		case IDENT_AMU:
 			info->Hs = ASICMINERUSB_HASH_TIME;
 			info->Hs = ASICMINERUSB_HASH_TIME;
 			break;
 			break;
-		case IDENT_CMR:
+		// TODO: ?
+		case IDENT_CMR1:
+		case IDENT_CMR2:
 			info->Hs = CAIRNSMORE1_HASH_TIME;
 			info->Hs = CAIRNSMORE1_HASH_TIME;
 			break;
 			break;
 		default:
 		default:
@@ -617,7 +642,9 @@ static void get_options(int this_option_offset, struct cgpu_info *icarus, int *b
 			*work_division = 1;
 			*work_division = 1;
 			*fpga_count = 1;
 			*fpga_count = 1;
 			break;
 			break;
-		case IDENT_CMR:
+		// TODO: ?
+		case IDENT_CMR1:
+		case IDENT_CMR2:
 			*baud = ICARUS_IO_SPEED;
 			*baud = ICARUS_IO_SPEED;
 			*work_division = 2;
 			*work_division = 2;
 			*fpga_count = 2;
 			*fpga_count = 2;
@@ -860,7 +887,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 
 	err = usb_write(icarus, (char *)ob_bin, sizeof(ob_bin), &amount, C_SENDWORK);
 	err = usb_write(icarus, (char *)ob_bin, sizeof(ob_bin), &amount, C_SENDWORK);
 	if (err < 0 || amount != sizeof(ob_bin)) {
 	if (err < 0 || amount != sizeof(ob_bin)) {
-		applog(LOG_ERR, "%s%i: Comms error (err=%d amt=%d)",
+		applog(LOG_ERR, "%s%i: Comms error (werr=%d amt=%d)",
 				icarus->drv->name, icarus->device_id, err, amount);
 				icarus->drv->name, icarus->device_id, err, amount);
 		dev_error(icarus, REASON_DEV_COMMS_ERROR);
 		dev_error(icarus, REASON_DEV_COMMS_ERROR);
 		icarus_initialise(icarus, info->baud);
 		icarus_initialise(icarus, info->baud);

+ 1 - 0
miner.h

@@ -880,6 +880,7 @@ extern int opt_expiry;
 
 
 #ifdef USE_USBUTILS
 #ifdef USE_USBUTILS
 extern pthread_mutex_t cgusb_lock;
 extern pthread_mutex_t cgusb_lock;
+extern pthread_mutex_t cgusbres_lock;
 #endif
 #endif
 
 
 extern cglock_t control_lock;
 extern cglock_t control_lock;

+ 593 - 236
usbutils.c

@@ -106,7 +106,24 @@ static struct usb_endpoints llt_eps[] = {
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(1), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(1), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(2), 0 }
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(2), 0 }
 };
 };
-static struct usb_endpoints cmr_eps[] = {
+static struct usb_endpoints cmr1_eps[] = {
+	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(1), 0 },
+	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(2), 0 }
+/*
+ Interface 1
+	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(3), 0 },
+	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(4), 0 },
+
+ Interface 2
+	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(5), 0 },
+	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(6), 0 },
+
+ Interface 3
+	{ 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,	EPI(1), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(2), 0 }
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(2), 0 }
 };
 };
@@ -230,7 +247,7 @@ static struct usb_find_devices find_dev[] = {
 	{
 	{
 		.drv = DRV_ICARUS,
 		.drv = DRV_ICARUS,
 		.name = "CMR",
 		.name = "CMR",
-		.ident = IDENT_CMR,
+		.ident = IDENT_CMR1,
 		.idVendor = IDVENDOR_FTDI,
 		.idVendor = IDVENDOR_FTDI,
 		.idProduct = 0x8350,
 		.idProduct = 0x8350,
 		.iProduct = "Cairnsmore1",
 		.iProduct = "Cairnsmore1",
@@ -238,12 +255,12 @@ static struct usb_find_devices find_dev[] = {
 		.config = 1,
 		.config = 1,
 		.interface = 0,
 		.interface = 0,
 		.timeout = ICARUS_TIMEOUT_MS,
 		.timeout = ICARUS_TIMEOUT_MS,
-		.epcount = ARRAY_SIZE(cmr_eps),
-		.eps = cmr_eps },
+		.epcount = ARRAY_SIZE(cmr1_eps),
+		.eps = cmr1_eps },
 	{
 	{
 		.drv = DRV_ICARUS,
 		.drv = DRV_ICARUS,
 		.name = "CMR",
 		.name = "CMR",
-		.ident = IDENT_CMR,
+		.ident = IDENT_CMR2,
 		.idVendor = IDVENDOR_FTDI,
 		.idVendor = IDVENDOR_FTDI,
 		.idProduct = 0x6014,
 		.idProduct = 0x6014,
 		.iProduct = "Cairnsmore1",
 		.iProduct = "Cairnsmore1",
@@ -251,8 +268,8 @@ static struct usb_find_devices find_dev[] = {
 		.config = 1,
 		.config = 1,
 		.interface = 0,
 		.interface = 0,
 		.timeout = ICARUS_TIMEOUT_MS,
 		.timeout = ICARUS_TIMEOUT_MS,
-		.epcount = ARRAY_SIZE(cmr_eps),
-		.eps = cmr_eps },
+		.epcount = ARRAY_SIZE(cmr2_eps),
+		.eps = cmr2_eps },
 #endif
 #endif
 #ifdef USE_ZTEX
 #ifdef USE_ZTEX
 // This is here so cgminer -n shows them
 // This is here so cgminer -n shows them
@@ -319,6 +336,8 @@ static struct driver_count {
 static struct usb_busdev {
 static struct usb_busdev {
 	int bus_number;
 	int bus_number;
 	int device_address;
 	int device_address;
+	void *resource1;
+	void *resource2;
 } *busdev;
 } *busdev;
 
 
 static int busdev_count = 0;
 static int busdev_count = 0;
@@ -336,6 +355,27 @@ struct usb_in_use_list {
 // List of in use devices
 // List of in use devices
 static struct usb_in_use_list *in_use_head = NULL;
 static struct usb_in_use_list *in_use_head = NULL;
 
 
+struct resource_work {
+	bool lock;
+	const char *dname;
+	uint8_t bus_number;
+	uint8_t device_address;
+	struct resource_work *next;
+};
+
+// Pending work for the reslock thread
+struct resource_work *res_work_head = NULL;
+
+struct resource_reply {
+	uint8_t bus_number;
+	uint8_t device_address;
+	bool got;
+	struct resource_reply *next;
+};
+
+// Replies to lock requests
+struct resource_reply *res_reply_head = NULL;
+
 // Set this to 0 to remove stats processing
 // Set this to 0 to remove stats processing
 #define DO_USB_STATS 1
 #define DO_USB_STATS 1
 
 
@@ -627,6 +667,8 @@ static void append(char **buf, char *append, size_t *off, size_t *len)
 	{
 	{
 		*len *= 2;
 		*len *= 2;
 		*buf = realloc(*buf, *len);
 		*buf = realloc(*buf, *len);
+		if (unlikely(!*buf))
+			quit(1, "USB failed to realloc append");
 	}
 	}
 
 
 	strcpy(*buf + *off, append);
 	strcpy(*buf + *off, append);
@@ -840,6 +882,8 @@ void usb_all(int level)
 	{
 	{
 		len = 10000;
 		len = 10000;
 		buf = malloc(len+1);
 		buf = malloc(len+1);
+		if (unlikely(!buf))
+			quit(1, "USB failed to malloc buf in usb_all");
 
 
 		sprintf(buf, "USB all: found %d devices", (int)count);
 		sprintf(buf, "USB all: found %d devices", (int)count);
 		off = strlen(buf);
 		off = strlen(buf);
@@ -878,6 +922,8 @@ static void cgusb_check_init()
 		}
 		}
 
 
 		usb_commands = malloc(sizeof(*usb_commands) * C_MAX);
 		usb_commands = malloc(sizeof(*usb_commands) * C_MAX);
+		if (unlikely(!usb_commands))
+			quit(1, "USB failed to malloc usb_commands");
 
 
 		// use constants so the stat generation is very quick
 		// use constants so the stat generation is very quick
 		// and the association between number and name can't
 		// and the association between number and name can't
@@ -968,6 +1014,80 @@ void usb_applog(struct cgpu_info *cgpu, enum usb_cmds cmd, char *msg, int amount
                         err, amount);
                         err, amount);
 }
 }
 
 
+#ifdef WIN32
+static void in_use_store_ress(uint8_t bus_number, uint8_t device_address, void *resource1, void *resource2)
+{
+	struct usb_in_use_list *in_use_tmp;
+	bool found = false, empty = true;
+
+	mutex_lock(&cgusb_lock);
+	in_use_tmp = in_use_head;
+	while (in_use_tmp) {
+		if (in_use_tmp->in_use.bus_number == (int)bus_number &&
+			in_use_tmp->in_use.device_address == (int)device_address) {
+			found = true;
+
+			if (in_use_tmp->in_use.resource1)
+				empty = false;
+			in_use_tmp->in_use.resource1 = resource1;
+
+			if (in_use_tmp->in_use.resource2)
+				empty = false;
+			in_use_tmp->in_use.resource2 = resource2;
+
+			break;
+		}
+		in_use_tmp = in_use_tmp->next;
+	}
+	mutex_unlock(&cgusb_lock);
+
+	if (found == false)
+		applog(LOG_ERR, "FAIL: USB store_ress not found (%d:%d)",
+				(int)bus_number, (int)device_address);
+
+	if (empty == false)
+		applog(LOG_ERR, "FAIL: USB store_ress not empty (%d:%d)",
+				(int)bus_number, (int)device_address);
+}
+
+static void in_use_get_ress(uint8_t bus_number, uint8_t device_address, void **resource1, void **resource2)
+{
+	struct usb_in_use_list *in_use_tmp;
+	bool found = false, empty = false;
+
+	mutex_lock(&cgusb_lock);
+	in_use_tmp = in_use_head;
+	while (in_use_tmp) {
+		if (in_use_tmp->in_use.bus_number == (int)bus_number &&
+			in_use_tmp->in_use.device_address == (int)device_address) {
+			found = true;
+
+			if (!in_use_tmp->in_use.resource1)
+				empty = true;
+			*resource1 = in_use_tmp->in_use.resource1;
+			in_use_tmp->in_use.resource1 = NULL;
+
+			if (!in_use_tmp->in_use.resource2)
+				empty = true;
+			*resource2 = in_use_tmp->in_use.resource2;
+			in_use_tmp->in_use.resource2 = NULL;
+
+			break;
+		}
+		in_use_tmp = in_use_tmp->next;
+	}
+	mutex_unlock(&cgusb_lock);
+
+	if (found == false)
+		applog(LOG_ERR, "FAIL: USB get_lock not found (%d:%d)",
+				(int)bus_number, (int)device_address);
+
+	if (empty == true)
+		applog(LOG_ERR, "FAIL: USB get_lock empty (%d:%d)",
+				(int)bus_number, (int)device_address);
+}
+#endif
+
 static bool __is_in_use(uint8_t bus_number, uint8_t device_address)
 static bool __is_in_use(uint8_t bus_number, uint8_t device_address)
 {
 {
 	struct usb_in_use_list *in_use_tmp;
 	struct usb_in_use_list *in_use_tmp;
@@ -1013,6 +1133,8 @@ static void add_in_use(uint8_t bus_number, uint8_t device_address)
 	}
 	}
 
 
 	in_use_tmp = calloc(1, sizeof(*in_use_tmp));
 	in_use_tmp = calloc(1, sizeof(*in_use_tmp));
+	if (unlikely(!in_use_tmp))
+		quit(1, "USB failed to calloc in_use_tmp");
 	in_use_tmp->in_use.bus_number = (int)bus_number;
 	in_use_tmp->in_use.bus_number = (int)bus_number;
 	in_use_tmp->in_use.device_address = (int)device_address;
 	in_use_tmp->in_use.device_address = (int)device_address;
 	in_use_tmp->next = in_use_head;
 	in_use_tmp->next = in_use_head;
@@ -1061,178 +1183,63 @@ static void remove_in_use(uint8_t bus_number, uint8_t device_address)
 				(int)bus_number, (int)device_address);
 				(int)bus_number, (int)device_address);
 }
 }
 
 
-#ifndef WIN32
-#include <errno.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/ipc.h>
-#include <sys/sem.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-union semun {
-	int sem;
-	struct semid_ds *seminfo;
-	ushort *all;
-};
-#endif
-
-// Any errors should always be printed since they will rarely if ever occur
-// and thus it is best to always display them
 static bool cgminer_usb_lock_bd(struct device_drv *drv, uint8_t bus_number, uint8_t device_address)
 static bool cgminer_usb_lock_bd(struct device_drv *drv, uint8_t bus_number, uint8_t device_address)
 {
 {
-	applog(LOG_DEBUG, "USB lock %s %d-%d", drv->name, (int)bus_number, (int)device_address);
+	struct resource_work *res_work;
+	bool ret;
 
 
-#ifdef WIN32
-	struct cgpu_info *cgpu;
-	HANDLE usbMutex;
-	char name[64];
-	DWORD res;
-	int i;
+	applog(LOG_DEBUG, "USB lock %s %d-%d", drv->dname, (int)bus_number, (int)device_address);
 
 
-	if (is_in_use_bd(bus_number, device_address))
-		return false;
+	res_work = calloc(1, sizeof(*res_work));
+	if (unlikely(!res_work))
+		quit(1, "USB failed to calloc lock res_work");
+	res_work->lock = true;
+	res_work->dname = (const char *)(drv->dname);
+	res_work->bus_number = bus_number;
+	res_work->device_address = device_address;
 
 
-	sprintf(name, "cgminer-usb-%d-%d", (int)bus_number, (int)device_address);
+	mutex_lock(&cgusbres_lock);
 
 
-	usbMutex = CreateMutex(NULL, FALSE, name);
-	if (usbMutex == NULL) {
-		applog(LOG_ERR,
-			"MTX: %s USB failed to get '%s' err (%d)",
-			drv->dname, name, GetLastError());
-		return false;
-	}
+	res_work->next = res_work_head;
+	res_work_head = res_work;
 
 
-	res = WaitForSingleObject(usbMutex, 0);
-	switch(res) {
-		case WAIT_OBJECT_0:
-		case WAIT_ABANDONED:
-			// Am I using it already?
-			for (i = 0; i < total_devices; i++) {
-				cgpu = get_devices(i);
-				if (cgpu->usbinfo.bus_number == bus_number &&
-				    cgpu->usbinfo.device_address == device_address &&
-				    cgpu->usbinfo.nodev == false) {
-					if (ReleaseMutex(usbMutex)) {
-						applog(LOG_WARNING,
-							"MTX: %s USB can't get '%s' - device in use",
-							drv->dname, name);
-						goto fail;
-					}
-					applog(LOG_ERR,
-						"MTX: %s USB can't get '%s' - device in use - failure (%d)",
-						drv->dname, name, GetLastError());
-					goto fail;
-				}
-			}
-			add_in_use(bus_number, device_address);
-			return true;
-		case WAIT_TIMEOUT:
-			if (!hotplug_mode)
-				applog(LOG_WARNING,
-					"MTX: %s USB failed to get '%s' - device in use",
-					drv->dname, name);
-			goto fail;
-		case WAIT_FAILED:
-			applog(LOG_ERR,
-				"MTX: %s USB failed to get '%s' err (%d)",
-				drv->dname, name, GetLastError());
-			goto fail;
-		default:
-			applog(LOG_ERR,
-				"MTX: %s USB failed to get '%s' unknown reply (%d)",
-				drv->dname, name, res);
-			goto fail;
-	}
+	mutex_unlock(&cgusbres_lock);
 
 
-	CloseHandle(usbMutex);
-	add_in_use(bus_number, device_address);
-	return true;
-fail:
-	CloseHandle(usbMutex);
-	return false;
-#else
-	struct semid_ds seminfo;
-	union semun opt;
-	char name[64];
-	key_t key;
-	int fd, sem, count;
+	nmsleep(46);
 
 
-	if (is_in_use_bd(bus_number, device_address))
-		return false;
+	// TODO: add a timeout fail - restart the resource thread?
+	while (true) {
+		mutex_lock(&cgusbres_lock);
 
 
-	sprintf(name, "/tmp/cgminer-usb-%d-%d", (int)bus_number, (int)device_address);
-	fd = open(name, O_CREAT|O_RDONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
-	if (fd == -1) {
-		applog(LOG_ERR,
-			"SEM: %s USB open failed '%s' err (%d) %s",
-			drv->dname, name, errno, strerror(errno));
-		return false;
-	}
-	close(fd);
-	key = ftok(name, 'K');
-	sem = semget(key, 1, IPC_CREAT | IPC_EXCL | 438);
-	if (sem < 0) {
-		if (errno != EEXIST) {
-			applog(LOG_ERR,
-				"SEM: %s USB failed to get '%s' err (%d) %s",
-				drv->dname, name, errno, strerror(errno));
-			return false;
-		}
+		if (res_reply_head) {
+			struct resource_reply *res_reply_prev = NULL;
+			struct resource_reply *res_reply = res_reply_head;
+			while (res_reply) {
+				if (res_reply->bus_number == bus_number &&
+					res_reply->device_address == device_address) {
 
 
-		sem = semget(key, 1, 0);
-		if (sem < 0) {
-			applog(LOG_ERR,
-				"SEM: %s USB failed to access '%s' err (%d) %s",
-				drv->dname, name, errno, strerror(errno));
-			return false;
-		}
+					if (res_reply_prev)
+						res_reply_prev->next = res_reply->next;
+					else
+						res_reply_head = res_reply->next;
 
 
-		opt.seminfo = &seminfo;
-		count = 0;
-		while (++count) {
-			// Should NEVER take 100ms
-			if (count > 99) {
-				applog(LOG_ERR,
-					"SEM: %s USB timeout waiting for (%d) '%s'",
-					drv->dname, sem, name);
-				return false;
-			}
-			if (semctl(sem, 0, IPC_STAT, opt) == -1) {
-				applog(LOG_ERR,
-					"SEM: %s USB failed to wait for (%d) '%s' count %d err (%d) %s",
-					drv->dname, sem, name, count, errno, strerror(errno));
-				return false;
+					mutex_unlock(&cgusbres_lock);
+
+					ret = res_reply->got;
+
+					free(res_reply);
+
+					return ret;
+				}
+				res_reply_prev = res_reply;
+				res_reply = res_reply->next;
 			}
 			}
-			if (opt.seminfo->sem_otime != 0)
-				break;
-			nmsleep(1);
 		}
 		}
-	}
 
 
-	struct sembuf sops[] = {
-		{ 0, 0, IPC_NOWAIT | SEM_UNDO },
-		{ 0, 1, IPC_NOWAIT | SEM_UNDO }
-	};
+		mutex_unlock(&cgusbres_lock);
 
 
-	if (semop(sem, sops, 2)) {
-		if (errno == EAGAIN) {
-			if (!hotplug_mode)
-				applog(LOG_WARNING,
-					"SEM: %s USB failed to get (%d) '%s' - device in use",
-					drv->dname, sem, name);
-		} else {
-			applog(LOG_DEBUG,
-				"SEM: %s USB failed to get (%d) '%s' err (%d) %s",
-				drv->dname, sem, name, errno, strerror(errno));
-		}
-		return false;
+		nmsleep(45);
 	}
 	}
-
-	add_in_use(bus_number, device_address);
-	return true;
-#endif
 }
 }
 
 
 static bool cgminer_usb_lock(struct device_drv *drv, libusb_device *dev)
 static bool cgminer_usb_lock(struct device_drv *drv, libusb_device *dev)
@@ -1240,89 +1247,41 @@ static bool cgminer_usb_lock(struct device_drv *drv, libusb_device *dev)
 	return cgminer_usb_lock_bd(drv, libusb_get_bus_number(dev), libusb_get_device_address(dev));
 	return cgminer_usb_lock_bd(drv, libusb_get_bus_number(dev), libusb_get_device_address(dev));
 }
 }
 
 
-// Any errors should always be printed since they will rarely if ever occur
-// and thus it is best to always display them
 static void cgminer_usb_unlock_bd(struct device_drv *drv, uint8_t bus_number, uint8_t device_address)
 static void cgminer_usb_unlock_bd(struct device_drv *drv, uint8_t bus_number, uint8_t device_address)
 {
 {
-	applog(LOG_DEBUG, "USB unlock %s %d-%d", drv->name, (int)bus_number, (int)device_address);
+	struct resource_work *res_work;
 
 
-#ifdef WIN32
-	HANDLE usbMutex;
-	char name[64];
+	applog(LOG_DEBUG, "USB unlock %s %d-%d", drv->dname, (int)bus_number, (int)device_address);
 
 
-	sprintf(name, "cgminer-usb-%d-%d", (int)bus_number, (int)device_address);
+	res_work = calloc(1, sizeof(*res_work));
+	if (unlikely(!res_work))
+		quit(1, "USB failed to calloc unlock res_work");
+	res_work->lock = false;
+	res_work->dname = (const char *)(drv->dname);
+	res_work->bus_number = bus_number;
+	res_work->device_address = device_address;
 
 
-	usbMutex = CreateMutex(NULL, FALSE, name);
-	if (usbMutex == NULL) {
-		applog(LOG_ERR,
-			"MTX: %s USB failed to get '%s' for release err (%d)",
-			drv->dname, name, GetLastError());
-		return;
-	}
+	mutex_lock(&cgusbres_lock);
 
 
-	if (!ReleaseMutex(usbMutex))
-		applog(LOG_ERR,
-			"MTX: %s USB failed to release '%s' err (%d)",
-			drv->dname, name, GetLastError());
+	res_work->next = res_work_head;
+	res_work_head = res_work;
+
+	mutex_unlock(&cgusbres_lock);
 
 
-	CloseHandle(usbMutex);
-	remove_in_use(bus_number, device_address);
 	return;
 	return;
-#else
-	char name[64];
-	key_t key;
-	int fd, sem;
+}
 
 
-	sprintf(name, "/tmp/cgminer-usb-%d-%d", (int)bus_number, (int)device_address);
-	fd = open(name, O_CREAT|O_RDONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
-	if (fd == -1) {
-		applog(LOG_ERR,
-			"SEM: %s USB open failed '%s' for release err (%d) %s",
-			drv->dname, name, errno, strerror(errno));
-		return;
-	}
-	close(fd);
-	key = ftok(name, 'K');
+static void cgminer_usb_unlock(struct device_drv *drv, libusb_device *dev)
+{
+	cgminer_usb_unlock_bd(drv, libusb_get_bus_number(dev), libusb_get_device_address(dev));
+}
 
 
-	sem = semget(key, 1, 0);
-	if (sem < 0) {
-		applog(LOG_ERR,
-			"SEM: %s USB failed to get '%s' for release err (%d) %s",
-			drv->dname, name, errno, strerror(errno));
-		return;
-	}
+static struct cg_usb_device *free_cgusb(struct cg_usb_device *cgusb)
+{
+	applog(LOG_DEBUG, "USB free %s", cgusb->found->name);
 
 
-	struct sembuf sops[] = {
-		{ 0, -1, SEM_UNDO }
-	};
-
-	// Allow a 10ms timeout
-	// exceeding this timeout means it would probably never succeed anyway
-	struct timespec timeout = { 0, 10000000 };
-
-	// Wait forever since we shoud be the one who has it
-	if (semtimedop(sem, sops, 1, &timeout)) {
-		applog(LOG_ERR,
-			"SEM: %s USB failed to release '%s' err (%d) %s",
-			drv->dname, name, errno, strerror(errno));
-	}
-
-	remove_in_use(bus_number, device_address);
-	return;
-#endif
-}
-
-static void cgminer_usb_unlock(struct device_drv *drv, libusb_device *dev)
-{
-	cgminer_usb_unlock_bd(drv, libusb_get_bus_number(dev), libusb_get_device_address(dev));
-}
-
-static struct cg_usb_device *free_cgusb(struct cg_usb_device *cgusb)
-{
-	applog(LOG_DEBUG, "USB free %s", cgusb->found->name);
-
-	if (cgusb->serial_string && cgusb->serial_string != BLANK)
-		free(cgusb->serial_string);
+	if (cgusb->serial_string && cgusb->serial_string != BLANK)
+		free(cgusb->serial_string);
 
 
 	if (cgusb->manuf_string && cgusb->manuf_string != BLANK)
 	if (cgusb->manuf_string && cgusb->manuf_string != BLANK)
 		free(cgusb->manuf_string);
 		free(cgusb->manuf_string);
@@ -1416,6 +1375,8 @@ static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct u
 		cgpu->usbinfo.bus_number, cgpu->usbinfo.device_address);
 		cgpu->usbinfo.bus_number, cgpu->usbinfo.device_address);
 
 
 	cgusb = calloc(1, sizeof(*cgusb));
 	cgusb = calloc(1, sizeof(*cgusb));
+	if (unlikely(!cgusb))
+		quit(1, "USB failed to calloc _usb_init cgusb");
 	cgusb->found = found;
 	cgusb->found = found;
 
 
 	if (found->idVendor == IDVENDOR_FTDI)
 	if (found->idVendor == IDVENDOR_FTDI)
@@ -1424,6 +1385,8 @@ static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct u
 	cgusb->ident = found->ident;
 	cgusb->ident = found->ident;
 
 
 	cgusb->descriptor = calloc(1, sizeof(*(cgusb->descriptor)));
 	cgusb->descriptor = calloc(1, sizeof(*(cgusb->descriptor)));
+	if (unlikely(!cgusb->descriptor))
+		quit(1, "USB failed to calloc _usb_init cgusb descriptor");
 
 
 	err = libusb_get_device_descriptor(dev, cgusb->descriptor);
 	err = libusb_get_device_descriptor(dev, cgusb->descriptor);
 	if (err) {
 	if (err) {
@@ -1724,6 +1687,8 @@ static struct usb_find_devices *usb_check_each(int drvnum, struct device_drv *dr
 		if (find_dev[i].drv == drvnum) {
 		if (find_dev[i].drv == drvnum) {
 			if (usb_check_device(drv, dev, &(find_dev[i]))) {
 			if (usb_check_device(drv, dev, &(find_dev[i]))) {
 				found = malloc(sizeof(*found));
 				found = malloc(sizeof(*found));
+				if (unlikely(!found))
+					quit(1, "USB failed to malloc found");
 				memcpy(found, &(find_dev[i]), sizeof(*found));
 				memcpy(found, &(find_dev[i]), sizeof(*found));
 				return found;
 				return found;
 			}
 			}
@@ -1961,13 +1926,13 @@ static void newstats(struct cgpu_info *cgpu)
 	mutex_unlock(&cgusb_lock);
 	mutex_unlock(&cgusb_lock);
 
 
 	usb_stats = realloc(usb_stats, sizeof(*usb_stats) * next_stat);
 	usb_stats = realloc(usb_stats, sizeof(*usb_stats) * next_stat);
-	if (!usb_stats)
+	if (unlikely(!usb_stats))
 		quit(1, "USB failed to realloc usb_stats %d", next_stat);
 		quit(1, "USB failed to realloc usb_stats %d", next_stat);
 
 
 	usb_stats[next_stat-1].name = cgpu->drv->name;
 	usb_stats[next_stat-1].name = cgpu->drv->name;
 	usb_stats[next_stat-1].device_id = -1;
 	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);
 	usb_stats[next_stat-1].details = calloc(1, sizeof(struct cg_usb_stats_details) * C_MAX * 2);
-	if (!usb_stats[next_stat-1].details)
+	if (unlikely(!usb_stats[next_stat-1].details))
 		quit(1, "USB failed to calloc details for %d", next_stat);
 		quit(1, "USB failed to calloc details for %d", next_stat);
 
 
 	for (i = 1; i < C_MAX * 2; i += 2)
 	for (i = 1; i < C_MAX * 2; i += 2)
@@ -2474,6 +2439,8 @@ void usb_initialise()
 				}
 				}
 
 
 				busdev = realloc(busdev, sizeof(*busdev) * (++busdev_count));
 				busdev = realloc(busdev, sizeof(*busdev) * (++busdev_count));
+				if (unlikely(!busdev))
+					quit(1, "USB failed to realloc busdev");
 
 
 				busdev[busdev_count-1].bus_number = bus;
 				busdev[busdev_count-1].bus_number = bus;
 				busdev[busdev_count-1].device_address = dev;
 				busdev[busdev_count-1].device_address = dev;
@@ -2542,3 +2509,393 @@ void usb_initialise()
 		}
 		}
 	}
 	}
 }
 }
+
+#ifndef WIN32
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+union semun {
+	int sem;
+	struct semid_ds *seminfo;
+	ushort *all;
+};
+#else
+static LPSECURITY_ATTRIBUTES unsec(LPSECURITY_ATTRIBUTES sec)
+{
+	FreeSid(((PSECURITY_DESCRIPTOR)(sec->lpSecurityDescriptor))->Group);
+	free(sec->lpSecurityDescriptor);
+	free(sec);
+	return NULL;
+}
+
+static LPSECURITY_ATTRIBUTES mksec(const char *dname, uint8_t bus_number, uint8_t device_address)
+{
+	SID_IDENTIFIER_AUTHORITY SIDAuthWorld = {SECURITY_WORLD_SID_AUTHORITY};
+	PSID gsid = NULL;
+	LPSECURITY_ATTRIBUTES sec_att = NULL;
+	PSECURITY_DESCRIPTOR sec_des = NULL;
+
+	sec_des = malloc(sizeof(*sec_des));
+	if (unlikely(!sec_des))
+		quit(1, "MTX: Failed to malloc LPSECURITY_DESCRIPTOR");
+
+	if (!InitializeSecurityDescriptor(sec_des, SECURITY_DESCRIPTOR_REVISION)) {
+		applog(LOG_ERR,
+			"MTX: %s (%d:%d) USB failed to init secdes err (%d)",
+			dname, (int)bus_number, (int)device_address,
+			GetLastError());
+		free(sec_des);
+		return NULL;
+	}
+
+	if (!SetSecurityDescriptorDacl(sec_des, TRUE, NULL, FALSE)) {
+		applog(LOG_ERR,
+			"MTX: %s (%d:%d) USB failed to secdes dacl err (%d)",
+			dname, (int)bus_number, (int)device_address,
+			GetLastError());
+		free(sec_des);
+		return NULL;
+	}
+
+	if(!AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &gsid)) {
+		applog(LOG_ERR,
+			"MTX: %s (%d:%d) USB failed to create gsid err (%d)",
+			dname, (int)bus_number, (int)device_address,
+			GetLastError());
+		free(sec_des);
+		return NULL;
+	}
+
+	if (!SetSecurityDescriptorGroup(sec_des, gsid, FALSE)) {
+		applog(LOG_ERR,
+			"MTX: %s (%d:%d) USB failed to secdes grp err (%d)",
+			dname, (int)bus_number, (int)device_address,
+			GetLastError());
+		FreeSid(gsid);
+		free(sec_des);
+		return NULL;
+	}
+
+	sec_att = malloc(sizeof(*sec_att));
+	if (unlikely(!sec_att))
+		quit(1, "MTX: Failed to malloc LPSECURITY_ATTRIBUTES");
+
+	sec_att->nLength = sizeof(*sec_att);
+	sec_att->lpSecurityDescriptor = sec_des;
+	sec_att->bInheritHandle = FALSE;
+
+	return sec_att;
+}
+#endif
+
+// Any errors should always be printed since they will rarely if ever occur
+// and thus it is best to always display them
+static bool resource_lock(const char *dname, uint8_t bus_number, uint8_t device_address)
+{
+	applog(LOG_DEBUG, "USB res lock %s %d-%d", dname, (int)bus_number, (int)device_address);
+
+#ifdef WIN32
+	struct cgpu_info *cgpu;
+	LPSECURITY_ATTRIBUTES sec;
+	HANDLE usbMutex;
+	char name[64];
+	DWORD res;
+	int i;
+
+	if (is_in_use_bd(bus_number, device_address))
+		return false;
+
+	sprintf(name, "cg-usb-%d-%d", (int)bus_number, (int)device_address);
+
+	sec = mksec(dname, bus_number, device_address);
+	if (!sec)
+		return false;
+
+	usbMutex = CreateMutex(sec, FALSE, name);
+	if (usbMutex == NULL) {
+		applog(LOG_ERR,
+			"MTX: %s USB failed to get '%s' err (%d)",
+			dname, name, GetLastError());
+		sec = unsec(sec);
+		return false;
+	}
+
+	res = WaitForSingleObject(usbMutex, 0);
+
+	switch(res) {
+		case WAIT_OBJECT_0:
+		case WAIT_ABANDONED:
+			// Am I using it already?
+			for (i = 0; i < total_devices; i++) {
+				cgpu = get_devices(i);
+				if (cgpu->usbinfo.bus_number == bus_number &&
+				    cgpu->usbinfo.device_address == device_address &&
+				    cgpu->usbinfo.nodev == false) {
+					if (ReleaseMutex(usbMutex)) {
+						applog(LOG_WARNING,
+							"MTX: %s USB can't get '%s' - device in use",
+							dname, name);
+						goto fail;
+					}
+					applog(LOG_ERR,
+						"MTX: %s USB can't get '%s' - device in use - failure (%d)",
+						dname, name, GetLastError());
+					goto fail;
+				}
+			}
+			break;
+		case WAIT_TIMEOUT:
+			if (!hotplug_mode)
+				applog(LOG_WARNING,
+					"MTX: %s USB failed to get '%s' - device in use",
+					dname, name);
+			goto fail;
+		case WAIT_FAILED:
+			applog(LOG_ERR,
+				"MTX: %s USB failed to get '%s' err (%d)",
+				dname, name, GetLastError());
+			goto fail;
+		default:
+			applog(LOG_ERR,
+				"MTX: %s USB failed to get '%s' unknown reply (%d)",
+				dname, name, res);
+			goto fail;
+	}
+
+	add_in_use(bus_number, device_address);
+	in_use_store_ress(bus_number, device_address, (void *)usbMutex, (void *)sec);
+
+	return true;
+fail:
+	CloseHandle(usbMutex);
+	sec = unsec(sec);
+	return false;
+#else
+	struct semid_ds seminfo;
+	union semun opt;
+	char name[64];
+	key_t key;
+	int fd, sem, count;
+
+	if (is_in_use_bd(bus_number, device_address))
+		return false;
+
+	sprintf(name, "/tmp/cgminer-usb-%d-%d", (int)bus_number, (int)device_address);
+	fd = open(name, O_CREAT|O_RDONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+	if (fd == -1) {
+		applog(LOG_ERR,
+			"SEM: %s USB open failed '%s' err (%d) %s",
+			dname, name, errno, strerror(errno));
+		return false;
+	}
+	close(fd);
+	key = ftok(name, 'K');
+	sem = semget(key, 1, IPC_CREAT | IPC_EXCL | 438);
+	if (sem < 0) {
+		if (errno != EEXIST) {
+			applog(LOG_ERR,
+				"SEM: %s USB failed to get '%s' err (%d) %s",
+				dname, name, errno, strerror(errno));
+			return false;
+		}
+
+		sem = semget(key, 1, 0);
+		if (sem < 0) {
+			applog(LOG_ERR,
+				"SEM: %s USB failed to access '%s' err (%d) %s",
+				dname, name, errno, strerror(errno));
+			return false;
+		}
+
+		opt.seminfo = &seminfo;
+		count = 0;
+		while (++count) {
+			// Should NEVER take 100ms
+			if (count > 99) {
+				applog(LOG_ERR,
+					"SEM: %s USB timeout waiting for (%d) '%s'",
+					dname, sem, name);
+				return false;
+			}
+			if (semctl(sem, 0, IPC_STAT, opt) == -1) {
+				applog(LOG_ERR,
+					"SEM: %s USB failed to wait for (%d) '%s' count %d err (%d) %s",
+					dname, sem, name, count, errno, strerror(errno));
+				return false;
+			}
+			if (opt.seminfo->sem_otime != 0)
+				break;
+			nmsleep(1);
+		}
+	}
+
+	struct sembuf sops[] = {
+		{ 0, 0, IPC_NOWAIT | SEM_UNDO },
+		{ 0, 1, IPC_NOWAIT | SEM_UNDO }
+	};
+
+	if (semop(sem, sops, 2)) {
+		if (errno == EAGAIN) {
+			if (!hotplug_mode)
+				applog(LOG_WARNING,
+					"SEM: %s USB failed to get (%d) '%s' - device in use",
+					dname, sem, name);
+		} else {
+			applog(LOG_DEBUG,
+				"SEM: %s USB failed to get (%d) '%s' err (%d) %s",
+				dname, sem, name, errno, strerror(errno));
+		}
+		return false;
+	}
+
+	add_in_use(bus_number, device_address);
+	return true;
+#endif
+}
+
+// Any errors should always be printed since they will rarely if ever occur
+// and thus it is best to always display them
+static void resource_unlock(const char *dname, uint8_t bus_number, uint8_t device_address)
+{
+	applog(LOG_DEBUG, "USB res unlock %s %d-%d", dname, (int)bus_number, (int)device_address);
+
+#ifdef WIN32
+	LPSECURITY_ATTRIBUTES sec = NULL;
+	HANDLE usbMutex = NULL;
+	char name[64];
+
+	sprintf(name, "cg-usb-%d-%d", (int)bus_number, (int)device_address);
+
+	in_use_get_ress(bus_number, device_address, (void **)(&usbMutex), (void **)(&sec));
+
+	if (!usbMutex || !sec)
+		goto fila;
+
+	if (!ReleaseMutex(usbMutex))
+		applog(LOG_ERR,
+			"MTX: %s USB failed to release '%s' err (%d)",
+			dname, name, GetLastError());
+
+fila:
+
+	if (usbMutex)
+		CloseHandle(usbMutex);
+	if (sec)
+		unsec(sec);
+	remove_in_use(bus_number, device_address);
+	return;
+#else
+	char name[64];
+	key_t key;
+	int fd, sem;
+
+	sprintf(name, "/tmp/cgminer-usb-%d-%d", (int)bus_number, (int)device_address);
+	fd = open(name, O_CREAT|O_RDONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+	if (fd == -1) {
+		applog(LOG_ERR,
+			"SEM: %s USB open failed '%s' for release err (%d) %s",
+			dname, name, errno, strerror(errno));
+		return;
+	}
+	close(fd);
+	key = ftok(name, 'K');
+
+	sem = semget(key, 1, 0);
+	if (sem < 0) {
+		applog(LOG_ERR,
+			"SEM: %s USB failed to get '%s' for release err (%d) %s",
+			dname, name, errno, strerror(errno));
+		return;
+	}
+
+	struct sembuf sops[] = {
+		{ 0, -1, SEM_UNDO }
+	};
+
+	// Allow a 10ms timeout
+	// exceeding this timeout means it would probably never succeed anyway
+	struct timespec timeout = { 0, 10000000 };
+
+	// Wait forever since we shoud be the one who has it
+	if (semtimedop(sem, sops, 1, &timeout)) {
+		applog(LOG_ERR,
+			"SEM: %s USB failed to release '%s' err (%d) %s",
+			dname, name, errno, strerror(errno));
+	}
+
+	remove_in_use(bus_number, device_address);
+	return;
+#endif
+}
+
+static void resource_process()
+{
+	struct resource_work *res_work = NULL;
+	struct resource_reply *res_reply = NULL;
+	bool ok;
+
+	applog(LOG_DEBUG, "RES: %s (%d:%d) lock=%d",
+			res_work_head->dname,
+			(int)res_work_head->bus_number,
+			(int)res_work_head->device_address,
+			res_work_head->lock);
+
+	if (res_work_head->lock) {
+		ok = resource_lock(res_work_head->dname,
+					res_work_head->bus_number,
+					res_work_head->device_address);
+
+		applog(LOG_DEBUG, "RES: %s (%d:%d) lock ok=%d",
+				res_work_head->dname,
+				(int)res_work_head->bus_number,
+				(int)res_work_head->device_address,
+				ok);
+
+		res_reply = calloc(1, sizeof(*res_reply));
+		if (unlikely(!res_reply))
+			quit(1, "USB failed to calloc res_reply");
+
+		res_reply->bus_number = res_work_head->bus_number;
+		res_reply->device_address = res_work_head->device_address;
+		res_reply->got = ok;
+		res_reply->next = res_reply_head;
+
+		res_reply_head = res_reply;
+	}
+	else
+		resource_unlock(res_work_head->dname,
+				res_work_head->bus_number,
+				res_work_head->device_address);
+
+	res_work = res_work_head;
+	res_work_head = res_work_head->next;
+	free(res_work);
+}
+
+void *usb_resource_thread(void __maybe_unused *userdata)
+{
+	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+
+	RenameThread("usbresource");
+
+	applog(LOG_DEBUG, "RES: thread starting");
+
+	while (0*1337+1) {
+		mutex_lock(&cgusbres_lock);
+
+		while (res_work_head)
+			resource_process();
+
+		mutex_unlock(&cgusbres_lock);
+
+		nmsleep(45);
+	}
+
+	return NULL;
+}

+ 11 - 1
usbutils.h

@@ -41,11 +41,19 @@
 #define FTDI_VALUE_BAUD_BLT 0x001a
 #define FTDI_VALUE_BAUD_BLT 0x001a
 #define FTDI_INDEX_BAUD_BLT 0x0000
 #define FTDI_INDEX_BAUD_BLT 0x0000
 
 
+// Avalon
 #define FTDI_VALUE_BAUD_AVA 0x001A
 #define FTDI_VALUE_BAUD_AVA 0x001A
 #define FTDI_INDEX_BAUD_AVA 0x0000
 #define FTDI_INDEX_BAUD_AVA 0x0000
 
 
 #define FTDI_VALUE_DATA_AVA 8
 #define FTDI_VALUE_DATA_AVA 8
 
 
+// CMR = 115200 & 57600
+#define FTDI_VALUE_BAUD_CMR_115 0xc068
+#define FTDI_INDEX_BAUD_CMR_115 0x0200
+
+#define FTDI_VALUE_BAUD_CMR_57 0x80d0
+#define FTDI_INDEX_BAUD_CMR_57 0x0200
+
 // Data control
 // Data control
 #define FTDI_VALUE_DATA_BFL 0
 #define FTDI_VALUE_DATA_BFL 0
 #define FTDI_VALUE_DATA_BAS FTDI_VALUE_DATA_BFL
 #define FTDI_VALUE_DATA_BAS FTDI_VALUE_DATA_BFL
@@ -114,7 +122,8 @@ enum sub_ident {
 	IDENT_AMU,
 	IDENT_AMU,
 	IDENT_BLT,
 	IDENT_BLT,
 	IDENT_LLT,
 	IDENT_LLT,
-	IDENT_CMR,
+	IDENT_CMR1,
+	IDENT_CMR2,
 	IDENT_ZTX
 	IDENT_ZTX
 };
 };
 
 
@@ -244,6 +253,7 @@ int _usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest
 int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, char *buf, int bufsiz, int *amount, unsigned int timeout, enum usb_cmds cmd);
 int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, char *buf, int bufsiz, int *amount, unsigned int timeout, enum usb_cmds cmd);
 void usb_cleanup();
 void usb_cleanup();
 void usb_initialise();
 void usb_initialise();
+void *usb_resource_thread(void *userdata);
 
 
 #define usb_read(cgpu, buf, bufsiz, read, cmd) \
 #define usb_read(cgpu, buf, bufsiz, read, cmd) \
 	_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false)
 	_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false)