|
@@ -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;
|
|
|
|
|
+}
|