Commit 584dc5acd56a5a74bf31d01c986652d158839773

Peter Stuge 2012-11-30T03:21:12

libztex: Download mining firmware to all devices with dummy firmware When one or more ZTEX devices with dummy firmware are found on startup, the correct firmware is downloaded to each device, and then USB devices are rescanned until all devices have reattached with the mining firmware. This allows to discover and configure all ZTEX devices and start mining directly, without first running the ZTEX Java software to download a firmware to the device.

diff --git a/libztex.c b/libztex.c
index f9fefed..ca81b41 100644
--- a/libztex.c
+++ b/libztex.c
@@ -2,6 +2,8 @@
  *   libztex.c - Ztex 1.15x fpga board support library
  *
  *   Copyright (c) 2012 nelisky.btc@gmail.com
+ *   Copyright (c) 2012 Denis Ahrens <denis@h3q.com>
+ *   Copyright (c) 2012 Peter Stuge <peter@stuge.se>
  *
  *   This work is based upon the Java SDK provided by ztex which is
  *   Copyright (C) 2009-2011 ZTEX GmbH.
@@ -47,21 +49,147 @@
 #define CAPABILITY_MULTI_FPGA 0,7
 
 
-static bool libztex_checkDevice(struct libusb_device *dev)
+enum check_result {
+	CHECK_ERROR,
+	CHECK_IS_NOT_ZTEX,
+	CHECK_OK,
+	CHECK_RESCAN,
+};
+
+static enum check_result libztex_checkDevice(struct libusb_device *dev)
 {
+	FILE *fp = NULL;
+	libusb_device_handle *hndl = NULL;
 	struct libusb_device_descriptor desc;
-	int err;
+	int i, ret = CHECK_ERROR, err, cnt;
+	size_t got_bytes, length;
+	unsigned char buf[64], *fw_buf;
+	char *firmware = "ztex_ufm1_15y1.bin";
 
 	err = libusb_get_device_descriptor(dev, &desc);
 	if (unlikely(err != 0)) {
 		applog(LOG_ERR, "Ztex check device: Failed to open read descriptor with error %d", err);
-		return false;
+		return CHECK_ERROR;
 	}
-	if (!(desc.idVendor == LIBZTEX_IDVENDOR && desc.idProduct == LIBZTEX_IDPRODUCT)) {
+
+	if (desc.idVendor != LIBZTEX_IDVENDOR || desc.idProduct != LIBZTEX_IDPRODUCT) {
 		applog(LOG_DEBUG, "Not a ZTEX device %0.4x:%0.4x", desc.idVendor, desc.idProduct);
-		return false;
+		return CHECK_IS_NOT_ZTEX;
 	}
-	return true;
+
+	err = libusb_open(dev, &hndl);
+	if (err != LIBUSB_SUCCESS) {
+		applog(LOG_ERR, "%s: Can not open ZTEX device: %s", __func__, libusb_error_name(err));
+		goto done;
+	}
+
+	cnt = libusb_control_transfer(hndl, 0xc0, 0x22, 0, 0, buf, 40, 500);
+	if (unlikely(cnt < 0)) {
+		applog(LOG_ERR, "Ztex check device: Failed to read ztex descriptor with err %d", cnt);
+		goto done;
+	}
+
+	if (buf[0] != 40 || buf[1] != 1 || buf[2] != 'Z' || buf[3] != 'T' || buf[4] != 'E' || buf[5] != 'X') {
+		applog(LOG_ERR, "Ztex check device: Error reading ztex descriptor");
+		goto done;
+	}
+
+	if (buf[6] != 10)
+	{
+		ret = CHECK_IS_NOT_ZTEX;
+		goto done;
+	}
+
+	// 15 = 1.15y   13 = 1.15d or 1.15x
+	switch(buf[7])
+	{
+		case 13:
+			applog(LOG_ERR, "Found ztex board 1.15d or 1.15x but currently unsupported!");
+			ret = CHECK_IS_NOT_ZTEX;
+			goto done;
+		case 15:
+			applog(LOG_ERR, "Found ztex board 1.15y");
+			break;
+		default:
+			applog(LOG_ERR, "Found unknown ztex board");
+			ret = CHECK_IS_NOT_ZTEX;
+			goto done;
+	}
+
+	// testing for dummy firmware
+	if (buf[8] != 0) {
+		ret = CHECK_OK;
+		goto done;
+	}
+
+	applog(LOG_ERR, "Found dummy firmware, trying to send mining firmware: %s", firmware);
+
+	// reset 1
+	buf[0] = 1;
+	cnt = libusb_control_transfer(hndl, 0x40, 0xA0, 0xE600, 0, buf, 1,1000);
+	if (cnt < 0)
+	{
+		applog(LOG_ERR, "Ztex reset 1 failed: %s", libusb_error_name(cnt));
+		goto done;
+	}
+
+	fp = open_bitstream("ztex", firmware);
+	if (!fp) {
+		applog(LOG_ERR, "failed to open firmware file '%s'", firmware);
+		goto done;
+	}
+
+	if (0 != fseek(fp, 0, SEEK_END)) {
+		applog(LOG_ERR, "Ztex firmware fseek: %s", strerror(errno));
+		goto done;
+	}
+
+	length = ftell(fp);
+	rewind(fp);
+	fw_buf = malloc(length);
+	if (!fw_buf) {
+		applog(LOG_ERR, "%s: Can not allocate memory: %s", __func__, strerror(errno));
+		goto done;
+	}
+
+	got_bytes = fread(fw_buf, 1, length, fp);
+	fclose(fp);
+	fp = NULL;
+
+	if (got_bytes < length) {
+		applog(LOG_ERR, "%s: Incomplete firmware read: %d/%d", __func__, got_bytes, length);
+		goto done;
+	}
+
+	for (i = 0; i < length; i+= 256) {
+		// firmware wants data in small chunks like 256 bytes
+		int numbytes = (length - i) < 256 ? (length - i) : 256;
+		int k = libusb_control_transfer(hndl, 0x40, 0xA0, i, 0, fw_buf + i, numbytes, 1000);
+		if (k < numbytes)
+		{
+			applog(LOG_ERR, "Ztex device: Failed to write firmware at %d with: %s", i, libusb_error_name(k));
+			goto done;
+		}
+	}
+
+	// reset 0
+	buf[0] = 0;
+	err = libusb_control_transfer(hndl, 0x40, 0xA0, 0xE600, 0, buf, 1,1000);
+	if (err < 0)
+	{
+		applog(LOG_ERR, "Ztex reset 0 failed: %s", libusb_error_name(err));
+		goto done;
+	}
+
+	applog(LOG_ERR, "Ztex device: succesfully wrote firmware");
+	ret = CHECK_RESCAN;
+
+done:
+	if (fp)
+		fclose(fp);
+	if (hndl)
+		libusb_close(hndl);
+	return ret;
 }
 
 static bool libztex_checkCapability(struct libztex_device *ztex, int i, int j)
@@ -408,35 +536,21 @@ int libztex_suspend(struct libztex_device *ztex) {
 }
 
 int libztex_prepare_device(struct libusb_device *dev, struct libztex_device** ztex) {
-	struct libztex_device *newdev;
+	struct libztex_device *newdev = *ztex;
 	int i, cnt, err;
 	unsigned char buf[64];
 	uint16_t langid;
 
-	newdev = malloc(sizeof(struct libztex_device));
-	newdev->bitFileName = NULL;
-	newdev->numberOfFpgas = -1;
-	newdev->valid = false;
-	newdev->hndl = NULL;
-	*ztex = newdev;
+	err = libusb_open(dev, &newdev->hndl);
+	if (err != LIBUSB_SUCCESS) {
+		applog(LOG_ERR, "%s: Can not open ZTEX device: %s", __func__, libusb_error_name(err));
+		return CHECK_ERROR;
+	}
 
 	err = libusb_get_device_descriptor(dev, &newdev->descriptor);
 	if (unlikely(err != 0)) {
 		applog(LOG_ERR, "Ztex check device: Failed to open read descriptor with error %d", err);
-		return err;
-	}
-
-	// Check vendorId and productId
-	if (!(newdev->descriptor.idVendor == LIBZTEX_IDVENDOR &&
-	    newdev->descriptor.idProduct == LIBZTEX_IDPRODUCT)) {
-		applog(LOG_ERR, "Not a ztex device? %0.4X, %0.4X", newdev->descriptor.idVendor, newdev->descriptor.idProduct);
-		return 1;
-	}
-
-	err = libusb_open(dev, &newdev->hndl);
-	if (unlikely(err != 0)) {
-		applog(LOG_ERR, "Ztex check device: Failed to open handle with error %d", err);
-		return err;
+		return CHECK_ERROR;
 	}
 
 	/* We open code string descriptor retrieval and ASCII decoding here
@@ -587,52 +701,104 @@ void libztex_destroy_device(struct libztex_device* ztex)
 int libztex_scanDevices(struct libztex_dev_list*** devs_p)
 {
 	int usbdevices[LIBZTEX_MAX_DESCRIPTORS];
-	struct libztex_dev_list **devs;
-	struct libztex_device *ztex;
-	int found = 0, pos = 0, err;
-	libusb_device **list;
-	ssize_t cnt, i = 0;
-
-	cnt = libusb_get_device_list(NULL, &list);
-	if (unlikely(cnt < 0)) {
-		applog(LOG_ERR, "Ztex scan devices: Failed to list usb devices with err %d", cnt);
-		return 0;
-	}
+	struct libztex_dev_list **devs = NULL;
+	struct libusb_device_descriptor dev_descr;
+	struct libztex_device *ztex = NULL;
+	int found, max_found = 0, pos = 0, err, rescan, ret = 0;
+	libusb_device **list = NULL;
+	ssize_t cnt, i;
+
+	do {
+		cnt = libusb_get_device_list(NULL, &list);
+		if (unlikely(cnt < 0)) {
+			applog(LOG_ERR, "Ztex scan devices: Failed to list usb devices with err %d", cnt);
+			goto done;
+		}
 
-	for (i = 0; i < cnt; i++) {
-		if (libztex_checkDevice(list[i])) {
-			// Got one!
-			usbdevices[found] = i;
-			found++;
+		for (found = rescan = i = 0; i < cnt; i++) {
+			err = libztex_checkDevice(list[i]);
+			switch (err) {
+			case CHECK_ERROR:
+				applog(LOG_ERR, "Ztex: Can not check device: %s", libusb_error_name(err));
+				continue;
+			case CHECK_IS_NOT_ZTEX:
+				continue;
+			case CHECK_OK:
+				// Got one!
+				usbdevices[found++] = i;
+				break;
+			case CHECK_RESCAN:
+				rescan = 1;
+				found++;
+				break;
+			}
 		}
-	}
+
+		if (found < max_found)
+			rescan = 1;
+		else if (found > max_found)
+			max_found = found;
+
+		if (rescan)
+			libusb_free_device_list(list, 1);
+	} while (rescan);
+
+	if (0 == found)
+		goto done;
 
 	devs = malloc(sizeof(struct libztex_dev_list *) * found);
 	if (devs == NULL) {
 		applog(LOG_ERR, "Ztex scan devices: Failed to allocate memory");
-		return 0;
+		goto done;
 	}
 
 	for (i = 0; i < found; i++) {
+		if (!ztex) {
+			ztex = malloc(sizeof(*ztex));
+			if (!ztex) {
+				applog(LOG_ERR, "%s: Can not allocate memory for device struct: %s", __func__, strerror(errno));
+				goto done;
+			}
+		}
+
+		ztex->bitFileName = NULL;
+		ztex->numberOfFpgas = -1;
+		ztex->valid = false;
+
 		err = libztex_prepare_device(list[usbdevices[i]], &ztex);
-		if (unlikely(err != 0))
+		if (unlikely(err != 0)) {
 			applog(LOG_ERR, "prepare device: %d", err);
-		// check if valid
-		if (!ztex->valid) {
 			libztex_destroy_device(ztex);
+			ztex = NULL;
 			continue;
 		}
+
 		devs[pos] = malloc(sizeof(struct libztex_dev_list));
+		if (NULL == devs[pos]) {
+			applog(LOG_ERR, "%s: Can not allocate memory for device: %s", __func__, strerror(errno));
+			libztex_destroy_device(ztex);
+			ztex = NULL;
+			continue;
+		}
+
 		devs[pos]->dev = ztex;
+		ztex = NULL;
 		devs[pos]->next = NULL;
 		if (pos > 0)
 			devs[pos - 1]->next = devs[pos];
 		pos++;
 	}
 
-	libusb_free_device_list(list, 1);
-	*devs_p = devs;
-	return pos;
+	ret = pos;
+
+done:
+	if (ret > 0)
+		*devs_p = devs;
+	else if (devs)
+		free(devs);
+	if (list)
+		libusb_free_device_list(list, 1);
+	return ret;
 }
 
 int libztex_sendHashData(struct libztex_device *ztex, unsigned char *sendbuf)