+#endif
+ }
+}
+
+static int get_usb_mass_storage_status(libusb_device_handle *handle, uint8_t endpoint, uint32_t *tag)
+{
+ unsigned char csw[13];
+ memset(csw, 0, sizeof(csw));
+ int transferred;
+ int ret;
+ int try = 0;
+ do {
+ ret = libusb_bulk_transfer(handle, endpoint, (unsigned char *)&csw, sizeof(csw),
+ &transferred, SG_TIMEOUT_MSEC);
+ if (ret == LIBUSB_ERROR_PIPE) {
+ libusb_clear_halt(handle, endpoint);
+ }
+ try++;
+ } while ((ret == LIBUSB_ERROR_PIPE) && (try < 3));
+ if (ret != LIBUSB_SUCCESS) {
+ fprintf(stderr, "%s: receiving failed: %d\n", __func__, ret);
+ return -1;
+ }
+ if (transferred != sizeof(csw)) {
+ fprintf(stderr, "%s: received unexpected amount: %d\n", __func__, transferred);
+ return -1;
+ }
+
+ uint32_t rsig = read_uint32(csw, 0);
+ uint32_t rtag = read_uint32(csw, 4);
+ uint32_t residue = read_uint32(csw, 8);
+#define USB_CSW_SIGNATURE 0x53425355 // 'U' 'S' 'B' 'S' (reversed)
+ if (rsig != USB_CSW_SIGNATURE) {
+ WLOG("status signature was invalid: %#x\n", rsig);
+ return -1;
+ }
+ DLOG("residue was= %#x\n", residue);
+ *tag = rtag;
+ uint8_t rstatus = csw[12];
+ DLOG("rstatus = %x\n", rstatus);
+ return rstatus;
+}
+
+static int dump_CDB_command(uint8_t *cdb, uint8_t cdb_len) {
+ char dbugblah[100];
+ char *dbugp = dbugblah;
+ dbugp += sprintf(dbugp, "Sending CDB [");
+ for (uint8_t i = 0; i < cdb_len; i++) {
+ dbugp += sprintf(dbugp, " %#02x", (unsigned int) cdb[i]);
+ }
+ sprintf(dbugp, "]\n");
+ DLOG(dbugblah);
+ return 0;
+}
+
+/**
+ * Wraps a CDB mass storage command in the appropriate gunk to get it down
+ * @param handle
+ * @param endpoint
+ * @param cdb
+ * @param cdb_length
+ * @param lun
+ * @param flags
+ * @param expected_rx_size
+ * @return
+ */
+int send_usb_mass_storage_command(libusb_device_handle *handle, uint8_t endpoint_out,
+ uint8_t *cdb, uint8_t cdb_length,
+ uint8_t lun, uint8_t flags, uint32_t expected_rx_size) {
+ DLOG("Sending usb m-s cmd: cdblen:%d, rxsize=%d\n", cdb_length, expected_rx_size);
+ dump_CDB_command(cdb, cdb_length);
+
+ static uint32_t tag;
+ if (tag == 0) {
+ tag = 1;
+ }
+
+ int try = 0;
+ int ret = 0;
+ int real_transferred;
+ int i = 0;
+
+ uint8_t c_buf[STLINK_SG_SIZE];
+ // tag is allegedly ignored... TODO - verify
+ c_buf[i++] = 'U';
+ c_buf[i++] = 'S';
+ c_buf[i++] = 'B';
+ c_buf[i++] = 'C';
+ write_uint32(&c_buf[i], tag);
+ uint32_t this_tag = tag++;
+ write_uint32(&c_buf[i+4], expected_rx_size);
+ i+= 8;
+ c_buf[i++] = flags;
+ c_buf[i++] = lun;
+
+ c_buf[i++] = cdb_length;
+
+ // Now the actual CDB request
+ assert(cdb_length <= CDB_SL);
+ memcpy(&(c_buf[i]), cdb, cdb_length);
+
+ int sending_length = STLINK_SG_SIZE;
+ DLOG("sending length set to: %d\n", sending_length);
+
+ // send....
+ do {
+ DLOG("attempting tx...\n");
+ ret = libusb_bulk_transfer(handle, endpoint_out, c_buf, sending_length,
+ &real_transferred, SG_TIMEOUT_MSEC);
+ if (ret == LIBUSB_ERROR_PIPE) {
+ libusb_clear_halt(handle, endpoint_out);
+ }
+ try++;
+ } while ((ret == LIBUSB_ERROR_PIPE) && (try < 3));
+ if (ret != LIBUSB_SUCCESS) {
+ WLOG("sending failed: %d\n", ret);
+ return -1;
+ }
+ DLOG("Actually sent: %d, returning tag: %d\n", real_transferred, tag);
+ return this_tag;
+}
+
+
+/**
+ * Straight from stm8 stlink code...
+ * @param handle
+ * @param endpoint_in
+ * @param endpoint_out
+ */
+static void
+get_sense(libusb_device_handle *handle, uint8_t endpoint_in, uint8_t endpoint_out)
+{
+ DLOG("Fetching sense...\n");
+ uint8_t cdb[16];
+ memset(cdb, 0, sizeof(cdb));
+#define REQUEST_SENSE 0x03
+#define REQUEST_SENSE_LENGTH 18
+ cdb[0] = REQUEST_SENSE;
+ cdb[4] = REQUEST_SENSE_LENGTH;
+ uint32_t tag = send_usb_mass_storage_command(handle, endpoint_out, cdb, sizeof(cdb), 0,
+ LIBUSB_ENDPOINT_IN, REQUEST_SENSE_LENGTH);
+ if (tag == 0) {
+ WLOG("refusing to send request sense with tag 0\n");
+ return;
+ }
+ unsigned char sense[REQUEST_SENSE_LENGTH];
+ int transferred;
+ int ret;
+ int try = 0;
+ do {
+ ret = libusb_bulk_transfer(handle, endpoint_in, sense, sizeof(sense),
+ &transferred, SG_TIMEOUT_MSEC);
+ if (ret == LIBUSB_ERROR_PIPE) {
+ libusb_clear_halt(handle, endpoint_in);
+ }
+ try++;
+ } while ((ret == LIBUSB_ERROR_PIPE) && (try < 3));
+ if (ret != LIBUSB_SUCCESS) {
+ WLOG("receiving sense failed: %d\n", ret);
+ return;
+ }
+ if (transferred != sizeof(sense)) {
+ WLOG("received unexpected amount of sense: %d != %d\n", transferred, sizeof(sense));
+ }
+ uint32_t received_tag;
+ int status = get_usb_mass_storage_status(handle, endpoint_in, &received_tag);
+ if (status != 0) {
+ WLOG("receiving sense failed with status: %02x\n", status);
+ return;
+ }
+ if (sense[0] != 0x70 && sense[0] != 0x71) {
+ WLOG("No sense data\n");
+ } else {
+ WLOG("Sense KCQ: %02X %02X %02X\n", sense[2] & 0x0f, sense[12], sense[13]);