/****************************************************************/
/* hostusb.c                                                    */
/****************************************************************/
/*                                                              */
/* WinUAE interface with windows dll                            */
/*                                                              */
/****************************************************************/
/*                                                              */
/* Modification history                                         */
/* ====================                                         */
/* 28-Jan-2013 Add libusbx stuff                                */
/* 01-Aug-2012 Add usb_resetep, usb_clear_halt                  */
/* 30-Jul-2012 Add usb_set_altinterface, usb_set_configuration  */
/* 26-Jul-2012 Add usb_command_msg + debug                      */
/* 18-Jul-2012 Add libusb stuff                                 */
/* 21-Jun-2012 creation                                         */
/****************************************************************/

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

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/libraries.h>

#include "hostusb.h"

#include <proto/exec.h>



/* lowlevel interface with the dll */

ULONG funcHostDebug             = 0 ;
ULONG funcHostNoDebug           = 0 ;
ULONG funcHostOpen              = 0 ;
ULONG funcHostFOpen             = 0 ;
ULONG funcHostClose             = 0 ;
ULONG funcHostRead              = 0 ;
ULONG funcHostWrite             = 0 ;
ULONG funcHostSeek              = 0 ;
ULONG funcHostCopyMem           = 0 ;
ULONG funcusb_init              = 0 ;
ULONG funcusb_find_busses       = 0 ;
ULONG funcusb_find_devices      = 0 ;
ULONG funcusb_get_busses        = 0 ;
ULONG funcusb_get_version       = 0 ;
ULONG funcusb_open              = 0 ;
ULONG funcusb_close             = 0 ;
ULONG funcusb_bulk_write        = 0 ; 
ULONG funcusb_bulk_read         = 0 ; 
ULONG funcusb_interrupt_write   = 0 ; 
ULONG funcusb_interrupt_read    = 0 ; 
ULONG funcusb_control_msg       = 0 ;
ULONG funcusb_set_configuration = 0 ;
ULONG funcusb_claim_interface   = 0 ;
ULONG funcusb_release_interface = 0 ;
ULONG funcusb_set_altinterface  = 0 ;
ULONG funcusb_resetep           = 0 ;
ULONG funcusb_clear_halt        = 0 ;

ULONG funclibusb_init                      = 0 ;
ULONG funclibusb_exit                      = 0 ;
ULONG funclibusb_set_debug                 = 0 ;
ULONG funclibusb_get_version               = 0 ;
ULONG funclibusb_has_capability            = 0 ;
ULONG funclibusb_error_name                = 0 ;
ULONG funclibusb_get_device_list           = 0 ;
ULONG funclibusb_free_device_list          = 0 ;
ULONG funclibusb_get_device_descriptor     = 0 ;
ULONG funclibusb_get_bus_number            = 0 ;
ULONG funclibusb_get_port_number           = 0 ;
ULONG funclibusb_get_parent                = 0 ;
ULONG funclibusb_get_device_address        = 0 ;
ULONG funclibusb_get_device_speed          = 0 ;
ULONG funclibusb_open                      = 0 ;
ULONG funclibusb_close                     = 0 ;
ULONG funclibusb_claim_interface           = 0 ;
ULONG funclibusb_release_interface         = 0 ;
ULONG funclibusb_set_interface_alt_setting = 0 ;
ULONG funclibusb_clear_halt                = 0 ;
ULONG funclibusb_control_transfer          = 0 ;
ULONG funclibusb_bulk_transfer             = 0 ;
ULONG funclibusb_interrupt_transfer        = 0 ;

void __asm HostDebug(register __d1 ULONG level)
{
  if (funcHostDebug != 0)
  {
    DLL_Exec(funcHostDebug) ;
  }
}

void SetDebug(int level)
{
  if (level > 0)
  {
    HostDebug(level) ;
  }
  else
  {
    if (funcHostNoDebug != 0)
    {
      DLL_Exec(funcHostNoDebug) ;
    }
    else
    {
      HostDebug(0) ;
    }
  }
}

/* HostOpen(name,accessMode)(d1/d2) */
/* name       MSDOS name, must be in chip ram + offset */
/* accessMode 1004, 1005, 1006 */
ULONG __asm HostOpen(register __d1 UBYTE *name, register __d2 ULONG accessMode)
{
  if (funcHostOpen != 0)
  {
    return DLL_Exec(funcHostOpen) ;
  }
  return 0 ;
}

/* HostFOpen(name, mode)(d1/d2) */
/* name  MSDOS name, must be in chip ram + offset(0) */
/* mode "rb+", "wb" must be in chip ram + offset(0) */
ULONG __asm HostFOpen(register __d1 UBYTE *name, register __d2 UBYTE *mode)
{
  if (funcHostFOpen != 0)
  {
    return DLL_Exec(funcHostFOpen) ;
  }
  return 0 ;
}

/* HostClose(file)(d1) */
void __asm HostClose(register __d1 ULONG file)
{
  if (funcHostClose != 0)
  {
    DLL_Exec(funcHostClose) ;
  }
}

/* HostRead(file,buffer,length)(d1/d2/d3) */
/* warning buffer must be in chip */
ULONG __asm HostRead(register __d1 ULONG file, register __d2 UBYTE *buffer, register __d3 ULONG length)
{
  if (funcHostRead != 0)
  {
    return DLL_Exec(funcHostRead) ;
  }
  return 0 ;
}

/* HostWrite(file,buffer,length)(d1/d2/d3) */
/* warning buffer must be in chip */
ULONG __asm HostWrite(register __d1 ULONG file, register __d2 UBYTE *buffer, register __d3 ULONG length)
{
  if (funcHostWrite != 0)
  {
    return DLL_Exec(funcHostWrite) ;
  }
  return 0 ;
}

/* HostSeek*/
ULONG __asm HostSeek(register __d1 ULONG file, register __d2 ULONG position, register __d3 ULONG offset)
{
  if (funcHostSeek != 0)
  {
    return DLL_Exec(funcHostSeek) ;
  }
  return 0 ;
}

void __asm HostCopyMem(register __d1 char *src, register __d2 char *dst, register __d3 ULONG length)
{
  if (funcHostCopyMem != 0)
  {
    DLL_Exec(funcHostCopyMem) ;
  }
}

long __asm usb_init(void)
{
  if (funcusb_init != 0)
  {
    return (long)DLL_Exec(funcusb_init) ;
  }
  return -2 ;
}

#if 0
void __asm usb_set_debug(register __d1 ULONG level)
{
  if (funcusb_set_debug != 0)
  {
    DLL_Exec(funcusb_set_debug) ;
  }
}
#endif

int __asm usb_find_busses(void)
{
  if (funcusb_find_busses != 0)
  {
    return (int)DLL_Exec(funcusb_find_busses) ;
  }
  return -1 ;
}

int __asm usb_find_devices(void)
{
  if (funcusb_find_devices != 0)
  {
    return (int)DLL_Exec(funcusb_find_devices) ;
  }
  return -1 ;
}

struct usb_bus * __asm usb_get_busses(void)
{
  if (funcusb_get_busses != 0)
  {
    return (struct usb_bus *) DLL_Exec(funcusb_get_busses) ;
  }
  return 0 ;
}

#if 0
struct usb_bus * __asm usb_get_next_bus(register __d1 struct usb_bus *current)
{
  if (funcusb_get_next_bus != 0)
  {
    return (struct usb_bus *)DLL_Exec(funcusb_get_next_bus) ;
  }
  return 0 ;
}
#endif

ULONG __asm usb_get_version(void)
{
  if (funcusb_get_version != 0)
  {
    return (ULONG)DLL_Exec(funcusb_get_version) ;
  }

  return NULL ;
}

#if 0
void __asm usb_get_version2(register __d1 UBYTE *ver)
{
  if (funcusb_get_version2 != 0)
  {
    DLL_Exec(funcusb_get_version2) ;
  }
}
#endif

ULONG __asm usb_open(register __d1 ULONG dev)
{
  if (funcusb_open != 0)
  {
    return (ULONG)DLL_Exec(funcusb_open) ;
  }

  return NULL ;
}

void __asm usb_close(register __d1 ULONG udev)
{
  if (funcusb_close != 0)
  {
    DLL_Exec(funcusb_close) ;
  }
}

#if 0
void __asm usb_get_string_simple(
register __d1 usb_dev_handle *udev,
register __d2 int index,
register __d3 char *buf,
register __d4 size_t buflen)
{
  if (funcusb_get_string_simple != 0)
  {
    DLL_Exec(funcusb_get_string_simple) ;
  }
}
#endif

int __asm usb_bulk_write(
register __d1 ULONG dev,
register __d2 ULONG ep,
register __d3 ULONG bytes,
register __d4 ULONG size,
register __d5 ULONG timeout)
{
  if (funcusb_bulk_write != 0)
  {
    return (int)DLL_Exec(funcusb_bulk_write) ;
  }
  return -1 ;
}

int __asm usb_bulk_read(
register __d1 ULONG dev,
register __d2 ULONG ep,
register __d3 ULONG bytes,
register __d4 ULONG size,
register __d5 ULONG timeout)
{
  if (funcusb_bulk_read != 0)
  {
    return (int)DLL_Exec(funcusb_bulk_read) ;
  }
  return -1 ; 
}

int __asm usb_interrupt_write(
register __d1 ULONG dev,
register __d2 ULONG ep,
register __d3 ULONG bytes,
register __d4 ULONG size,
register __d5 ULONG timeout)
{
  if (funcusb_interrupt_write != 0)
  {
    return (int)DLL_Exec(funcusb_interrupt_write) ;
  }
  return -1 ;
}

int __asm usb_interrupt_read(
register __d1 ULONG dev,
register __d2 ULONG ep,
register __d3 ULONG bytes,
register __d4 ULONG size,
register __d5 ULONG timeout)
{
  if (funcusb_interrupt_read != 0)
  {
    return (int)DLL_Exec(funcusb_interrupt_read) ;
  }
  return -1 ;
}

int __asm usb_control_msg(
register __d1 ULONG udev,
register __d2 ULONG requesttype,
register __d3 ULONG request,
register __d4 ULONG value,
register __d5 ULONG index,
register __d6 ULONG /*char **/bytes,
register __d7 ULONG size,
register __a1 ULONG timeout)
{
  if (funcusb_control_msg != 0)
  {
    return (int)DLL_Exec(funcusb_control_msg) ;
  }
  return -1 ;
}

int __asm usb_set_configuration(
register __d1 ULONG udev,
register __d2 int config
)
{
  if (funcusb_set_configuration != 0)
  {
    return (int)DLL_Exec(funcusb_set_configuration) ;
  }
  return -1 ;
}

int __asm usb_claim_interface(
register __d1 ULONG udev,
register __d2 int interface
)
{
  if (funcusb_claim_interface != 0)
  {
    return (int)DLL_Exec(funcusb_claim_interface) ;
  }
  return -1 ;
}

int __asm usb_release_interface(
register __d1 ULONG udev,
register __d2 int interface
)
{
  if (funcusb_release_interface != 0)
  {
    return (int)DLL_Exec(funcusb_release_interface) ;
  }
  return -1 ;
}

int __asm usb_set_altinterface(
register __d1 ULONG udev,
register __d2 int alternate
)
{
  if (funcusb_set_altinterface != 0)
  {
    return (int)DLL_Exec(funcusb_set_altinterface) ;
  }
  return -1 ;
}

int __asm usb_resetep(
register __d1 ULONG udev,
register __d2 int ep
)
{
  if (funcusb_resetep != 0)
  {
    return (int)DLL_Exec(funcusb_resetep) ;
  }
  return -1 ;
}

int __asm usb_clear_halt(
register __d1 ULONG udev,
register __d2 int ep
)
{
  if (funcusb_clear_halt != 0)
  {
    return (int)DLL_Exec(funcusb_clear_halt) ;
  }
  return -1 ;
}

/***************************************************************************/
/**                               LIBUSBX                                 **/
/***************************************************************************/
long __asm libusb_init(
register __d1 ULONG ctx
)
{
  printf("ctx %08lx\n", ctx) ;
  if (funclibusb_init != 0)
  {
    return (long)DLL_Exec(funclibusb_init) ;
  }
  return -2 ;
}

long __asm libusb_exit(
register __d1 ULONG ctx
)
{
  if (funclibusb_exit != 0)
  {
    return (long)DLL_Exec(funclibusb_exit) ;
  }
  return -2 ;
}

ULONG * __asm libusb_get_version(void)
{
  if (funclibusb_get_version != 0)
  {
    return (ULONG *)DLL_Exec(funclibusb_get_version) ;
  }

  return NULL ;
}

ULONG * __asm libusb_error_name(register __d1 ULONG errcode)
{
  if (funclibusb_error_name != 0)
  {
    return (ULONG *)DLL_Exec(funclibusb_error_name) ;
  }

  return NULL ;
}

int __asm libusb_get_device_list(
register __d1 ULONG ctx,
register __d2 ULONG list
)
{
  if (funclibusb_get_device_list != 0)
  {
    return (int)DLL_Exec(funclibusb_get_device_list) ;
  }

  return -1 ;
}

void __asm libusb_free_device_list(
register __d1 ULONG list,
register __d2 ULONG unref_devices
)
{
  if (funclibusb_free_device_list != 0)
  {
    DLL_Exec(funclibusb_free_device_list) ;
  }
}


ULONG __asm libusb_get_device_descriptor(
register __d1 ULONG /*libusb_device * */ dev,
register __d2 ULONG /*struct libusb_device_descriptor * */ desc
)
{
  if (funclibusb_get_device_descriptor)
  {
    return DLL_Exec(funclibusb_get_device_descriptor) ;
  }

  return -8 ;
}

ULONG __asm libusb_get_bus_number(
register __d1 ULONG dev
)
{
  if (funclibusb_get_bus_number != 0)
  {
    return DLL_Exec(funclibusb_get_bus_number) & 0xff ;
  }

  return -8 ;
}

ULONG __asm libusb_get_port_number(
register __d1 ULONG dev
)
{
  if (funclibusb_get_port_number != 0)
  {
    return DLL_Exec(funclibusb_get_port_number) & 0xff ;
  }

  return -8 ;
}

ULONG __asm libusb_get_parent(
register __d1 ULONG dev
)
{
  if (funclibusb_get_parent != 0)
  {
    return DLL_Exec(funclibusb_get_parent) ;
  }

  return NULL ;
}

ULONG __asm libusb_get_device_address(
register __d1 ULONG dev
)
{
  if (funclibusb_get_device_address != 0)
  {
    return DLL_Exec(funclibusb_get_device_address) & 0xff ;
  }

  return -8 ;
}

ULONG __asm libusb_get_device_speed(
register __d1 ULONG dev
)
{
  if (funclibusb_get_device_speed != 0)
  {
    return DLL_Exec(funclibusb_get_device_speed) ;
  }

  return 0 ;
}

int __asm libusb_open(register __d1 ULONG dev, register __d2 ULONG handleptr)
{
  if (funclibusb_open != 0)
  {
    return (int)DLL_Exec(funclibusb_open) ;
  }

  return -4 ;
}

void __asm libusb_close(register __d1 ULONG handle)
{
  if (funclibusb_close != 0)
  {
    DLL_Exec(funclibusb_close) ;
  }
}

int __asm libusb_claim_interface(register __d1 ULONG handle, register __d2 ULONG interface)
{
  if (funclibusb_claim_interface != 0)
  {
    return (int)DLL_Exec(funclibusb_claim_interface) ;
  }

  return -4 ;
}

int __asm libusb_release_interface(register __d1 ULONG handle, register __d2 ULONG interface)
{
  if (funclibusb_release_interface != 0)
  {
    return (int)DLL_Exec(funclibusb_release_interface) ;
  }

  return -4 ;
}

int __asm libusb_set_interface_alt_setting(register __d1 ULONG handle, register __d2 ULONG interface_number, register __d3 ULONG alternate_setting)
{
  if (funclibusb_set_interface_alt_setting != 0)
  {
    return (int)DLL_Exec(funclibusb_set_interface_alt_setting) ;
  }

  return -4 ;  
}

int __asm libusb_clear_halt(register __d1 ULONG handle, register __d2 ULONG endpoint) 
{
  if (funclibusb_clear_halt != 0)
  {
    return (int)DLL_Exec(funclibusb_clear_halt) ;
  }

  return -4 ;  
}

int __asm libusb_control_transfer(
register __d1 ULONG dev_handle,
register __d2 ULONG request_type,
register __d3 ULONG request,
register __d4 ULONG value,
register __d5 ULONG index,
register __d6 ULONG bytes,
register __d7 ULONG size,
register __a1 ULONG timeout)
{
  if (funclibusb_control_transfer != 0)
  {
    return (int)DLL_Exec(funclibusb_control_transfer) ;
  }

  return -1 ;
}

int __asm libusb_bulk_transfer(
register __d1 ULONG dev_handle,
register __d2 ULONG endpoint,
register __d3 ULONG data,
register __d4 ULONG length,
register __d5 ULONG actual_length,
register __d6 ULONG timeout)
{
  if (funclibusb_bulk_transfer != 0)
  {
    return (int)DLL_Exec(funclibusb_bulk_transfer) ;
  }

  return -1 ;
}

int __asm libusb_interrupt_transfer(
register __d1 ULONG dev_handle,
register __d2 ULONG endpoint,
register __d3 ULONG data,
register __d4 ULONG length,
register __d5 ULONG actual_length,
register __d6 ULONG timeout)
{
  if (funclibusb_bulk_transfer != 0)
  {
    return (int)DLL_Exec(funclibusb_bulk_transfer) ;
  }

  return -1 ;
}

/* Helpers */

ULONG DLLOpen(UBYTE *name, ULONG accessMode)
{
  struct Library *SysBase = *(struct Library **)4 ;
  ULONG ret = NULL ;

  if (name != NULL)
  {
    ULONG len = strlen(name) ;
    UBYTE *chipname ;

    if (len > 0)
    {
      chipname = AllocMem(len+8, MEMF_CHIP) ;
      if (chipname != NULL)
      {
        if (((struct Library*)SysBase)->lib_Version >= 33)
        {
          CopyMem(name, chipname, len+1) ;
        }
        else
        {
          memcpy(chipname, name, len+1) ;
        }

        ret = HostOpen(DLL_GetMemoryOffset()+chipname, accessMode) ;

        FreeMem(chipname, len+8) ;
      }
    }
  }

  return ret ;
}

ULONG DLLFOpen(UBYTE *name, UBYTE *mode)
{
  struct Library *SysBase = *(struct Library **) 4 ;
  ULONG ret = NULL ;

  if (name != NULL)
  {
    ULONG lenname ;
    ULONG lenmode ;
    UBYTE *chipname ;
    UBYTE *chipmode ;

    lenname = strlen(name) ;
    lenmode = strlen(mode) ;
   
    if ((lenname > 0) && (lenmode > 0))
    {
      chipname = AllocMem(lenname+8, MEMF_CHIP) ;
      chipmode = AllocMem(lenmode+8, MEMF_CHIP) ;

      if ((chipname != NULL) && (chipmode != NULL))
      {
        if (((struct Library *)SysBase)->lib_Version >= 33)
        {
          CopyMem(name, chipname, lenname+1) ;
          CopyMem(mode, chipmode, lenmode+1) ;
        }
        else
        {
          memcpy(chipname, name, lenname+1) ;
          memcpy(chipmode, mode, lenmode+1) ;
        }

        ret = HostFOpen(DLL_GetMemoryOffset()+chipname, DLL_GetMemoryOffset()+chipmode) ;

      }

      if (chipmode != NULL)
      {
        FreeMem(chipmode, lenmode+8) ;
      }

      if (chipname != NULL)
      {
        FreeMem(chipname, lenname+8) ;
      }
    }
  }

  return ret ;
}

void DLLClose(ULONG file)
{
  HostClose(file) ;
}

ULONG DLLSeek(ULONG file, ULONG position, ULONG offset)
{
  return HostSeek(file, position, offset) ;
}

ULONG DLLRead(ULONG file, UBYTE *buffer, ULONG length)
{
  struct Library *SysBase = *(struct Library **) 4 ;
  ULONG ret ;

  if ((buffer != NULL) && (length > 0))
  {
    UBYTE *chipbuffer ;

    chipbuffer = AllocMem(length, MEMF_CHIP) ;
    if (chipbuffer != NULL)
    {
      ret = HostRead(file, DLL_GetMemoryOffset()+chipbuffer, length) ;

      if (((struct Library *)SysBase)->lib_Version >= 33)
      {
        CopyMem(chipbuffer, buffer, length) ;
      }
      else
      {
        memcpy(buffer, chipbuffer, length) ;
      }

      FreeMem(chipbuffer, length) ;
    }
  }

  return ret ;
}

ULONG DLLWrite(ULONG file, UBYTE *buffer, ULONG length)
{
  struct Library *SysBase = *(struct Library **) 4 ;
  ULONG ret ;

  if ((buffer != NULL) && (length > 0))
  {
    UBYTE *chipbuffer ;

    chipbuffer = AllocMem(length, MEMF_CHIP) ;
    if (chipbuffer != NULL)
    {
      if (((struct Library *)SysBase)->lib_Version >= 33)
      {
        CopyMem(buffer, chipbuffer, length) ;
      }
      else
      {
        memcpy(chipbuffer, buffer, length) ;
      }

      ret = HostWrite(file, DLL_GetMemoryOffset()+chipbuffer, length) ;

      FreeMem(chipbuffer, length) ;
    }
  }

  return ret ;
}

ULONG DLLInit(void)
{
  ULONG handle = 0 ;
  UBYTE *dllname ;

  dllname = "hostusb.dll" ;
  handle = DLL_LoadLibrary(dllname) ;
  if (handle != 0)
  {
    funcHostDebug             = DLL_GetProcAddress(handle, "HostDebug") ;
    funcHostNoDebug           = DLL_GetProcAddress(handle, "HostNoDebug") ;

    funcHostOpen              = DLL_GetProcAddress(handle, "HostOpen") ;
    funcHostFOpen             = DLL_GetProcAddress(handle, "HostFOpen") ;
    funcHostClose             = DLL_GetProcAddress(handle, "HostClose") ;
    funcHostRead              = DLL_GetProcAddress(handle, "HostRead") ;
    funcHostWrite             = DLL_GetProcAddress(handle, "HostWrite") ;
    funcHostSeek              = DLL_GetProcAddress(handle, "HostSeek") ;
    funcHostCopyMem           = DLL_GetProcAddress(handle, "HostCopyMem") ;

    funcusb_init              = DLL_GetProcAddress(handle, "usb_init") ;
    funcusb_find_busses       = DLL_GetProcAddress(handle, "usb_find_busses") ;
    funcusb_find_devices      = DLL_GetProcAddress(handle, "usb_find_devices") ;
    funcusb_get_busses        = DLL_GetProcAddress(handle, "usb_get_busses") ;
    funcusb_get_version       = DLL_GetProcAddress(handle, "usb_get_version") ;
    funcusb_open              = DLL_GetProcAddress(handle, "usb_open") ;
    funcusb_close             = DLL_GetProcAddress(handle, "usb_close") ;
    funcusb_bulk_write        = DLL_GetProcAddress(handle, "usb_bulk_write") ;
    funcusb_bulk_read         = DLL_GetProcAddress(handle, "usb_bulk_read") ;
    funcusb_interrupt_write   = DLL_GetProcAddress(handle, "usb_interrupt_write") ;
    funcusb_interrupt_read    = DLL_GetProcAddress(handle, "usb_interrupt_read") ;
    funcusb_control_msg       = DLL_GetProcAddress(handle, "usb_control_msg") ;
    funcusb_set_configuration = DLL_GetProcAddress(handle, "usb_set_configuration") ;
    funcusb_claim_interface   = DLL_GetProcAddress(handle, "usb_claim_interface") ;
    funcusb_release_interface = DLL_GetProcAddress(handle, "usb_release_interface") ;
    funcusb_set_altinterface  = DLL_GetProcAddress(handle, "usb_set_altinterface") ;
    funcusb_resetep           = DLL_GetProcAddress(handle, "usb_resetep") ;
    funcusb_clear_halt        = DLL_GetProcAddress(handle, "usb_clear_halt") ;

    funclibusb_init             = DLL_GetProcAddress(handle, "libusb_init") ;
    funclibusb_exit             = DLL_GetProcAddress(handle, "libusb_exit") ;
    funclibusb_get_version      = DLL_GetProcAddress(handle, "libusb_get_version") ;
    funclibusb_error_name       = DLL_GetProcAddress(handle, "libusb_error_name") ;
    funclibusb_get_device_list  = DLL_GetProcAddress(handle, "libusb_get_device_list") ;
    funclibusb_free_device_list = DLL_GetProcAddress(handle, "libusb_free_device_list") ;
    funclibusb_control_transfer = DLL_GetProcAddress(handle, "libusb_control_transfer") ;
    funclibusb_bulk_transfer    = DLL_GetProcAddress(handle, "libusb_bulk_transfer") ;
    funclibusb_interrupt_transfer = DLL_GetProcAddress(handle, "libusb_interrupt_transfer") ;
    funclibusb_get_device_descriptor = DLL_GetProcAddress(handle, "libusb_get_device_descriptor") ;
    funclibusb_get_bus_number     = DLL_GetProcAddress(handle, "libusb_get_bus_number") ;
    funclibusb_get_port_number    = DLL_GetProcAddress(handle, "libusb_get_port_number") ;
    funclibusb_get_parent         = DLL_GetProcAddress(handle, "libusb_get_parent") ;
    funclibusb_get_device_address = DLL_GetProcAddress(handle, "libusb_get_device_address") ;
    funclibusb_get_device_speed   = DLL_GetProcAddress(handle, "libusb_get_device_speed") ;
    funclibusb_open               = DLL_GetProcAddress(handle, "libusb_open") ;
    funclibusb_close              = DLL_GetProcAddress(handle, "libusb_close") ;
    funclibusb_claim_interface    = DLL_GetProcAddress(handle, "libusb_claim_interface") ;
    funclibusb_release_interface  = DLL_GetProcAddress(handle, "libusb_release_interface") ;
    funclibusb_set_interface_alt_setting = DLL_GetProcAddress(handle, "libusb_setinterface_alt_setting") ;
    funclibusb_clear_halt         = DLL_GetProcAddress(handle, "libusb_clear_halt") ;
    funclibusb_control_transfer   = DLL_GetProcAddress(handle, "libusb_control_transfer") ;
    funclibusb_bulk_transfer      = DLL_GetProcAddress(handle, "libusb_bulk_transfer") ;
    funclibusb_interrupt_transfer = DLL_GetProcAddress(handle, "libusb_interrupt_transfer") ;  
  }
  return handle ;
}

void DLLFree(ULONG handle)
{
  if (handle != 0)
  {
    DLL_FreeLibrary(handle) ;
  }

  funcHostDebug             = 0 ;
  funcHostNoDebug           = 0 ;

  funcHostOpen              = 0 ;
  funcHostFOpen             = 0 ;
  funcHostClose             = 0 ;
  funcHostRead              = 0 ;
  funcHostWrite             = 0 ;
  funcHostSeek              = 0 ;
  funcHostCopyMem           = 0 ;
  funcusb_init              = 0 ;
  funcusb_find_busses       = 0 ;
  funcusb_find_devices      = 0 ;
  funcusb_get_busses        = 0 ;
  funcusb_get_version       = 0 ;
  funcusb_open              = 0 ;
  funcusb_close             = 0 ;
  funcusb_bulk_write        = 0 ;
  funcusb_bulk_read         = 0 ;
  funcusb_interrupt_write   = 0 ;
  funcusb_interrupt_read    = 0 ;
  funcusb_control_msg       = 0 ;
  funcusb_set_configuration = 0 ;
  funcusb_claim_interface   = 0 ;
  funcusb_release_interface = 0 ;
  funcusb_set_altinterface  = 0 ;
  funcusb_resetep           = 0 ;
  funcusb_clear_halt        = 0 ;

  funclibusb_init                      = 0 ;
  funclibusb_exit                      = 0 ;
  funclibusb_get_version               = 0 ;
  funclibusb_error_name                = 0 ;
  funclibusb_get_device_list           = 0 ;
  funclibusb_free_device_list          = 0 ;
  funclibusb_control_transfer          = 0 ;
  funclibusb_bulk_transfer             = 0 ;
  funclibusb_interrupt_transfer        = 0 ;
  funclibusb_get_device_descriptor     = 0 ;
  funclibusb_get_bus_number            = 0 ;
  funclibusb_get_port_number           = 0 ;
  funclibusb_get_parent                = 0 ;
  funclibusb_get_device_address        = 0 ;
  funclibusb_get_device_speed          = 0 ;
  funclibusb_open                      = 0 ;
  funclibusb_close                     = 0 ;
  funclibusb_claim_interface           = 0 ;
  funclibusb_release_interface         = 0 ;
  funclibusb_set_interface_alt_setting = 0 ;
  funclibusb_clear_halt                = 0 ;
  funclibusb_control_transfer          = 0 ;
  funclibusb_bulk_transfer             = 0 ;
  funclibusb_interrupt_transfer        = 0 ;
}

