Browse Source

cointerra: New driver, probing number of pipes

Luke Dashjr 12 years ago
parent
commit
1df899ed7b
1 changed files with 146 additions and 0 deletions
  1. 146 0
      driver-cointerra.c

+ 146 - 0
driver-cointerra.c

@@ -0,0 +1,146 @@
+/*
+ * Copyright 2014 Luke Dashjr
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "deviceapi.h"
+#include "logging.h"
+#include "lowlevel.h"
+#include "lowl-usb.h"
+
+#define COINTERRA_EP_R  (LIBUSB_ENDPOINT_IN  | 1)
+#define COINTERRA_EP_W  (LIBUSB_ENDPOINT_OUT | 1)
+#define COINTERRA_USB_TIMEOUT  100
+#define COINTERRA_PACKET_SIZE  0x40
+#define COINTERRA_START_SEQ  0x5a,0x5a
+#define COINTERRA_MSG_SIZE  (COINTERRA_PACKET_SIZE - sizeof(cointerra_startseq))
+
+BFG_REGISTER_DRIVER(cointerra_drv)
+
+enum cointerra_msg_type_out {
+	CMTO_RESET     = 1,
+	CMTO_WORK      = 2,
+	CMTO_REQUEST   = 4,
+	CMTO_HWERR     = 5,
+	CMTO_LEDCTL    = 6,
+	CMTO_HASHRATE  = 7,
+};
+
+enum cointerra_msg_type_in {
+	CMTI_WORKREQ   = 1,
+	CMTI_MATCH     = 2,
+	CMTI_WORKDONE  = 3,
+	CMTI_STATUS    = 4,
+	CMTI_SETTINGS  = 5,
+	CMTI_INFO      = 6,
+	CMTI_LOGMSG    = 7,
+	CMTI_RESETDONE = 8,
+	CMTI_ERRINFO   = 0xa,
+};
+
+static const uint8_t cointerra_startseq[] = {COINTERRA_START_SEQ};
+
+static
+int cointerra_read_msg(uint8_t * const out_msgtype, uint8_t * const out, libusb_device_handle * const usbh, const char * const repr, const unsigned timeout)
+{
+	uint8_t ss[] = {COINTERRA_START_SEQ};
+	uint8_t buf[COINTERRA_PACKET_SIZE];
+	int e, xfer;
+	e = libusb_bulk_transfer(usbh, COINTERRA_EP_R, buf, sizeof(buf), &xfer, timeout);
+	if (e)
+		return e;
+	if (xfer != COINTERRA_PACKET_SIZE)
+		applogr(LIBUSB_ERROR_OTHER, LOG_ERR, "%s: Packet size mismatch (actual=%d expected=%d)",
+		        repr, xfer, (int)COINTERRA_PACKET_SIZE);
+	for (int i = sizeof(ss); i--; )
+		if (ss[i] != buf[i])
+			applogr(LIBUSB_ERROR_OTHER;, LOG_ERR, "%s: Packet start sequence mismatch", repr);
+	uint8_t * const bufp = &buf[sizeof(ss)];
+	*out_msgtype = upk_u8(bufp, 0);
+	memcpy(out, &bufp[1], COINTERRA_MSGBODY_SIZE);
+	return 0;
+}
+
+static
+bool cointerra_lowl_match(const struct lowlevel_device_info * const info)
+{
+	return lowlevel_match_lowlproduct(info, &lowl_usb, "GoldStrike");
+}
+
+static
+bool cointerra_lowl_probe(const struct lowlevel_device_info * const info)
+{
+	int e;
+	
+	if (info->lowl != &lowl_usb)
+		applogr(false, LOG_DEBUG, "%s: Matched \"%s\" %s, but lowlevel driver is not usb_generic!",
+		        __func__, info->product, info->devid);
+	
+	libusb_device_handle *usbh;
+	e = libusb_open(info->lowl_data, &usbh);
+	if (e)
+		applogr(false, LOG_ERR, "%s: Failed to open %s: %s",
+		        cointerra_drv.dname, info->devid, bfg_strerror(e, BST_LIBUSB));
+	
+	unsigned pipes;
+	{
+		uint8_t buf[COINTERRA_PACKET_SIZE] = {
+			COINTERRA_START_SEQ,
+			CMTO_REQUEST,
+			CMTI_INFO, 0,
+		};
+		int xfer;
+		uint8_t msgtype;
+		
+		e = libusb_bulk_transfer(usbh, COINTERRA_EP_W, buf, sizeof(buf), &xfer, COINTERRA_USB_TIMEOUT);
+		if (e)
+			return e;
+		
+		while (true)
+		{
+			e = cointerra_read_msg(&msgtype, buf, usbh, cointerra_drv.dname, COINTERRA_USB_TIMEOUT);
+			if (e)
+				return e;
+			if (msgtype == CMTI_INFO)
+				break;
+			// FIXME: Timeout if we keep getting packets we don't care about
+		}
+		
+		pipes = upk_u16le(buf, 8);
+	}
+	
+	applog(LOG_DEBUG, "%s: Found %u pipes on %s",
+	       __func__, pipes, info->devid);
+	
+	struct cgpu_info * const cgpu = malloc(sizeof(*cgpu));
+	*cgpu = (struct cgpu_info){
+		.drv = &cointerra_drv,
+		.procs = pipes,
+		.device_data = lowlevel_ref(info),
+		.threads = 1,
+		.device_path = strdup(info->devid),
+		.dev_manufacturer = maybe_strdup(info->manufacturer),
+		.dev_product = maybe_strdup(info->product),
+		.dev_serial = maybe_strdup(info->serial),
+		.deven = DEV_ENABLED,
+	};
+	return add_cgpu(cgpu);
+}
+
+struct device_drv cointerra_drv = {
+	.dname = "cointerra",
+	.name = "CTA",
+	
+	.lowl_match = cointerra_lowl_match,
+	.lowl_probe = cointerra_lowl_probe,
+};