OpenCBM
xum1541.c
Go to the documentation of this file.
1 /*
2  * xum1541 driver for bulk and control messages
3  * Copyright 2009-2010 Nate Lawson <nate@root.org>
4  * Copyright 2010 Spiro Trikaliotis
5  * Copyright 2012 Arnd Menge
6  *
7  * Incorporates some code from the xu1541 driver by:
8  * Copyright 2007 Till Harbaum <till@harbaum.org>
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version
13  * 2 of the License, or (at your option) any later version.
14  */
15 
23 // This XUM1541 plugin has tape support.
24 #define TAPE_SUPPORT 1
25 
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <errno.h>
31 
32 #include "opencbm.h"
33 
34 #include "arch.h"
35 #include "dynlibusb.h"
36 #include "getpluginaddress.h"
37 #include "xum1541.h"
38 
39 // XXX Fix for Linux/Mac build, should be moved
40 #ifndef LIBUSB_PATH_MAX
41 #define LIBUSB_PATH_MAX 512
42 #endif
43 
44 static int debug_level = -1;
46 unsigned char DeviceDriveMode; // Temporary disk/tape mode hack until usb device handle context is there.
47 
56 static void
57 xum1541_dbg(int level, char *msg, ...)
58 {
59  va_list argp;
60 
61  /* determine debug mode if not yet known */
62  if (debug_level == -1) {
63  char *val = getenv("XUM1541_DEBUG");
64  if (val)
65  debug_level = atoi(val);
66  }
67 
68  if (level <= debug_level) {
69  fprintf(stderr, "[XUM1541] ");
70  va_start(argp, msg);
71  vfprintf(stderr, msg, argp);
72  va_end(argp);
73  fprintf(stderr, "\n");
74  }
75 }
76 
98 static int
99 usbGetStringAscii(usb_dev_handle *dev, int index, int langid,
100  char *buf, int buflen)
101 {
102  char buffer[256];
103  int rval, i;
104 
105  rval = usb.control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
106  (USB_DT_STRING << 8) + index, langid,
107  buffer, sizeof(buffer), 1000);
108  if (rval < 0)
109  return rval;
110 
111  if (buffer[1] != USB_DT_STRING)
112  return 0;
113  if ((unsigned char)buffer[0] < rval)
114  rval = (unsigned char)buffer[0];
115 
116  rval /= 2;
117  /* lossy conversion to ISO Latin1 */
118  for (i = 1; i < rval; i++) {
119  if (i > buflen) /* destination buffer overflow */
120  break;
121  buf[i-1] = buffer[2 * i];
122  if (buffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */
123  buf[i-1] = '?';
124  }
125  buf[i-1] = 0;
126  return i - 1;
127 }
128 
129 // Cleanup after a failure
130 static void
131 xum1541_cleanup(usb_dev_handle **HandleXum1541, char *msg, ...)
132 {
133  va_list args;
134 
135  if (msg != NULL) {
136  va_start(args, msg);
137  fprintf(stderr, msg, args);
138  va_end(args);
139  }
140  if (*HandleXum1541 != NULL)
141  usb.close(*HandleXum1541);
142  *HandleXum1541 = NULL;
143 }
144 
145 // USB bus enumeration
146 static void
147 xum1541_enumerate(usb_dev_handle **HandleXum1541, int PortNumber)
148 {
149  static char xumProduct[] = "xum1541"; // Start of USB product string id
150  static int prodLen = sizeof(xumProduct) - 1;
151  struct usb_bus *bus;
152  struct usb_device *dev, *preferredDefaultHandle;
153  char string[256];
154  int len, serialnum, leastserial;
155 
156  if (PortNumber < 0 || PortNumber > MAX_ALLOWED_XUM1541_SERIALNUM) {
157  // Normalise the Portnumber for invalid values
158  PortNumber = 0;
159  }
160 
161  xum1541_dbg(0, "scanning usb ...");
162 
163  usb.init();
164  usb.find_busses();
165  usb.find_devices();
166 
167  /* usb.find_devices sets errno if some devices don't reply 100% correct. */
168  /* make lib ignore this as this has nothing to do with our device */
169  errno = 0;
170 
171  *HandleXum1541 = NULL;
172  preferredDefaultHandle = NULL;
173  leastserial = MAX_ALLOWED_XUM1541_SERIALNUM + 1;
174  for (bus = usb.get_busses(); !*HandleXum1541 && bus; bus = bus->next) {
175  xum1541_dbg(1, "scanning bus %s", bus->dirname);
176  for (dev = bus->devices; !*HandleXum1541 && dev; dev = dev->next) {
177  xum1541_dbg(1, "device %04x:%04x at %s",
178  dev->descriptor.idVendor, dev->descriptor.idProduct,
179  dev->filename);
180 
181  // First, find our vendor and product id
182  if (dev->descriptor.idVendor != XUM1541_VID ||
183  dev->descriptor.idProduct != XUM1541_PID)
184  continue;
185 
186  xum1541_dbg(0, "found xu/xum1541 version %04x on bus %s, device %s",
187  dev->descriptor.bcdDevice, bus->dirname, dev->filename);
188  if ((*HandleXum1541 = usb.open(dev)) == NULL) {
189  fprintf(stderr, "error: Cannot open USB device: %s\n",
190  usb.strerror());
191  continue;
192  }
193 
194  // Get device product name and try to match against "xum1541".
195  // If no match, it could be an xum1541 so don't report an error.
196  len = usbGetStringAscii(*HandleXum1541, dev->descriptor.iProduct,
197  0x0409, string, sizeof(string) - 1);
198  if (len < 0) {
199  xum1541_cleanup(HandleXum1541,
200  "error: cannot query product name: %s\n", usb.strerror());
201  continue;
202  }
203  string[len] = '\0';
204  if (len < prodLen || strstr(string, xumProduct) == NULL) {
205  xum1541_cleanup(HandleXum1541, NULL);
206  continue;
207  }
208  xum1541_dbg(0, "xum1541 name: %s", string);
209 
210  len = usbGetStringAscii(*HandleXum1541,
211  dev->descriptor.iSerialNumber, 0x0409,
212  string, sizeof(string) - 1);
213  if (len < 0 && PortNumber != 0){
214  // we need the serial number, when PortNumber is not 0
215  xum1541_cleanup(HandleXum1541,
216  "error: cannot query serial number: %s\n",
217  usb.strerror());
218  continue;
219  }
220  serialnum = 0;
221  if (len > 0 && len <=3 ) {
222  string[len] = '\0';
223  serialnum = atoi(string);
224  }
225  if (PortNumber != serialnum) {
226  // keep in mind the handle, if the device's
227  // serial number is less than previous ones
228  if(serialnum < leastserial) {
229  leastserial = serialnum;
230  preferredDefaultHandle = dev;
231  }
232  xum1541_cleanup(HandleXum1541, NULL);
233  continue;
234  }
235 
236  xum1541_dbg(0, "xum1541 serial number: %3u", serialnum);
237  return;
238  }
239  }
240  // if no default device was found because only specific devices were present,
241  // determine the default device from the specific ones and open it
242  if(preferredDefaultHandle != NULL) {
243  if ((*HandleXum1541 = usb.open(preferredDefaultHandle)) == NULL) {
244  fprintf(stderr, "error: Cannot reopen USB device: %s\n",
245  usb.strerror());
246  }
247  }
248 }
249 
250 // Check for a firmware version compatible with this plugin
251 static int
252 xum1541_check_version(int version)
253 {
254  xum1541_dbg(0, "firmware version %d, library version %d", version,
255  XUM1541_VERSION);
256  if (version < XUM1541_VERSION) {
257  fprintf(stderr, "xum1541 firmware version too low (%d < %d)\n",
258  version, XUM1541_VERSION);
259  fprintf(stderr, "please update your xum1541 firmware\n");
260  return -1;
261  } else if (version > XUM1541_VERSION) {
262  fprintf(stderr, "xum1541 firmware version too high (%d > %d)\n",
263  version, XUM1541_VERSION);
264  fprintf(stderr, "please update your OpenCBM plugin\n");
265  return -1;
266  }
267  return 0;
268 }
269 
286 const char *
287 xum1541_device_path(int PortNumber)
288 {
289 #define PREFIX_OFFSET (sizeof("libusb/xum1541:") - 1)
290  usb_dev_handle *HandleXum1541;
291  static char dev_path[PREFIX_OFFSET + LIBUSB_PATH_MAX] = "libusb/xum1541:";
292 
293  dev_path[PREFIX_OFFSET + 1] = '\0';
294  xum1541_enumerate(&HandleXum1541, PortNumber);
295 
296  if (HandleXum1541 != NULL) {
297  strcpy(dev_path, (usb.device(HandleXum1541))->filename);
298  xum1541_close(HandleXum1541);
299  } else {
300  fprintf(stderr, "error: no xum1541 device found\n");
301  }
302 
303  return dev_path;
304 }
305 #undef PREFIX_OFFSET
306 
307 static int
308 xum1541_clear_halt(usb_dev_handle *handle)
309 {
310  int ret;
311 
312  ret = usb.clear_halt(handle, XUM_BULK_IN_ENDPOINT | USB_ENDPOINT_IN);
313  if (ret != 0) {
314  fprintf(stderr, "USB clear halt request failed for in ep: %s\n",
315  usb.strerror());
316  return -1;
317  }
318  ret = usb.clear_halt(handle, XUM_BULK_OUT_ENDPOINT);
319  if (ret != 0) {
320  fprintf(stderr, "USB clear halt request failed for out ep: %s\n",
321  usb.strerror());
322  return -1;
323  }
324 
325 #ifdef __APPLE__
326  /*
327  * The Darwin libusb implementation calls ClearPipeStall() in
328  * usb_clear_halt(). While that clears the host data toggle and resets
329  * its endpoint, it does not send the CLEAR_FEATURE(halt) control
330  * request to the device. The ClearPipeStallBothEnds() function does
331  * do this.
332  *
333  * We manually send this control request here on Mac systems.
334  */
335  ret = usb.control_msg(handle, USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE,
336  0, XUM_BULK_IN_ENDPOINT | USB_ENDPOINT_IN, NULL, 0, USB_TIMEOUT);
337  if (ret != 0) {
338  fprintf(stderr, "USB clear control req failed for in ep: %s\n",
339  usb.strerror());
340  return -1;
341  }
342  ret = usb.control_msg(handle, USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE,
343  0, XUM_BULK_OUT_ENDPOINT, NULL, 0, USB_TIMEOUT);
344  if (ret != 0) {
345  fprintf(stderr, "USB clear control req failed for out ep: %s\n",
346  usb.strerror());
347  return -1;
348  }
349 #endif // __APPLE__
350 
351  return 0;
352 }
353 
373 int
374 xum1541_init(usb_dev_handle **HandleXum1541, int PortNumber)
375 {
376  unsigned char devInfo[XUM_DEVINFO_SIZE], devStatus;
377  int len;
378 
379  // Place after "xum1541_usb_handle" allocation:
380  /*uh->*/DeviceDriveMode = DeviceDriveMode_Uninit;
381 
382  xum1541_enumerate(HandleXum1541, PortNumber);
383 
384  if (*HandleXum1541 == NULL) {
385  fprintf(stderr, "error: no xum1541 device found\n");
386  return -1;
387  }
388 
389  // Select first and only device configuration.
390  if (usb.set_configuration(*HandleXum1541, 1) != 0) {
391  xum1541_cleanup(HandleXum1541, "USB error: %s\n", usb.strerror());
392  return -1;
393  }
394 
395  /*
396  * Get exclusive access to interface 0.
397  * After this point, do cleanup using xum1541_close() instead of
398  * xum1541_cleanup().
399  */
400  if (usb.claim_interface(*HandleXum1541, 0) != 0) {
401  xum1541_cleanup(HandleXum1541, "USB error: %s\n", usb.strerror());
402  return -1;
403  }
404 
405  // Check the basic device info message for firmware version
406  memset(devInfo, 0, sizeof(devInfo));
407  len = usb.control_msg(*HandleXum1541, USB_TYPE_CLASS | USB_ENDPOINT_IN,
408  XUM1541_INIT, 0, 0, (char*)devInfo, sizeof(devInfo), USB_TIMEOUT);
409  if (len < 2) {
410  fprintf(stderr, "USB request for XUM1541 info failed: %s\n",
411  usb.strerror());
412  xum1541_close(*HandleXum1541);
413  return -1;
414  }
415  if (xum1541_check_version(devInfo[0]) != 0) {
416  xum1541_close(*HandleXum1541);
417  return -1;
418  }
419  if (len >= 4) {
420  xum1541_dbg(0, "device capabilities %02x status %02x",
421  devInfo[1], devInfo[2]);
422  }
423 
424  // Check for the xum1541's current status. (Not the drive.)
425  devStatus = devInfo[2];
426  if ((devStatus & XUM1541_DOING_RESET) != 0) {
427  fprintf(stderr, "previous command was interrupted, resetting\n");
428  // Clear the stalls on both endpoints
429  if (xum1541_clear_halt(*HandleXum1541) < 0) {
430  xum1541_close(*HandleXum1541);
431  return -1;
432  }
433  }
434 
435  // Enable disk or tape mode.
436  if (devInfo[1] & XUM1541_CAP_TAP)
437  {
438  if (devInfo[2] & XUM1541_TAPE_PRESENT)
439  {
440  /*uh->*/DeviceDriveMode = DeviceDriveMode_Tape;
441  xum1541_dbg(1, "[xum1541_init] Tape supported, tape mode entered.");
442  }
443  else
444  {
445  /*uh->*/DeviceDriveMode = DeviceDriveMode_Disk;
446  xum1541_dbg(1, "[xum1541_init] Tape supported, disk mode entered.");
447  }
448  }
449  else
450  {
451  DeviceDriveMode = (unsigned char) DeviceDriveMode_NoTapeSupport;
452  xum1541_dbg(1, "[xum1541_init] No tape support.");
453  }
454 
455  return 0;
456 }
465 void
466 xum1541_close(usb_dev_handle *HandleXum1541)
467 {
468  int ret;
469 
470  xum1541_dbg(0, "Closing USB link");
471 
472  ret = usb.control_msg(HandleXum1541, USB_TYPE_CLASS | USB_ENDPOINT_OUT,
473  XUM1541_SHUTDOWN, 0, 0, NULL, 0, 1000);
474  if (ret < 0) {
475  fprintf(stderr,
476  "USB request for XUM1541 close failed, continuing: %s\n",
477  usb.strerror());
478  }
479  if (usb.release_interface(HandleXum1541, 0) != 0)
480  fprintf(stderr, "USB release intf error: %s\n", usb.strerror());
481 
482  if (usb.close(HandleXum1541) != 0)
483  fprintf(stderr, "USB close error: %s\n", usb.strerror());
484 }
485 
498 int
499 xum1541_control_msg(usb_dev_handle *HandleXum1541, unsigned int cmd)
500 {
501  int nBytes;
502 
503  xum1541_dbg(1, "control msg %d", cmd);
504 
505  nBytes = usb.control_msg(HandleXum1541, USB_TYPE_CLASS | USB_ENDPOINT_OUT,
506  cmd, 0, 0, NULL, 0, USB_TIMEOUT);
507  if (nBytes < 0) {
508  fprintf(stderr, "USB error in xum1541_control_msg: %s\n",
509  usb.strerror());
510  exit(-1);
511  }
512 
513  return nBytes;
514 }
515 
516 static int
517 xum1541_wait_status(usb_dev_handle *HandleXum1541)
518 {
519  int nBytes, deviceBusy, ret;
520  unsigned char statusBuf[XUM_STATUSBUF_SIZE];
521 
522  xum1541_dbg(2, "xum1541_wait_status checking for status");
523  deviceBusy = 1;
524  while (deviceBusy) {
525  nBytes = usb.bulk_read(HandleXum1541,
526  XUM_BULK_IN_ENDPOINT | USB_ENDPOINT_IN,
527  (char*)statusBuf, XUM_STATUSBUF_SIZE, LIBUSB_NO_TIMEOUT);
528  if (nBytes == XUM_STATUSBUF_SIZE) {
529  switch (XUM_GET_STATUS(statusBuf)) {
530  case XUM1541_IO_BUSY:
531  xum1541_dbg(2, "device busy, waiting");
532  break;
533  case XUM1541_IO_ERROR:
534  fprintf(stderr, "device reports error\n");
535  /* FALLTHROUGH */
536  case XUM1541_IO_READY:
537  deviceBusy = 0;
538  break;
539  default:
540  fprintf(stderr, "unknown status value: %d\n",
541  XUM_GET_STATUS(statusBuf));
542  exit(-1);
543  }
544  } else {
545  fprintf(stderr, "USB error in xum1541_wait_status: %s\n",
546  usb.strerror());
547  exit(-1);
548  }
549  }
550 
551  // Once we have a valid response (done ok), get extended status
552  if (XUM_GET_STATUS(statusBuf) == XUM1541_IO_READY)
553  ret = XUM_GET_STATUS_VAL(statusBuf);
554  else
555  ret = -1;
556 
557  xum1541_dbg(2, "return val = %x", ret);
558  return ret;
559 }
560 
561 // Macro to enforce disk/tape mode.
562 // Checks if xum1541_ioctl/xum1541_read/xum1541_write command is allowed in currently set disk/tape mode.
563 #define RefuseToWorkInWrongMode \
564  { \
565  if (/*uh->*/DeviceDriveMode == DeviceDriveMode_Uninit) \
566  { \
567  xum1541_dbg(1, "[RefuseToWorkInWrongMode] cmd blocked - No disk or tape mode set."); \
568  return XUM1541_Error_NoDiskTapeMode; \
569  } \
570  \
571  if (isTapeCmd) \
572  { \
573  if (/*uh->*/DeviceDriveMode == DeviceDriveMode_NoTapeSupport) \
574  { \
575  xum1541_dbg(1, "[RefuseToWorkInWrongMode] cmd blocked - Firmware has no tape support."); \
576  return XUM1541_Error_NoTapeSupport; \
577  } \
578  \
579  if (/*uh->*/DeviceDriveMode == DeviceDriveMode_Disk) \
580  { \
581  xum1541_dbg(1, "[RefuseToWorkInWrongMode] cmd blocked - Tape cmd in disk mode."); \
582  return XUM1541_Error_TapeCmdInDiskMode; \
583  } \
584  } \
585  else /*isDiskCmd*/ \
586  { \
587  if (/*uh->*/DeviceDriveMode == DeviceDriveMode_Tape) \
588  { \
589  xum1541_dbg(1, "[RefuseToWorkInWrongMode] cmd blocked - Disk cmd in tape mode."); \
590  return XUM1541_Error_DiskCmdInTapeMode; \
591  } \
592  } \
593  }
594 
615 int
616 xum1541_ioctl(usb_dev_handle *HandleXum1541, unsigned int cmd, unsigned int addr, unsigned int secaddr)
617 {
618  int nBytes, ret;
619  unsigned char cmdBuf[XUM_CMDBUF_SIZE];
620  BOOL isTapeCmd = ((XUM1541_TAP_MOTOR_ON <= cmd) && (cmd <= XUM1541_TAP_MOTOR_OFF));
621 
622  xum1541_dbg(1, "ioctl %d for device %d, sub %d", cmd, addr, secaddr);
623 
624  RefuseToWorkInWrongMode; // Check if command allowed in current disk/tape mode.
625 
626  cmdBuf[0] = (unsigned char)cmd;
627  cmdBuf[1] = (unsigned char)addr;
628  cmdBuf[2] = (unsigned char)secaddr;
629  cmdBuf[3] = 0;
630 
631  // Send the 4-byte command block
632  nBytes = usb.bulk_write(HandleXum1541,
633  XUM_BULK_OUT_ENDPOINT | USB_ENDPOINT_OUT,
634  (char *)cmdBuf, sizeof(cmdBuf), LIBUSB_NO_TIMEOUT);
635  if (nBytes < 0) {
636  fprintf(stderr, "USB error in xum1541_ioctl cmd: %s\n",
637  usb.strerror());
638  exit(-1);
639  }
640 
641  // If we have a valid response, return extended status
642  ret = xum1541_wait_status(HandleXum1541);
643  xum1541_dbg(2, "return val = %x", ret);
644  return ret;
645 }
646 
655 int
656 xum1541_tap_break(usb_dev_handle *HandleXum1541)
657 {
658  BOOL isTapeCmd = TRUE;
659  RefuseToWorkInWrongMode; // Check if command allowed in current disk/tape mode.
660 
661  xum1541_dbg(1, "[xum1541_tap_break] Sending tape break command.");
662 
663  return xum1541_control_msg(HandleXum1541, XUM1541_TAP_BREAK);
664 }
665 
685 int
686 xum1541_write(usb_dev_handle *HandleXum1541, unsigned char modeFlags, const unsigned char *data, size_t size)
687 {
688  int wr, mode, ret;
689  size_t bytesWritten, bytes2write;
690  unsigned char cmdBuf[XUM_CMDBUF_SIZE];
691  BOOL isTapeCmd = ((modeFlags == XUM1541_TAP) || (modeFlags == XUM1541_TAP_CONFIG));
692 
693  mode = modeFlags & 0xf0;
694  xum1541_dbg(1, "write %d %d bytes from address %p flags %x",
695  mode, size, data, modeFlags & 0x0f);
696 
697  RefuseToWorkInWrongMode; // Check if command allowed in current disk/tape mode.
698 
699  // Send the write command
700  cmdBuf[0] = XUM1541_WRITE;
701  cmdBuf[1] = modeFlags;
702  cmdBuf[2] = size & 0xff;
703  cmdBuf[3] = (size >> 8) & 0xff;
704  wr = usb.bulk_write(HandleXum1541,
705  XUM_BULK_OUT_ENDPOINT | USB_ENDPOINT_OUT,
706  (char *)cmdBuf, sizeof(cmdBuf), LIBUSB_NO_TIMEOUT);
707  if (wr < 0) {
708  fprintf(stderr, "USB error in write cmd: %s\n",
709  usb.strerror());
710  return -1;
711  }
712 
713  bytesWritten = 0;
714  while (bytesWritten < size) {
715  bytes2write = size - bytesWritten;
716  if (bytes2write > XUM_MAX_XFER_SIZE)
717  bytes2write = XUM_MAX_XFER_SIZE;
718  wr = usb.bulk_write(HandleXum1541,
719  XUM_BULK_OUT_ENDPOINT | USB_ENDPOINT_OUT,
720  (char *)data, bytes2write, LIBUSB_NO_TIMEOUT);
721  if (wr < 0) {
722  if (isTapeCmd)
723  {
724  if (usb.resetep(HandleXum1541, XUM_BULK_OUT_ENDPOINT | USB_ENDPOINT_OUT) < 0)
725  fprintf(stderr, "USB reset ep request failed for out ep (tape stall): %s\n", usb.strerror());
726  if (usb.control_msg(HandleXum1541, USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE, 0, XUM_BULK_OUT_ENDPOINT, NULL, 0, USB_TIMEOUT) < 0)
727  fprintf(stderr, "USB error in xum1541_control_msg (tape stall): %s\n", usb.strerror());
728  return bytesWritten;
729  }
730  fprintf(stderr, "USB error in write data: %s\n",
731  usb.strerror());
732  return -1;
733  } else if (wr > 0)
734  xum1541_dbg(2, "wrote %d bytes", wr);
735 
736  data += wr;
737  bytesWritten += wr;
738 
739  /*
740  * If we wrote less than we requested (or 0), the transfer is done
741  * even if we had more data to write still.
742  */
743  if (wr < (int)bytes2write)
744  break;
745  }
746 
747  // If this is the CBM protocol, wait for the status message.
748  if (mode == XUM1541_CBM) {
749  ret = xum1541_wait_status(HandleXum1541);
750  if (ret >= 0)
751  xum1541_dbg(2, "wait done, extended status %d", ret);
752  else
753  xum1541_dbg(2, "wait done with error");
754  bytesWritten = ret;
755  }
756 
757  xum1541_dbg(2, "write done, got %d bytes", bytesWritten);
758  return bytesWritten;
759 }
760 
774 int
775 xum1541_write_ext(usb_dev_handle *HandleXum1541, unsigned char modeFlags, const unsigned char *data, size_t size, int *Status, int *BytesWritten)
776 {
777  xum1541_dbg(1, "[xum1541_write_ext]");
778  *BytesWritten = xum1541_write(HandleXum1541, modeFlags, data, size);
779  if (*BytesWritten < 0)
780  return *BytesWritten;
781  xum1541_dbg(2, "[xum1541_write_ext] BytesWritten = %d", *BytesWritten);
782  *Status = xum1541_wait_status(HandleXum1541);
783  xum1541_dbg(2, "[xum1541_write_ext] Status = %d", *Status);
784  return 1;
785 }
786 
800 int
801 xum1541_read_ext(usb_dev_handle *HandleXum1541, unsigned char mode, unsigned char *data, size_t size, int *Status, int *BytesRead)
802 {
803  xum1541_dbg(1, "[xum1541_read_ext]");
804  *BytesRead = xum1541_read(HandleXum1541, mode, data, size);
805  if (*BytesRead < 0)
806  return *BytesRead;
807  xum1541_dbg(2, "[xum1541_read_ext] BytesRead = %d", *BytesRead);
808  *Status = xum1541_wait_status(HandleXum1541);
809  xum1541_dbg(2, "[xum1541_read_ext] Status = %d", *Status);
810  return 1;
811 }
812 
832 int
833 xum1541_read(usb_dev_handle *HandleXum1541, unsigned char mode, unsigned char *data, size_t size)
834 {
835  int rd;
836  size_t bytesRead, bytes2read;
837  unsigned char cmdBuf[XUM_CMDBUF_SIZE];
838  BOOL isTapeCmd = ((mode == XUM1541_TAP) || (mode == XUM1541_TAP_CONFIG));
839 
840  xum1541_dbg(1, "read %d %d bytes to address %p",
841  mode, size, data);
842 
843  RefuseToWorkInWrongMode; // Check if command allowed in current disk/tape mode.
844 
845  // Send the read command
846  cmdBuf[0] = XUM1541_READ;
847  cmdBuf[1] = mode;
848  cmdBuf[2] = size & 0xff;
849  cmdBuf[3] = (size >> 8) & 0xff;
850  rd = usb.bulk_write(HandleXum1541,
851  XUM_BULK_OUT_ENDPOINT | USB_ENDPOINT_OUT,
852  (char *)cmdBuf, sizeof(cmdBuf), LIBUSB_NO_TIMEOUT);
853  if (rd < 0) {
854  fprintf(stderr, "USB error in read cmd: %s\n",
855  usb.strerror());
856  return -1;
857  }
858 
859  // Read the actual data now that it's ready.
860  bytesRead = 0;
861  while (bytesRead < size) {
862  bytes2read = size - bytesRead;
863  if (bytes2read > XUM_MAX_XFER_SIZE)
864  bytes2read = XUM_MAX_XFER_SIZE;
865  rd = usb.bulk_read(HandleXum1541,
866  XUM_BULK_IN_ENDPOINT | USB_ENDPOINT_IN,
867  (char *)data, bytes2read, LIBUSB_NO_TIMEOUT);
868  if (rd < 0) {
869  fprintf(stderr, "USB error in read data(%p, %d): %s\n",
870  data, (int)size, usb.strerror());
871  return -1;
872  } else if (rd > 0)
873  xum1541_dbg(2, "read %d bytes", rd);
874 
875  data += rd;
876  bytesRead += rd;
877 
878  /*
879  * If we read less than we requested (or 0), the transfer is done
880  * even if we had more data to read still.
881  */
882  if (rd < (int)bytes2read)
883  break;
884  }
885 
886  xum1541_dbg(2, "read done, got %d bytes", bytesRead);
887  return bytesRead;
888 }
const char * xum1541_device_path(int PortNumber)
Query unique identifier for the xum1541 device This function tries to find an unique identifier for t...
Definition: xum1541.c:287
void xum1541_close(usb_dev_handle *HandleXum1541)
close the xum1541 device
Definition: xum1541.c:466
int xum1541_tap_break(usb_dev_handle *HandleXum1541)
Send tape operations abort command to the xum1541 device.
Definition: xum1541.c:656
Allow for libusb (0.1) to be loaded dynamically (Currently, this is used on Windows only) ...
Shared library / DLL for accessing the driver Functions for obtaining the addresses of plugin functio...
int xum1541_write(usb_dev_handle *HandleXum1541, unsigned char modeFlags, const unsigned char *data, size_t size)
Write data to the xum1541 device.
Definition: xum1541.c:686
int xum1541_read_ext(usb_dev_handle *HandleXum1541, unsigned char mode, unsigned char *data, size_t size, int *Status, int *BytesRead)
Wrapper for xum1541_read() forcing xum1541_wait_status(), with additional parameters: ...
Definition: xum1541.c:801
DLL interface for accessing the driver.
int xum1541_init(usb_dev_handle **HandleXum1541, int PortNumber)
Initialize the xum1541 device This function tries to find and identify the xum1541 device...
Definition: xum1541.c:374
Define makros and functions which account for differences between the different architectures.
int xum1541_write_ext(usb_dev_handle *HandleXum1541, unsigned char modeFlags, const unsigned char *data, size_t size, int *Status, int *BytesWritten)
Wrapper for xum1541_write() forcing xum1541_wait_status(), with additional parameters: ...
Definition: xum1541.c:775
int xum1541_ioctl(usb_dev_handle *HandleXum1541, unsigned int cmd, unsigned int addr, unsigned int secaddr)
Perform an ioctl on the xum1541, which is any command other than read/write or special device managem...
Definition: xum1541.c:616
int xum1541_control_msg(usb_dev_handle *HandleXum1541, unsigned int cmd)
Handle synchronous USB control messages, e.g. for RESET. xum1541_ioctl() is used for bulk messages...
Definition: xum1541.c:499
Definition: usb.h:260
int xum1541_read(usb_dev_handle *HandleXum1541, unsigned char mode, unsigned char *data, size_t size)
Read data from the xum1541 device.
Definition: xum1541.c:833