/********************************************************************\

  Name:         musbstd.c
  Created by:   Konstantin Olchanski, Stefan Ritt

  Contents:     Midas USB access

  $Id$

\********************************************************************/

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <musbstd.h>

#ifdef _MSC_VER                 // Windows includes

#include <windows.h>
#include <conio.h>
#include <winioctl.h>

#include <setupapi.h>
#include <initguid.h>           /* Required for GUID definition */

// link with SetupAPI.Lib.
#pragma comment (lib, "setupapi.lib")

// disable "deprecated" warning
#pragma warning( disable: 4996)

// {CBEB3FB1-AE9F-471c-9016-9B6AC6DCD323}
DEFINE_GUID(GUID_CLASS_MSCB_BULK, 0xcbeb3fb1, 0xae9f, 0x471c, 0x90, 0x16, 0x9b, 0x6a, 0xc6, 0xdc, 0xd3, 0x23);

#elif defined(OS_DARWIN)

#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <fcntl.h>

#include <assert.h>
#include <mach/mach.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/usb/IOUSBLib.h>

#elif defined(OS_LINUX)         // Linux includes

#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#endif

#ifdef HAVE_LIBUSB
#include <errno.h>
#include <usb.h>
#endif

#ifdef HAVE_LIBUSB10
#include <errno.h>
#include <libusb.h>
#endif

#if !defined(HAVE_LIBUSB) && !defined(HAVE_LIBUSB10)
#ifdef OS_DARWIN

IOReturn darwin_configure_device(MUSB_INTERFACE* musb)
{
   IOReturn status;
   io_iterator_t iter;
   io_service_t service;
   IOCFPlugInInterface **plugin;
   SInt32 score;
   IOUSBInterfaceInterface **uinterface;
   UInt8 numend;

   IOUSBDeviceInterface **device = (IOUSBDeviceInterface **)musb->device;

   status = (*device)->SetConfiguration(device, musb->usb_configuration);
   assert(status == kIOReturnSuccess);

   IOUSBFindInterfaceRequest request;

   request.bInterfaceClass = kIOUSBFindInterfaceDontCare;
   request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare;
   request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare;
   request.bAlternateSetting = kIOUSBFindInterfaceDontCare;
   
   status = (*device)->CreateInterfaceIterator(device, &request, &iter);
   assert(status == kIOReturnSuccess);
  
   while ((service = IOIteratorNext(iter))) {
      int i;
      status =
        IOCreatePlugInInterfaceForService(service, kIOUSBInterfaceUserClientTypeID,
                                          kIOCFPlugInInterfaceID, &plugin, &score);
      assert(status == kIOReturnSuccess);
      
      status =
        (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
                                  (void *) &uinterface);
      assert(status == kIOReturnSuccess);
      
      
      status = (*uinterface)->USBInterfaceOpen(uinterface);
      fprintf(stderr, "musb_open: USBInterfaceOpen status 0x%x\n", status);
      assert(status == kIOReturnSuccess);
      
      status = (*uinterface)->GetNumEndpoints(uinterface, &numend);
      assert(status == kIOReturnSuccess);
      
      fprintf(stderr, "musb_open: endpoints: %d\n", numend);
      
      for (i=1; i<=numend; i++) {
         status = (*uinterface)->GetPipeStatus(uinterface, i);
         fprintf(stderr, "musb_open: pipe %d status: 0x%x\n", i, status);
      
#if 0
         status = (*uinterface)->ClearPipeStall(uinterface, i);
         fprintf(stderr, "musb_open: pipe %d ClearPipeStall() status: 0x%x\n", i, status);
         status = (*uinterface)->ResetPipe(uinterface, i);
         fprintf(stderr, "musb_open: pipe %d ResetPipe() status: 0x%x\n", i, status);
         status = (*uinterface)->AbortPipe(uinterface, i);
         fprintf(stderr, "musb_open: pipe %d AbortPipe() status: 0x%x\n", i, status);
#endif
      }

      musb->interface = uinterface;
      return kIOReturnSuccess;
   }

   assert(!"Should never be reached!");
   return -1;
}
    
#endif

#endif

int musb_open(MUSB_INTERFACE **musb_interface, int vendor, int product, int instance, int configuration, int usbinterface, int debug)
{
#if defined(HAVE_LIBUSB)
   
   struct usb_bus *bus;
   struct usb_device *dev;
   int count = 0;
   
   usb_init();
   usb_find_busses();
   usb_find_devices();
   usb_set_debug(3);
   
   for (bus = usb_get_busses(); bus; bus = bus->next)
      for (dev = bus->devices; dev; dev = dev->next)
         if (dev->descriptor.idVendor == vendor && dev->descriptor.idProduct == product) {
            if (count == instance) {
               int status;
               usb_dev_handle *udev;

               udev = usb_open(dev);
               if (!udev) {
                  fprintf(stderr, "musb_open: usb_open() error\n");
                  return MUSB_ACCESS_ERROR;
               }

               status = usb_set_configuration(udev, configuration);
               if (status != 0) {
                  fprintf(stderr, "musb_open: usb_set_configuration() error %d (%s)\n", status,
                     strerror(-status));
                  fprintf(stderr,
                     "musb_open: Found USB device 0x%04x:0x%04x instance %d, but cannot initialize it: please check permissions on \"/proc/bus/usb/%s/%s\" and \"/dev/bus/usb/%s/%s\"\n",
                     vendor, product, instance, bus->dirname, dev->filename, bus->dirname, dev->filename);
                  return MUSB_ACCESS_ERROR;
               }

               /* see if we have write access */
               status = usb_claim_interface(udev, usbinterface);
               if (status != 0) {
                  fprintf(stderr, "musb_open: usb_claim_interface() error %d (%s)\n", status,
                     strerror(-status));

#ifdef _MSC_VER
                  fprintf(stderr,
                     "musb_open: Found USB device 0x%04x:0x%04x instance %d, but cannot initialize it:\nDevice is probably used by another program\n",
                     vendor, product, instance);
#else
                  fprintf(stderr,
                     "musb_open: Found USB device 0x%04x:0x%04x instance %d, but cannot initialize it: please check permissions on \"/proc/bus/usb/%s/%s\"\n",
                     vendor, product, instance, bus->dirname, dev->filename);
#endif

                  return MUSB_ACCESS_ERROR;
               }

               *musb_interface = (MUSB_INTERFACE*)calloc(1, sizeof(MUSB_INTERFACE));
               (*musb_interface)->dev = udev;
               (*musb_interface)->usb_configuration = configuration;
               (*musb_interface)->usb_interface     = usbinterface;
               return MUSB_SUCCESS;
            }

            count++;
         }
   
   return MUSB_NOT_FOUND;
   
#elif defined(HAVE_LIBUSB10)
   
   static int first_call = 1;

   libusb_device **dev_list;
   libusb_device_handle *dev;
   struct libusb_device_descriptor desc;
   
   int status, i, n;
   int count = 0;
   
   if (first_call) {
      first_call = 0;
      status = libusb_init(NULL);
      if (status != 0)
         printf("libusb_init returns error code %d\n", status);
   }
      
   n = libusb_get_device_list(NULL, &dev_list);
   if (debug)
      printf("Found %d USB devices\n", n);
   
   for (i=0 ; i<n ; i++) {
      status = libusb_get_device_descriptor(dev_list[i], &desc);
      if (debug)
         printf("Found device VID=%04X PID=%04X\n", desc.idVendor, desc.idProduct);
      if (desc.idVendor == vendor && desc.idProduct == product) {
         if (count == instance || debug) {
            status = libusb_open(dev_list[i], &dev);
            if (status != 0) {
               fprintf(stderr, "musb_open: libusb_open() error %d\n", status);
               return MUSB_ACCESS_ERROR;
            }

            status = libusb_set_configuration(dev, configuration);
            if (status < 0) {
               fprintf(stderr, "musb_open: usb_set_configuration() error %d\n", status);
               fprintf(stderr,
                       "musb_open: Found USB device 0x%04x:0x%04x instance %d, but cannot initialize it: please check permissions on \"/proc/bus/usb/%d/%d\" and \"/dev/bus/usb/%d/%d\"\n",
                       vendor, product, instance, libusb_get_bus_number(dev_list[i]), libusb_get_device_address(dev_list[i]), libusb_get_bus_number(dev_list[i]), libusb_get_device_address(dev_list[i]));
               return MUSB_ACCESS_ERROR;
            }
            
            /* see if we have write access */
            status = libusb_claim_interface(dev, usbinterface);
            if (status != 0) {
               fprintf(stderr, "musb_open: libusb_claim_interface() error %d\n", status);
               
#ifdef _MSC_VER
               fprintf(stderr,
                       "musb_open: Found USB device 0x%04x:0x%04x instance %d, but cannot initialize it:\nDevice is probably used by another program\n",
                       vendor, product, instance);
#else
               fprintf(stderr,
                       "musb_open: Found USB device 0x%04x:0x%04x instance %d, but cannot initialize it: please check permissions on \"/proc/bus/usb/%d/%d\"\n",
                       vendor, product, instance, libusb_get_bus_number(dev_list[i]), libusb_get_device_address(dev_list[i]));
#endif
               
               return MUSB_ACCESS_ERROR;
            }

            *musb_interface = (MUSB_INTERFACE*)calloc(1, sizeof(MUSB_INTERFACE));
            (*musb_interface)->dev = dev;
            (*musb_interface)->usb_configuration = configuration;
            (*musb_interface)->usb_interface     = usbinterface;
            
            if (debug)
               printf("Found DRS4 evaluation board and successfully claimed interface\n");
            else
               return MUSB_SUCCESS;
         }
         count++;
      }
   }
   
   libusb_free_device_list(dev_list, 1);
   
   return MUSB_NOT_FOUND;
     
#elif defined(OS_DARWIN)
   
   kern_return_t status;
   io_iterator_t iter;
   io_service_t service;
   IOCFPlugInInterface **plugin;
   SInt32 score;
   IOUSBDeviceInterface **device;
   UInt16 xvendor, xproduct;
   int count = 0;

   *musb_interface = calloc(1, sizeof(MUSB_INTERFACE));
   
   status = IORegistryCreateIterator(kIOMasterPortDefault, kIOUSBPlane, kIORegistryIterateRecursively, &iter);
   assert(status == kIOReturnSuccess);

   while ((service = IOIteratorNext(iter))) {
      status =
          IOCreatePlugInInterfaceForService(service, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID,
                                            &plugin, &score);
      assert(status == kIOReturnSuccess);

      status = IOObjectRelease(service);
      assert(status == kIOReturnSuccess);

      status =
          (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (void *) &device);
      assert(status == kIOReturnSuccess);

      status = (*plugin)->Release(plugin);

      status = (*device)->GetDeviceVendor(device, &xvendor);
      assert(status == kIOReturnSuccess);
      status = (*device)->GetDeviceProduct(device, &xproduct);
      assert(status == kIOReturnSuccess);

      //fprintf(stderr, "musb_open: Found USB device: vendor 0x%04x, product 0x%04x\n", xvendor, xproduct);

      if (xvendor == vendor && xproduct == product) {
         if (count == instance) {

            fprintf(stderr, "musb_open: Found USB device: vendor 0x%04x, product 0x%04x, instance %d\n", xvendor, xproduct, instance);

            status = (*device)->USBDeviceOpen(device);
            fprintf(stderr, "musb_open: USBDeviceOpen status 0x%x\n", status);

            assert(status == kIOReturnSuccess);

            (*musb_interface)->usb_configuration = configuration;
            (*musb_interface)->usb_interface     = usbinterface;
            (*musb_interface)->device = (void*)device;
            (*musb_interface)->interface = NULL;

            status = darwin_configure_device(*musb_interface);

            if (status == kIOReturnSuccess)
               return MUSB_SUCCESS;

            fprintf(stderr, "musb_open: USB device exists, but configuration fails!");
            return MUSB_NOT_FOUND;
         }

         count++;
      }

      (*device)->Release(device);
   }

   return MUSB_NOT_FOUND;
#elif defined(_MSC_VER)
   GUID guid;
   HDEVINFO hDevInfoList;
   SP_DEVICE_INTERFACE_DATA deviceInfoData;
   PSP_DEVICE_INTERFACE_DETAIL_DATA functionClassDeviceData;
   ULONG predictedLength, requiredLength;
   int status;
   char device_name[256], str[256];

   *musb_interface = (MUSB_INTERFACE *)calloc(1, sizeof(MUSB_INTERFACE));

   guid = GUID_CLASS_MSCB_BULK;

   // Retrieve device list for GUID that has been specified.
   hDevInfoList = SetupDiGetClassDevs(&guid, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));

   status = FALSE;
   if (hDevInfoList != NULL) {

      // Clear data structure
      memset(&deviceInfoData, 0, sizeof(deviceInfoData));
      deviceInfoData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

      // retrieves a context structure for a device interface of a device information set.
      if (SetupDiEnumDeviceInterfaces(hDevInfoList, 0, &guid, instance, &deviceInfoData)) {
         // Must get the detailed information in two steps
         // First get the length of the detailed information and allocate the buffer
         // retrieves detailed information about a specified device interface.
         functionClassDeviceData = NULL;

         predictedLength = requiredLength = 0;

         SetupDiGetDeviceInterfaceDetail(hDevInfoList, &deviceInfoData, NULL,   // Not yet allocated
                                         0,     // Set output buffer length to zero
                                         &requiredLength,       // Find out memory requirement
                                         NULL);

         predictedLength = requiredLength;
         functionClassDeviceData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(predictedLength);
         functionClassDeviceData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

         // Second, get the detailed information
         if (SetupDiGetDeviceInterfaceDetail(hDevInfoList,
                                             &deviceInfoData, functionClassDeviceData,
                                             predictedLength, &requiredLength, NULL)) {

            // Save the device name for subsequent pipe open calls
            strcpy(device_name, functionClassDeviceData->DevicePath);
            free(functionClassDeviceData);

            // Signal device found
            status = TRUE;
         } else
            free(functionClassDeviceData);
      }
   }
   // SetupDiDestroyDeviceInfoList() destroys a device information set
   // and frees all associated memory.
   SetupDiDestroyDeviceInfoList(hDevInfoList);

   if (status) {

      // Get the read handle
      sprintf(str, "%s\\PIPE00", device_name);
      (*musb_interface)->rhandle = CreateFile(str,
                                    GENERIC_WRITE | GENERIC_READ,
                                    FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
                                    OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);

      if ((*musb_interface)->rhandle == INVALID_HANDLE_VALUE)
         return MUSB_ACCESS_ERROR;

      // Get the write handle
      sprintf(str, "%s\\PIPE01", device_name);
      (*musb_interface)->whandle = CreateFile(str,
                                    GENERIC_WRITE | GENERIC_READ,
                                    FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);

      if ((*musb_interface)->whandle == INVALID_HANDLE_VALUE)
         return MUSB_ACCESS_ERROR;

      return MUSB_SUCCESS;
   } 
     
   return MUSB_NOT_FOUND;
#endif
}

int musb_set_altinterface(MUSB_INTERFACE *musb_interface, int index)
{
#if defined (HAVE_LIBUSB)
   int status;

   status = usb_set_altinterface(musb_interface->dev, index);
   if (status < 0)
      fprintf(stderr, "musb_set_altinterface: usb_set_altinterface() error %d\n", status);

   return status;
#else
   return -1;
#endif
}

int musb_close(MUSB_INTERFACE *musb_interface)
{
#if defined(HAVE_LIBUSB)

   int status;
   status = usb_release_interface(musb_interface->dev, musb_interface->usb_interface);
   if (status < 0)
      fprintf(stderr, "musb_close: usb_release_interface() error %d\n", status);
   
#ifdef OS_LINUX   // linux wants a reset, otherwise the device cannot be accessed next time
   musb_reset(musb_interface);
#endif

   status = usb_close(musb_interface->dev);
   if (status < 0)
      fprintf(stderr, "musb_close: usb_close() error %d\n", status);
   
#elif defined(HAVE_LIBUSB10)   

   int status;
   if (!musb_interface)
      return 0;
   
   status = libusb_release_interface(musb_interface->dev, musb_interface->usb_interface);

   if (status < 0)
      fprintf(stderr, "musb_close: libusb_release_interface() error %d\n", status);
   
#ifdef OS_LINUX   // linux wants a reset, otherwise the device cannot be accessed next time
   musb_reset(musb_interface);
#endif
   
   libusb_close(musb_interface->dev);

#elif defined(OS_DARWIN)

   IOReturn status;
   IOUSBInterfaceInterface **interface = (IOUSBInterfaceInterface **)musb_interface->interface;

   status = (*interface)->USBInterfaceClose(interface);
   if (status != kIOReturnSuccess)
      fprintf(stderr, "musb_close: USBInterfaceClose() status %d 0x%x\n", status, status);

   status = (*interface)->Release(interface);
   if (status != kIOReturnSuccess)
      fprintf(stderr, "musb_close: USB Interface Release() status %d 0x%x\n", status, status);

   IOUSBDeviceInterface **device = (IOUSBDeviceInterface**)musb_interface->device;
   status = (*device)->USBDeviceClose(device);
   if (status != kIOReturnSuccess)
      fprintf(stderr, "musb_close: USBDeviceClose() status %d 0x%x\n", status, status);

   status = (*device)->Release(device);
   if (status != kIOReturnSuccess)
      fprintf(stderr, "musb_close: USB Device Release() status %d 0x%x\n", status, status);

#elif defined(_MSC_VER)

   CloseHandle(musb_interface->rhandle);
   CloseHandle(musb_interface->whandle);

#else
   assert(!"musb_close() is not implemented");
#endif

   /* free memory allocated in musb_open() */
   free(musb_interface);
   return 0;
}

int musb_write(MUSB_INTERFACE *musb_interface, int endpoint, const void *buf, int count, int timeout)
{
   int n_written;

#if defined(HAVE_LIBUSB)
   n_written = usb_bulk_write(musb_interface->dev, endpoint, (char*)buf, count, timeout);
   if (n_written != count) {
      fprintf(stderr, "musb_write: requested %d, wrote %d, errno %d (%s)\n", count, n_written, errno, strerror(errno));
   }
#elif defined(HAVE_LIBUSB10)
   int status = libusb_bulk_transfer(musb_interface->dev, endpoint, (unsigned char*)buf, count, &n_written, timeout);
   if (n_written != count) {
      fprintf(stderr, "musb_write: requested %d, wrote %d, errno %d (%s)\n", count, n_written, status, strerror(status));
   }
#elif defined(OS_DARWIN)
   IOReturn status;
   IOUSBInterfaceInterface182 **interface = (IOUSBInterfaceInterface182 **)musb_interface->interface;
   status = (*interface)->WritePipeTO(interface, endpoint, buf, count, 0, timeout);
   if (status != 0) {
      fprintf(stderr, "musb_write: WritePipe() status %d 0x%x\n", status, status);
      return -1;
   }
   n_written = count;
#elif defined(_MSC_VER)
   WriteFile(musb_interface->whandle, buf, count, &n_written, NULL);
#endif

   //fprintf(stderr, "musb_write(ep %d, %d bytes) (%s) returns %d\n", endpoint, count, buf, n_written); 

   return n_written;
}

int musb_read(MUSB_INTERFACE *musb_interface, int endpoint, void *buf, int count, int timeout)
{
   int n_read = 0;

#if defined(HAVE_LIBUSB)

   n_read = usb_bulk_read(musb_interface->dev, endpoint | 0x80, (char*)buf, count, timeout);
   /* errors should be handled in upper layer ....
   if (n_read <= 0) {
      fprintf(stderr, "musb_read: requested %d, read %d, errno %d (%s)\n", count, n_read, errno, strerror(errno));
   }
   */

#elif defined(HAVE_LIBUSB10)
   
   libusb_bulk_transfer(musb_interface->dev, endpoint | 0x80, (unsigned char*)buf, count, &n_read, timeout);
   /* errors should be handled in upper layer ....
    if (n_read <= 0) {
    fprintf(stderr, "musb_read: requested %d, read %d, errno %d (%s)\n", count, n_read, status, libusb_strerror(status));
    }
    */
   
#elif defined(OS_DARWIN)

   UInt32 xcount = count;
   IOReturn status;
   IOUSBInterfaceInterface182 **interface = (IOUSBInterfaceInterface182 **)musb_interface->interface;

   status = (*interface)->ReadPipeTO(interface, endpoint, buf, &xcount, 0, timeout);
   if (status != kIOReturnSuccess) {
      fprintf(stderr, "musb_read: requested %d, read %d, ReadPipe() status %d 0x%x (%s)\n", count, n_read, status, status, strerror(status));
      return -1;
   }

   n_read = xcount;

#elif defined(_MSC_VER)

   OVERLAPPED overlapped;
   int status;

   memset(&overlapped, 0, sizeof(overlapped));
   overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
   n_read = 0;

   status = ReadFile(musb_interface->rhandle, buf, count, &n_read, &overlapped);
   
   if (!status) {

      status = GetLastError();
      if (status != ERROR_IO_PENDING)
         return 0;

      /* wait for completion with timeout */
      status = WaitForSingleObject(overlapped.hEvent, timeout);
      if (status == WAIT_TIMEOUT)
         CancelIo(musb_interface->rhandle);
      else
         GetOverlappedResult(musb_interface->rhandle, &overlapped, &n_read, FALSE);
   }

   CloseHandle(overlapped.hEvent);

#endif

   //fprintf(stderr, "musb_read(ep %d, %d bytes) returns %d (%s)\n", endpoint, count, n_read, buf); 

   return n_read;
}

int musb_reset(MUSB_INTERFACE *musb_interface)
{
#if defined(HAVE_LIBUSB)

   /* Causes re-enumeration: After calling usb_reset, the device will need 
      to re-enumerate and thusly, requires you to find the new device and 
      open a new handle. The handle used to call usb_reset will no longer work */

   int status;
   status = usb_reset(musb_interface->dev);
   if (status < 0)
      fprintf(stderr, "musb_reset: usb_reset() status %d\n", status);

#elif defined(HAVE_LIBUSB10)
   
   int status;
   status = libusb_reset_device(musb_interface->dev);
   if (status < 0)
      fprintf(stderr, "musb_reset: usb_reset() status %d\n", status);
   
#elif defined(OS_DARWIN)

   IOReturn status;
   IOUSBDeviceInterface **device = (IOUSBDeviceInterface**)musb_interface->device;

   status = (*device)->ResetDevice(device);
   fprintf(stderr, "musb_reset: ResetDevice() status 0x%x\n", status);

   status = darwin_configure_device(musb_interface);
   assert(status == kIOReturnSuccess);

#elif defined(_MSC_VER)

#define IOCTL_BULKUSB_RESET_DEVICE          CTL_CODE(FILE_DEVICE_UNKNOWN,     \
                                                     1,                       \
                                                     METHOD_BUFFERED,         \
                                                     FILE_ANY_ACCESS)
#define IOCTL_BULKUSB_RESET_PIPE            CTL_CODE(FILE_DEVICE_UNKNOWN,     \
                                                     2,                       \
                                                     METHOD_BUFFERED,         \
                                                     FILE_ANY_ACCESS)

   int status, n_bytes;

   status =  DeviceIoControl(musb_interface->rhandle,
                  IOCTL_BULKUSB_RESET_DEVICE,
                  NULL, 0, NULL, 0, &n_bytes, NULL);
   status =  DeviceIoControl(musb_interface->whandle,
                  IOCTL_BULKUSB_RESET_DEVICE,
                  NULL, 0, NULL, 0, &n_bytes, NULL);
   status =  DeviceIoControl(musb_interface->rhandle,
                  IOCTL_BULKUSB_RESET_PIPE,
                  NULL, 0, NULL, 0, &n_bytes, NULL);
   status =  DeviceIoControl(musb_interface->whandle,
                  IOCTL_BULKUSB_RESET_PIPE,
                  NULL, 0, NULL, 0, &n_bytes, NULL);
   return status;

#endif
   return 0;
}

int musb_get_device(MUSB_INTERFACE *usb_interface)
{
#ifdef HAVE_LIBUSB
   struct usb_device_descriptor d;
   usb_get_descriptor(usb_interface->dev, USB_DT_DEVICE, 0, &d, sizeof(d));
   return d.bcdDevice;
#elif HAVE_LIBUSB10
   struct libusb_device_descriptor d;
   libusb_get_descriptor(usb_interface->dev, LIBUSB_DT_DEVICE, 0, (unsigned char *)&d, sizeof(d));
   return d.bcdDevice;
#else
   return 0;
#endif
}

/* end */
