/****************************************************************/
/* hcddemo.c                                                    */
/****************************************************************/
/*                                                              */
/* HCD driver template                                          */
/*                                                              */
/****************************************************************/
/*                                                              */
/* Modification history                                         */
/* ====================                                         */
/* 21-Nov-2013 detach notification libusbx                      */
/* 20-Nov-2013 AllocMem of 32 instead of 8... crash if not      */
/* 05-Nov-2013 libusb_control                                   */
/* 10-Oct-2013 Be careful with DOSBase...                       */
/* 30-Sep-2013 uae.resource                                     */
/* 07-Feb-2013 Add some protection to avoid crashes on Amiga    */
/* 26-Jan-2013 Add libusbx                                      */
/* 20-Jan-2013 io_Actual missing for usb massstorage            */
/* 12-Jan-2013 Add interfacename + configname                   */
/* 02-Dec-2012 Add HCD statistics                               */
/* 29-Sep-2012 Clean traces                                     */
/* 09-Aug-2012 Add usb_clear_halt                               */
/* 02-Aug-2012 Add Claim/Release interface                      */
/* 31-Jul-2012 Reduce alloc/free mem count                      */
/* 18-Jul-2012 libusb                                           */
/* 21-Jun-2012 pb with okmouse                                  */
/* 20-Jun-2012 host DLL                                         */
/* 30-Dec-2011 (6,1,1) PTP                                      */
/* 16-Jun-2011 problems under WB 31                             */
/* 06-May-2011 Level 1 and level 0                              */
/* 04-Mar-2011 SCSI Read Write (6, 10, 12, 16)                  */
/* 07-Nov-2010 3 modules                                        */
/* 14-Sep-2010 Process                                          */
/* 16-Mar-2010 HCDQuery                                         */
/* 01-Mar-2010 all demo code is here now                        */
/* 02-Jul-2009 demo code                                        */
/* 04-Nov-2008 more code                                        */
/* 01-Jun-2008 first steps                                      */
/****************************************************************/

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

#include <exec/exec.h>
#include <clib/alib_protos.h>
#include <exec/memory.h>
#include <exec/devices.h>
#include <exec/resident.h>
#include <exec/errors.h>
#include <exec/io.h>

#include <dos/dosextens.h>

#define __NOLIBBASE__
#define __USE_BASETYPE__
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>

#include <usb/system.h>
#include <usb/hub.h>

#include "compiler.h"
#include "anaiis.h"

#ifdef OKHOSTDLL
#include "hostusb.h"
#endif

#define LIBUSBX        1
#define HCDDEMOPROCESS 0
#define SIMULTIME      0
#define TRACE          0
#define PTP_KODAK      0

/* version stuff */
#define VERSION       1
#define REVISION      9
#define VSVERSION    "1"
#define VSREVISION  "09"

#ifdef OKHOSTDLL
#define OKMASS 1
#define DEV_NAME    "hostusb.usbhcd"
#define DEV_VSTRING "host usbhcd " VSVERSION "." VSREVISION " (" __DATE__ ")\r\n"
#else
#ifdef OKPSC2200
#define OKPTP 1
#define DEV_NAME    "demo.usbhcd"
#define DEV_VSTRING "usbhcd demo " VSVERSION "." VSREVISION " (" __DATE__ ")\r\n"
#else
#ifdef OKMOUSE
#define DEV_NAME    "noway.usbhcd"
#define DEV_VSTRING "usbhcd demo " VSVERSION "." VSREVISION " (" __DATE__ ")\r\n"
#else
#define DEV_NAME    "elmer.usbhcd"
#define DEV_VSTRING "usbhcd demo " VSVERSION "." VSREVISION " (" __DATE__ ")\r\n"
#endif
#endif
#endif

/* NEED to check that */
#define USBREQC_GET_PORT_STATUS         1


UBYTE DevName[] = { DEV_NAME } ;
UBYTE DevID[]   = { DEV_VSTRING } ;

UBYTE _ProgramName[] = { DEV_NAME } ;
long _XCEXIT ;
long _OSERR ;

#define CMD_OpenUnit  (CMD_NONSTD + 2100)
#define CMD_CloseUnit (CMD_NONSTD + 2101)

struct DeviceUnit
{
  struct Unit    du_Unit ;
  struct Task    *du_Task ;       /* level 1 task */

  UBYTE du_NameL0[40] ;
  UBYTE du_NameL1[40] ;

  /* demo purpose only, in true world the following is done by hardware */
  struct MsgPort *du_uhc124Port ;
  struct Task    *du_uhc124Task ; /* level 0 task */

#ifdef OKHOSTDLL
  /* */
  UBYTE *datachip ;
#if LIBUSBX
  UBYTE *datachip2 ;
  ULONG libusbx_devscnt ;
  ULONG libusbx_devs ;
#endif
#endif

  UWORD dev0step ;
  UWORD dev0steplibusb ;
  UWORD dev0maxlibusb ;    /* total libusb or libusbx present */
  UWORD dev0maxlibusbok ;  /* total devices ready to use */


  UWORD hub_config ;
  UWORD hub_altsetting ;
  UWORD hub_interface ;
  ULONG hub_port[20] ;

  UWORD mouse_config ;
  UWORD mouse_altsetting ;
  UWORD mouse_interface ;
  ULONG mouse_old ;

  UWORD printer1_config ;
  UWORD printer1_altsetting ;
  UWORD printer1_interface ;

  UWORD printer2_config ;
  UWORD printer2_altsetting ;
  UWORD printer2_interface ;

  UWORD printer6_config ;
  UWORD printer6_altsetting ;
  UWORD printer6_interface ;

  ULONG mass6_filesize ;
  UBYTE mass6_state ;
  UBYTE mass6_scsi[31] ;
  UBYTE mass6_data[512] ;
  UBYTE mass6_status[13] ;

  UWORD mass_config ;
  UWORD mass_altsetting ;
  UWORD mass_interface ;

  ULONG mass_filesize ;
  UBYTE mass_state ;
  UBYTE mass_scsi[31] ;
  UBYTE mass_data[512] ;
  UBYTE mass_status[13] ;

  UWORD ptp_config ;
  UWORD ptp_altsetting ;
  UWORD ptp_interface ;
  ULONG ptp_index ;
  UBYTE ptp_op[512] ;

  struct USBHCDQuery audit ;

  ULONG serialnumber ;
  ULONG hwnumber ;
} ;

struct SegList
{
  ULONG length ;
  ULONG next ;
  UWORD jumpcode ;
  APTR  entry ;
  UWORD pad ;
} ;

struct HCDBase
{
  struct Library    hcd_Library ;
  UWORD             pad0 ;
  BPTR              hcd_SegList ;

  /* strictly private stuff */
  struct Library   *hcd_SysBase ;
  ULONG             hcd_Counter ;
  struct DeviceUnit hcd_Unit ;

  struct Library    *AnaiisPrivateBase ;
#if HCDDEMOPROCESS
  struct Library    *DOSBase ;
#endif
  struct Node       *hw ;

  int            buswidth ;
  struct timeval read8 ;      /* read byte */
  struct timeval write8 ;     /* write byte */
  struct timeval read16 ;     /* read short */
  struct timeval write16 ;    /* write short */
  struct timeval read32 ;     /* read long */
  struct timeval write32 ;    /* write long */
  struct timeval ccread8 ;    /* custom chip read byte access */
  struct timeval ccwrite8 ;   /* custom chip write byte access */
  struct timeval ccread16 ;   /* custom chip read short access */
  struct timeval ccwrite16 ;  /* custom chip write short access */  
  struct timeval ccreadblk ;  /* custom chip read long access */
  struct timeval ccwriteblk ; /* custom chip write long access */

  ULONG segdata[8] ;

#ifdef OKHOSTDLL
  ULONG dllhandle ;
#endif
} ;

void ASM SDS procmainloop(void) ;
void ASM SDS procuhc124loop(void) ;

static void ASM SDS SendCmd(
A0 struct HCDBase    *db,
A1 struct DeviceUnit *du,
D0 UWORD command
)
{
  struct IORequest ior ;
  struct MsgPort   port ;

  memset(&port, 0, sizeof(port)) ;
  port.mp_Node.ln_Type = NT_MSGPORT ;
  port.mp_Flags   = PA_SIGNAL ;
  port.mp_SigBit  = SIGB_SINGLE ;
  port.mp_SigTask = FindTask(NULL) ;
  NewList(&port.mp_MsgList) ;

  memset(&ior, 0, sizeof(ior)) ;
  ior.io_Message.mn_ReplyPort = &port ;
  ior.io_Message.mn_Length    = sizeof(ior) ;
  ior.io_Unit                 = (struct Unit*)du ;
  ior.io_Device               = (struct Device *)db ;
  ior.io_Command              = command ;

  SetSignal(0, SIGF_SINGLE) ;

  PutMsg(&ior.io_Unit->unit_MsgPort, (struct Message *)&ior) ;
  WaitPort(&port) ;
}

struct TagItem * ASM SDS UT_NextTagItem(A0 struct TagItem **tagListPtr)
{
  struct TagItem *ti = NULL ;

  if (tagListPtr != NULL)
  {
    if (*tagListPtr != NULL)
    {
      int loop = TRUE ;
      while (loop)
      {
        switch ((*tagListPtr)->ti_Tag)
        {
	  case TAG_END :
          {
            /* Terminate array of TagItems */
            (*tagListPtr) = NULL ;
            loop = FALSE ;
            ti = NULL ;
            break ;
          }

          case TAG_IGNORE:
          {
            /* Ignore this item, not end of array */
            (*tagListPtr) ++;
            break ;
          }

          case TAG_MORE:
          {
            /* ti_Data is pointer to another array of TagItems */
            *tagListPtr = (struct TagItem *)(*tagListPtr)->ti_Data ;
            if (tagListPtr == NULL)
            {
              loop = FALSE ;
              ti = NULL ;
            }
            break ;
          }

          case TAG_SKIP:
          {
            /* skip this and the next ti_Data items */
            (*tagListPtr) += (*tagListPtr)->ti_Data + 1 ;
	    break ;
          }

          default:
          {
            loop = FALSE ;
	    ti = (struct TagItem *)(*tagListPtr)++ ;
            break ;
          }
        }
      }
    }
  }

  return ti ;
}

/****/

struct TraceMessage
{
  struct Message msg ;
  long type ;
  long subtype ;
  BPTR file ;
  char *str ;
  long offset ;
  long len ;
} ;

static void TraxMsg(struct TraceMessage *msg)
{
  struct MsgPort *port ;
  struct MsgPort *replyport ;

  port = FindPort("TraxPort-GP") ;
  if (port)
  {
    replyport = CreatePort(NULL, 0) ;
    if (replyport != NULL)
    {
      msg->msg.mn_Node.ln_Type = NT_MESSAGE ;
      msg->msg.mn_ReplyPort = replyport ;
      msg->msg.mn_Length = sizeof(struct TraceMessage) ;
      PutMsg(port, (struct Message *)msg) ;
      WaitPort(replyport) ;
      GetMsg(replyport) ;
      DeletePort(replyport) ;
    }
  }
}

static BPTR MyOpen(char *name, long openarg)
{
  struct TraceMessage MSG ;

  memset(&MSG, 0, sizeof(MSG)) ;

  MSG.type    = 0 ;
  MSG.subtype = openarg ;
  MSG.str     = name ;
  TraxMsg(&MSG) ;

  return MSG.file ;
}

static void MyClose(BPTR f)
{
  struct TraceMessage MSG ;

  memset(&MSG, 0, sizeof(MSG)) ;

  MSG.type    = -1 ;
  MSG.file    = f ;
  TraxMsg(&MSG) ;
}

static void MyWrite(BPTR f, APTR data, LONG len)
{
  struct TraceMessage MSG ;

  memset(&MSG, 0, sizeof(MSG)) ;

  MSG.type    = 1 ;
  MSG.file    = f ;
  MSG.str     = data ;
  MSG.len     = len ;
  TraxMsg(&MSG) ;
}

static void MyTrace(char *str)
{
#if TRACE
  struct TraceMessage MSG ;

  memset(&MSG, 0, sizeof(MSG)) ;

  MSG.type    = 4 ;
  MSG.str     = str ;
  TraxMsg(&MSG) ;
#endif
}

/******/
#ifdef OKHOSTDLL
ULONG USB_open(ULONG device)
{
#if TRACE
  char cBuf[256] ;
#endif
  ULONG handle = 0 ;
#if LIBUSBX
  ULONG *handleptr = NULL ;
  LONG r = 0 ;

  if (device != 0)
  {
    handleptr = AllocMem(32, MEMF_CLEAR|MEMF_CHIP) ;
    if (handleptr != NULL)
    {
      r = libusb_open(device, (ULONG)(DLL_GetChipOffset()+(char*)handleptr)) ;
      if (r == 0)
      {
        handle = LE_LONG(*handleptr) ;
      }
      FreeMem(handleptr, 32) ;
    }
  }
#else
  handle = usb_open(device) ;
#endif
#if TRACE
#if LIBUSBX
  sprintf(cBuf, "libusb_open(%08lx,%08lx) => %08lx (%ld)\n", device, handleptr, handle, r) ;
#else
  sprintf(cBuf, "usb_open(%08lx) => %08lx\n", device, handle) ;
#endif
  MyTrace(cBuf) ;
#endif
  return handle ;
}

void USB_close(ULONG handle)
{
#if LIBUSBX
  libusb_close(handle) ;
#else
  usb_close(handle) ;
#endif
}

LONG USB_claim_interface(ULONG handle, ULONG internum)
{
  LONG err ;
#if LIBUSBX
  err = libusb_claim_interface(handle, internum) ;
#else
  err = usb_claim_interface(handle, internum) ;
#endif
  return err ;
}

void USB_release_interface(ULONG handle, ULONG intnum)
{
#if LIBUSBX
  libusb_release_interface(handle, intnum) ;
#else
  usb_release_interface(handle, intnum) ;
#endif
}

LONG USB_set_altinterface(ULONG handle, ULONG intnum, ULONG altnum)
{
  LONG err ;
#if LIBUSBX
  err = libusb_set_interface_alt_setting(handle, intnum, altnum) ;
#else
  err = usb_set_altinterface(handle, altnum) ;
#endif
  return err ;
}

ULONG ASM SDS emul_ClaimInterface(
A1 struct Node *rawifc,
A6 struct Library *AnaiisPrivateBase
)
{
#if TRACE
  char cBuf[256] ;
#endif
  ULONG class, subclass, protocol, d1, d2, d3, claimedi, intnum, altnum ;
  int err ;
  struct Node *device = NULL ;
  ULONG claimedd, confd ;

  AP_GetAttrs(ATYPE_INTERFACE, rawifc,
              USBA_Class, &class,
              USBA_SubClass, &subclass,
              USBA_Protocol, &protocol,
              USBA_Data1, &d1,
              USBA_Data2, &d2,
              USBA_Data3, &d3,
              USBA_Device, &device,
              USBA_Claimed, &claimedi,
              USBA_InterfaceNum, &intnum,
              USBA_AlternateNum, &altnum,
              TAG_DONE) ;

  if (device)
  {
    AP_GetAttrs(ATYPE_DEVICE, device,
                USBA_Claimed, &claimedd,
                USBA_Configured, &confd,
                TAG_DONE) ;
  }

  if (d1 == 0)
  {
    ULONG handle = d3 ;

#if TRACE
    sprintf(cBuf, "CLAIMINTERFACE(%08lx,%ld,%ld) !!!! %08lx (%ld,%ld,%ld) %08lx %08lx %08lx %ld %ld %ld\n",
            d3, intnum, altnum,
            rawifc,
            class,
            subclass,
            protocol,
            d1,
            d2,
            d3,
            claimedi,
            claimedd,
            confd) ;
    MyTrace(cBuf) ;
#endif

    if (handle == NULL)
    {
      handle = USB_open(d2) ;

      if (handle != NULL)
      {
#if LIBUSBX
        //long speed = libusb_get_device_speed(handle) ;
        //AP_SetAttrs(ATYPE_DEVICE, device,
        //            USBA_DeviceSpeed, speed+1,
        //            TAG_DONE) ;
#if TRACE
        //if (1)
        //{
        //  char cBuf[80] ;
        //
        //  sprintf(cBuf, "Set speed %08lx %ld\n", device, speed+1) ;
        //  MyTrace(cBuf) ;
        //}
#endif
#endif
        AP_SetAttrs(ATYPE_INTERFACE, rawifc,
                    USBA_Data3, handle,
                    TAG_DONE) ;
      }
    }

    if (handle != NULL)
    {
      if (claimedi == 0)
      {
        err = USB_claim_interface(handle, intnum) ;
        if (err == 0)
        {
          AP_SetAttrs(ATYPE_INTERFACE, rawifc,
                      USBA_Claimed, 1,
                      TAG_DONE) ;
#if TRACE
#if LIBUSBX
          sprintf(cBuf, "libusb_claim_interface(%08lx,%ld) => %ld\n", handle, intnum, err) ;
#else
          sprintf(cBuf, "usb_claim_interface(%08lx,%ld) => %ld\n", handle, intnum, err) ;
#endif
          MyTrace(cBuf) ;
#endif
        }
      }
      else
      {
#if TRACE
#if LIBUSBX
       sprintf(cBuf, "libusb_claim_interface(%08lx,%ld) => already done !!!!!\n", handle, intnum) ;
#else
       sprintf(cBuf, "usb_claim_interface(%08lx,%ld) => already done !!!!!\n", handle, intnum) ;
#endif
       MyTrace(cBuf) ;
#endif
      }

      err = USB_set_altinterface(handle, intnum, altnum) ;
#if TRACE
#if LIBUSBX
      sprintf(cBuf, "libusb_set_interface_alt_setting(%08lx,%ld,%ld) => %ld\n", handle, intnum, altnum, err) ;
#else
      sprintf(cBuf, "usb_set_altinterface(%08lx,%ld) => %ld\n", handle, altnum, err) ;
#endif
      MyTrace(cBuf) ;
#endif
    }
  }
  else
  {
    AP_SetAttrs(ATYPE_INTERFACE, rawifc,
                USBA_Claimed, 1,
                TAG_DONE) ;
#if TRACE
    sprintf(cBuf, "CLAIMINTERFACE(%08lx,%ld,%ld) FAKE %08lx (%ld,%ld,%ld) %08lx %08lx %08lx %ld %ld %ld\n",
            d3, intnum, altnum,
            rawifc,
            class,
            subclass,
            protocol,
            d1,
            d2,
            d3,
            claimedi,
            claimedd,
            confd) ;
    MyTrace(cBuf) ;
#endif
  }


  return (ULONG)rawifc ;
}

ULONG ASM SDS emul_ReleaseInterface(
A1 struct Node *usifc,
A6 struct Library *AnaiisPrivateBase
)
{
#if TRACE
  char cBuf[256] ;
#endif
  ULONG class, subclass, protocol, d1, d2, d3, intnum, altnum ;

  AP_GetAttrs(ATYPE_INTERFACE, usifc,
              USBA_Class, &class,
              USBA_SubClass, &subclass,
              USBA_Protocol, &protocol,
              USBA_Data1, &d1,
              USBA_Data2, &d2,
              USBA_Data3, &d3,
              USBA_InterfaceNum, &intnum,
              USBA_AlternateNum, &altnum,
              TAG_DONE) ;

  if (d1 == 0)
  {
    ULONG handle = d3 ;

#if TRACE
    sprintf(cBuf, "RELEASEINTERFACE(%08lx,%ld,%ld) !!!! %08lx (%ld,%ld,%ld) %08lx %08lx %08lx\n",
            d3, intnum, altnum,
            usifc,
            class,
            subclass,
            protocol,
            d1,
            d2,
            d3) ;
    MyTrace(cBuf) ;
#endif

    if (handle != NULL)
    {
      USB_release_interface(handle, intnum) ;

      USB_close(handle) ;

      AP_SetAttrs(ATYPE_INTERFACE, usifc,
                  USBA_Data3, 0,
                  TAG_DONE) ;
    }
  }
  else
  {
#if TRACE
    sprintf(cBuf, "RELEASEINTERFACE(%08lx,%ld,%ld) FAKE %08lx (%ld,%ld,%ld) %08lx %08lx %08lx\n",
            d3, intnum, altnum,
            usifc,
            class,
            subclass,
            protocol,
            d1,
            d2,
            d3) ;
    MyTrace(cBuf) ;
#endif
  }

  return (ULONG) usifc ;
}

int countdev(ULONG *devs)
{
  int devnum = 0 ;
#if LIBUSBX
  ULONG *adevs ;

  if (devs != NULL)
  {
    *devs = 0 ;
  }

  adevs = AllocMem(32, MEMF_CHIP) ;
  if (adevs != NULL)
  {
    devnum = libusb_get_device_list(NULL, (LONG)(DLL_GetChipOffset()+(UBYTE *)adevs)) ;
    if (devnum >= 0)
    {
      if (devs != NULL)
      {
        *devs = LE_LONG(*adevs) ;
      }
    }
    else
    {
      devnum = 0 ;
    }
    FreeMem(adevs, 32) ;
  }

#else
  int ret ;
  struct usb_bus    *abus = NULL, *bus = NULL ;
  struct usb_device *adev = NULL, *dev = NULL ;

  abus = AllocMem(sizeof(struct usb_bus), MEMF_CHIP) ;
  adev = AllocMem(sizeof(struct usb_device), MEMF_CHIP) ;

  if ((abus != NULL) && (adev != NULL))
  {
    ret = usb_find_busses() ;
    ret = usb_find_devices() ;
        
    devnum = 0 ;
    bus = (struct usb_bus *)usb_get_busses() ;
    do
    {
      if (bus)
      {
        HostCopyMem((char*)bus,
                    DLL_GetMemoryOffset()+(char*)abus,
                    sizeof(struct usb_bus)) ;

        dev = (struct usb_device *)LE_LONG((ULONG)abus->devices) ;
        do
        {
          devnum++ ;
          HostCopyMem((char*)dev,
                      DLL_GetMemoryOffset()+(char*)adev,
                      sizeof(struct usb_device)) ;
          dev = (struct usb_device*)LE_LONG((ULONG)adev->next) ; 
        } while (dev) ;

        bus = (struct usb_bus*)LE_LONG((ULONG)abus->next) ;
      }
    } while (bus) ;
  }

  if (abus) FreeMem(abus, sizeof(struct usb_bus)) ;
  if (adev) FreeMem(adev, sizeof(struct usb_device)) ;
#endif

  return devnum ;
}

ULONG getdev(
struct HCDBase *base,
int num)
{
  ULONG dev = NULL ;
#if LIBUSBX
  if (num < base->hcd_Unit.libusbx_devscnt)
  {
    if (base->hcd_Unit.datachip2 != NULL)
    {
      HostCopyMem((char *)base->hcd_Unit.libusbx_devs + num * 4,
                  (char *)(DLL_GetChipOffset() + (char *)base->hcd_Unit.datachip2),
                  4) ;

      dev = LE_LONG(*(ULONG *)base->hcd_Unit.datachip2) ;
    }
  }
#else
  BOOL loop = TRUE ;
  int devnum = 0 ;
  int ret ;
  struct usb_bus    *abus = NULL, *bus = NULL ;
  struct usb_device *adev = NULL ;

  abus = AllocMem(sizeof(struct usb_bus), MEMF_CHIP) ;
  adev = AllocMem(sizeof(struct usb_device), MEMF_CHIP) ;

  if ((abus != NULL) && (adev != NULL))
  {
    ret = usb_find_busses() ;
    ret = usb_find_devices() ;
        
    devnum = 0 ;
    bus = (struct usb_bus *)usb_get_busses() ;
    do
    {
      if (bus)
      {
        HostCopyMem((char*)bus,
                    DLL_GetMemoryOffset()+(char*)abus,
                    sizeof(struct usb_bus)) ;

        dev = LE_LONG((ULONG)abus->devices) ;
        do
        {
          if (devnum == num)
          {
            loop = FALSE ;
          }
          else
          {
            devnum ++ ;
            HostCopyMem((char*)dev,
                      DLL_GetMemoryOffset()+(char*)adev,
                      sizeof(struct usb_device)) ;
            dev = LE_LONG((ULONG)adev->next) ;
          }
        } while (dev && loop) ;

        bus = (struct usb_bus*)LE_LONG((ULONG)abus->next) ;
      }
    } while (bus && loop) ;
  }

  if (abus) FreeMem(abus, sizeof(struct usb_bus)) ;
  if (adev) FreeMem(adev, sizeof(struct usb_device)) ;
#endif

  return dev ;
}

int ASM USB_control_msg(
A0 struct USBIOReqHCD *ior,
D0 ULONG hdev,
D1 ULONG hdevhandle,
A6 struct HCDBase *base
)
{
  int error = USBERR_XFERFAIL ;
  struct Library *AnaiisPrivateBase = base->AnaiisPrivateBase ;

  if (hdev != NULL)
  {
    int liberr = -1 ;
    ULONG localhdevhandle = NULL ;
                  
    if (hdevhandle == NULL)
    {
      localhdevhandle = USB_open(hdev) ;
    }
    else
    {
      localhdevhandle = hdevhandle ;
    }

    if (localhdevhandle != NULL)
    {
      struct USBBusSetupData *ubsd = ior->io_SetupData ;
      char *data = NULL ;
      int  len   = 0 ;
      int  epnum = 0 ;
      int  rcmd ;
      int  rtyp ;
      int  rval ;
      int  ridx ;

      if (ior->io_EndPoint != NULL)
      {
        AP_GetAttrs(ATYPE_ENDPOINT, (struct Node *)ior->io_EndPoint,
                    USBA_Address, &epnum,
                    TAG_DONE) ;
      }

      if (ubsd != NULL)
      {
        rtyp = ubsd->sd_RequestType ;    /* UBYTE */
        rcmd = ubsd->sd_Request ;        /* UBYTE */
        rval = LE_WORD(ubsd->sd_Value) ; /* UWORD */
        ridx = LE_WORD(ubsd->sd_Index) ; /* UWORD */

        len = ior->io_Length ;
        if ((ior->io_Data != NULL) && len > 0)
        {
          data = base->hcd_Unit.datachip ;
        
          switch (ior->io_Command)
          {
            case CMD_READ :
            {
              memset(data, 0, ior->io_Length) ;
#if LIBUSBX
              liberr = libusb_control_transfer(localhdevhandle,
                                               rtyp,
                                               rcmd,
                                               rval,
                                               ridx,
                                               (ULONG)(DLL_GetChipOffset()+data),
                                               len+1020,
                                               1000) ;
                                          
#else
              liberr = usb_control_msg(localhdevhandle,
                                       /*epnum |*/ rtyp,
                                       rcmd,
                                       rval,
                                       ridx,
                                       (ULONG)(DLL_GetChipOffset()+data),
                                       len+1020,
                                       1000) ;
#endif
              break ;
            }

            case CMD_WRITE :
            {
              memcpy(data, ior->io_Data, ior->io_Length) ;
#if LIBUSBX
              liberr = libusb_control_transfer(localhdevhandle,
                                               rtyp,
                                               rcmd,
                                               rval,
                                               ridx,
                                               (ULONG)(DLL_GetChipOffset()+data),
                                               len,
                                               1000) ;
#else
              liberr = usb_control_msg((ULONG)localhdevhandle,
                                       /*epnum |*/ rtyp,
                                       rcmd,
                                       rval,
                                       ridx,
                                       (ULONG)(DLL_GetChipOffset()+data),
                                       len,
                                       1000) ;
#endif
              break ;
            }
          }
        }

#if TRACE
        if (1)
        {
          char cbuf[200] ;
#if LIBUSBX
          sprintf(cbuf, "(hdev=%08lx, epnum=%ld) libusb_control_transfer(%08lx, %08lx, %08lx, %08lx, %08lx, %08lx, %08lx, %08lx) => %ld\n",
                        hdev,
                        epnum,
                        localhdevhandle,
                        rtyp,
                        rcmd,
                        rval,
                        ridx,
                        DLL_GetChipOffset()+data,
                        len,
                        1000,
                        liberr) ;
#else
          sprintf(cbuf, "(hdev=%08lx, epnum=%ld) usb_control_msg(%08lx, %08lx, %08lx, %08lx, %08lx, %08lx, %08lx, %08lx) => %ld\n",
                        hdev,
                        epnum,
                        localhdevhandle,
                        rtyp,
                        rcmd,
                        rval,
                        ridx,
                        DLL_GetChipOffset()+data,
                        len,
                        1000,
                        liberr) ;
#endif
          MyTrace(cbuf) ;
        }
#endif

#if LIBUSBX
        if (liberr >= 0)
        {
          error = 0 ;
        }
        else
        {
          // TO DO !!
          error = USBERR_XFERFAIL ;
        }
#else
        if (liberr >= 0)
        {
          error = 0 ;
        }
        else
        {
          switch (liberr)
          {
            case -5 :   error = USBERR_IOERROR  ; break ;
            case -116 : error = USBERR_TIMEOUT  ; break ;
            default :   error = USBERR_XFERFAIL ; break ;
          }
        }
#endif
        if (data != NULL)
        {
          if (error == 0)
          {
            switch (ior->io_Command)
            {
              case CMD_READ :
              {
                memcpy(ior->io_Data, data, ior->io_Length) ;
                ior->io_Actual = ior->io_Length ;
                break ;
              }

              case CMD_WRITE :
              {
                ior->io_Actual = ior->io_Length ;
                break ;
              }
            }
          }
        }                   
      }
    }

    if (hdevhandle == NULL)
    {
      if (localhdevhandle != NULL)
      {
        USB_close(localhdevhandle) ;
        localhdevhandle = NULL ;
      }
    }
  }

  return error ;
}

#endif
/**************/

struct MyDeviceUnit
{
  APTR RootHub ;
} ;

static void ASM SDS HCD_UninitRootHub(
A0 APTR hcunit,
A1 APTR hcfk,
A2 struct TagItem *taglist,
A6 struct HCDBase *base
)
{
  return ;
}

static LONG ASM SDS HCD_InitRootHub(
A0 struct MyDeviceUnit *hcunit,
A1 struct UsbRawInterface *usifc,
A2 APTR *hcfkt,
A3 struct TagItem *taglist,
A6 struct HCDBase *base
)
{
  LONG ret   = FALSE ;

  return ret ;
}

static void ASM SDS HCD_GetAttrs(
A0 struct TagItem *taglist,
A6 struct HCDBase *base
)
{
  struct TagItem *ti ;
  struct TagItem *tstate = taglist ;
 
  /* USBA_HCD_APIVersion */

  if (tstate != NULL)
  {
    do
    {
      ti = UT_NextTagItem(&tstate) ;
      if (ti != NULL)
      {
        switch (ti->ti_Tag)
        {
          case USBA_HCD_APIVersion :
          {
            *(ULONG *)ti->ti_Data = 0xdeadbeef ;
            break ;
          }

          case USBA_SoftVer :
          {
            break ;
          }

          case USBA_Name :
          {
            
#ifdef OKHOSTDLL
#if LIBUSBX
            *(ULONG *)ti->ti_Data = (ULONG)"LibUSBX" ;
#else
            *(ULONG *)ti->ti_Data = (ULONG)"libusb" ;
#endif
#else
            *(ULONG *)ti->ti_Data = (ULONG)((struct Node *)base)->ln_Name ;
#endif
            break ;
          }

          case USBA_Base :
          {
            break ;
          }

          case USBA_State :
          {
            break ;
          }
    
          case USBA_Product :
          {
#ifdef OKPSC2200
            *(ULONG *)ti->ti_Data = 511 ;
#else
#ifdef OKMOUSE
            *(ULONG *)ti->ti_Data = 512 ;
#else
            *(ULONG *)ti->ti_Data = 513 ;
#endif
#endif
#if LIBUSBX
            *(ULONG *)ti->ti_Data = 515 ;
#endif
            break ;
          }
    
          case USBA_Manufacturer :
          {
            *(ULONG *)ti->ti_Data = 0xdeadbeef ;
#if LIBUSBX
            *(ULONG *)ti->ti_Data = 515 ;
#endif
            break ;
          }

          case USBA_Serial :
          {
            *(ULONG *)ti->ti_Data = base->hcd_Unit.serialnumber ;
            break ;
          }
 
          case USBA_HardVer :
          {
            *(ULONG *)ti->ti_Data = base->hcd_Unit.hwnumber ;
            break ;
          }

          case USBA_ResetCnt :
          {
            *(ULONG *)ti->ti_Data = 1 ;
            break ;
          }

          case USBA_BusWidth :
          {
            *(ULONG *)ti->ti_Data = base->buswidth ;
            break ;
          }

          case USBA_Read8Time :
          {
            memcpy((char *)ti->ti_Data, &base->read8, sizeof(struct timeval)) ;
            break ;
          }

          case USBA_Write8Time :
          {
            memcpy((char *)ti->ti_Data, &base->write8, sizeof(struct timeval)) ;
            break ;
          }

          case USBA_Read16Time :
          {
            memcpy((char *)ti->ti_Data, &base->read16, sizeof(struct timeval)) ;
            break ;
          }

          case USBA_Write16Time :
          {
            memcpy((char *)ti->ti_Data, &base->write16, sizeof(struct timeval)) ;
            break ;
          }

          case USBA_Read32Time :
          {
            memcpy((char *)ti->ti_Data, &base->read32, sizeof(struct timeval)) ;
            break ;
          }

          case USBA_Write32Time :
          {
            memcpy((char *)ti->ti_Data, &base->write32, sizeof(struct timeval)) ;
            break ;
          }

          case USBA_CCRead8Time :
          {
            memcpy((char *)ti->ti_Data, &base->ccread8, sizeof(struct timeval)) ;
            break ;
          }

          case USBA_CCWrite8Time :
          {
            memcpy((char *)ti->ti_Data, &base->ccwrite8, sizeof(struct timeval)) ;
            break ;
          }

          case USBA_CCRead16Time :
          {
            memcpy((char *)ti->ti_Data, &base->ccread16, sizeof(struct timeval)) ;
            break ;
          }

          case USBA_CCWrite16Time :
          {
            memcpy((char *)ti->ti_Data, &base->ccwrite16, sizeof(struct timeval)) ;
            break ;
          }

          case USBA_CCReadBlkTime :
          {
            memcpy((char *)ti->ti_Data, &base->ccreadblk, sizeof(struct timeval)) ;
            break ;
          }

          case USBA_CCWriteBlkTime :
          {
            memcpy((char *)ti->ti_Data, &base->ccwriteblk, sizeof(struct timeval)) ;
            break ;
          }
        }
      }
    } while (ti != NULL) ;
  }
}

static void ASM SDS HCD_RemEndPoint(
A0 APTR hcunit,
A1 APTR hcep,
A6 struct HCDBase *base
)
{
}

static APTR ASM SDS HCD_AddEndPoint(
A0 APTR hcunit,
A1 APTR hcfkt,
A2 APTR usep,
D0 LONG epnum,
A3 struct TagItem *taglist,
A6 struct HCDBase *base
)
{
  /* USBA_EndPointDesc */
  /* USBA_InterfaceDesc */
  /* USBA_DeviceDesc */

  return 0 ;
}

static void ASM SDS HCD_RemFunction(
A0 APTR hcunit,
A1 APTR hcfkt,
A6 struct HCDBase *base
)
{
  return ;
}

static APTR ASM SDS HCD_AddFunction(
A0 APTR hcunit,
A1 APTR hchub,
A2 struct UsbRawFunction *usfkt,
A3 struct TagItem *taglist,
A6 struct HCDBase *base
)
{
  return 0 ;
}

static LONG ASM SDS HCD_AbortIO(
A1 struct USBIOReqHCD *req,
A6 struct HCDBase *base
)
{
  LONG result = 0 ;

  if ((req->io_Message.mn_Node.ln_Type != NT_REPLYMSG) &&
      !(req->io_Flags & ~IOF_QUICK))
  {
    result = IOERR_ABORTED ;
    req->io_Error = result ;

    ReplyMsg((struct Message *)req) ;
  }

  return result ;
}

static void ASM SDS HCD_BeginIO(
A1 struct USBIOReqHCD *req,
A6 struct HCDBase *base
)
{
  req->io_Message.mn_Node.ln_Type = NT_MESSAGE ;
  req->io_Error                   = IOERR_SUCCESS ;

  switch (req->io_Command)
  {
    case CMD_STOP  :
    case CMD_RESET :
    case CMD_READ  :
    case CMD_WRITE :
    {
      req->io_Flags &= ~IOF_QUICK ;
      PutMsg(&base->hcd_Unit.du_Unit.unit_MsgPort, (struct Message *)req) ;
      req = NULL ;
      break ;
    }

    case USBCMD_HCDQuery :
    {
      if (req->io_Data != NULL)
      {
        memcpy(req->io_Data, &base->hcd_Unit.audit, req->io_Length) ;
      }
      break ;
    }

    default :
    {
      req->io_Error = IOERR_NOCMD ;
      break ;
    }
  }

  if (req != NULL)
  {
    if (!(req->io_Flags & IOF_QUICK))
    {
      if (req->io_Message.mn_ReplyPort != NULL)
      {
        ReplyMsg((struct Message *)req) ;
      }
    }
  }
}

LONG ASM SDS HCD_Reserved(
A6 struct HCDBase *base
)
{
  return 0 ;
}

static BPTR ASM SDS HCD_Expunge(
A6 struct HCDBase *base
)
{
  BPTR result = 0 ;

#if TRACE
  char cTmp[40] ;

  sprintf(cTmp, "HCD_Expunge %ld\n", base->hcd_Library.lib_OpenCnt) ;
  MyTrace(cTmp) ;
#endif

  if (base->hcd_Library.lib_OpenCnt == 0)
  {
    result = base->hcd_SegList ;

    Remove((struct Node *)base);


    FreeMem((BYTE *)base - base->hcd_Library.lib_NegSize,
            base->hcd_Library.lib_NegSize + base->hcd_Library.lib_PosSize);
  }
  else
  {
    base->hcd_Library.lib_Flags |= LIBF_DELEXP ;
  }

  return result ;
}

static APTR ASM SDS HCD_Close(
A1 struct IORequest *ior,
A6 struct HCDBase *base
)
{
  APTR result = NULL ;

#if TRACE
  char cTmp[80] ;

  sprintf(cTmp, "HCD_Close cnt=%ld\n", base->hcd_Library.lib_OpenCnt) ;
  MyTrace(cTmp) ;
#endif

  if (ior->io_Unit != NULL)
  {
    ior->io_Unit->unit_OpenCnt-- ;

    if ((ior->io_Unit->unit_OpenCnt == 0) &&
        (base->hcd_Unit.du_Task     != NULL))
    {
      SendCmd(base, &base->hcd_Unit, CMD_CloseUnit) ;

      while (base->hcd_Unit.du_Task != NULL)
      {
        // Pas bien
        //
      }

      FreeSignal(base->hcd_Unit.du_Unit.unit_MsgPort.mp_SigBit) ;
     
    }
  }

  base->hcd_Library.lib_OpenCnt-- ;

  if (base->hcd_Library.lib_OpenCnt == 0)
  {
    ior->io_Device = NULL ;
    ior->io_Unit   = NULL ;

#ifdef OKHOSTDLL
#if LIBUSBX
    libusb_exit(NULL) ;
#else
#endif

    DLLFree(base->dllhandle) ;

#if LIBUSBX
    if (base->hcd_Unit.datachip2 != NULL)
    {
      FreeMem(base->hcd_Unit.datachip2, 32) ;
      base->hcd_Unit.datachip2 = NULL ;
    }
#endif

    if (base->hcd_Unit.datachip != NULL)
    {
      FreeMem(base->hcd_Unit.datachip, 2048) ;
      base->hcd_Unit.datachip = NULL ;
    }
#endif
#if HCDDEMOPROCESS
    if (base->DOSBase != NULL)
    {
      CloseLibrary(base->DOSBase) ;
      base->DOSBase = NULL ;
    }
#endif

    if (base->AnaiisPrivateBase != NULL)
    {
      CloseLibrary(base->AnaiisPrivateBase) ;
      base->AnaiisPrivateBase = NULL ;
    }

    if (base->hcd_Library.lib_Flags & LIBF_DELEXP)
    {
      result = (APTR)HCD_Expunge(base) ;
    }
  }

  return result ;
}

static LONG ASM SDS HCD_Open(
D0 ULONG unitnumber,
D1 ULONG flags,
A1 struct IORequest *ior,
A6 struct HCDBase *base
)
{
  LONG result = -1 ;
#if HCDDEMOPROCESS
  struct Library *DOSBase = NULL ;
  struct SegList *segptr ;
  struct MsgPort *process ;
#endif
#if TRACE
  char cTmp[80] ;

  sprintf(cTmp, "HCD_Open %ld\n", base->hcd_Library.lib_OpenCnt) ;
  MyTrace(cTmp) ;
#endif

#ifdef OKPSC2200
#else
  //unitnumber = -1 ;
#endif

  if (0 == unitnumber)
  {
    base->hcd_Library.lib_OpenCnt++ ;

    if (0 == base->hcd_Unit.du_Unit.unit_OpenCnt)
    {
      result = 0 ;
      base->hcd_Unit.serialnumber = 1234567890 ;
      base->hcd_Unit.hwnumber     = 119 ;  
    
#ifdef OKHOSTDLL
      if (base->dllhandle != NULL)
      {
#if LIBUSBX
        libusb_init(NULL) ;
#else
        usb_init() ;
#endif

#if TRACE
        /* ca fait ramer !!! */
        SetDebug(3) ;
#endif

        /* To avoid to many allocations during the work */
#if LIBUSBX
        base->hcd_Unit.datachip2 = AllocMem(32, MEMF_CHIP|MEMF_CLEAR) ;
#endif
        base->hcd_Unit.datachip = AllocMem(2048, MEMF_CHIP|MEMF_CLEAR) ;

        if (base->hcd_Unit.datachip != NULL)
        {
          ULONG *v, *pv ;
#if LIBUSBX
          v = libusb_get_version() ;
          if (v != NULL)
          {

          }
#else
          v = (ULONG *)usb_get_version() ;
          if (v != NULL)
          {
            HostCopyMem((char *)v,
                        DLL_GetChipOffset() + (char *)base->hcd_Unit.datachip,
                        8*4) ;

            pv = (ULONG *)base->hcd_Unit.datachip ;
            base->hcd_Unit.serialnumber = LE_LONG(pv[0])*1000000 + LE_LONG(pv[1])*10000 + LE_LONG(pv[2])*100 + LE_LONG(pv[3]) ;
            base->hcd_Unit.hwnumber     = LE_LONG(pv[4])*1000000 + LE_LONG(pv[5])*10000 + LE_LONG(pv[6])*100 + LE_LONG(pv[7]) ;  
          }
#endif
          result = 0 ;
        }
      }
      else
      {
        result = -3 ;
      }
#endif

      if (result == 0)
      {
        base->AnaiisPrivateBase = OpenLibrary("anaiisprivate.library", 0) ;
#if HCDDEMOPROCESS
        base->DOSBase = OpenLibrary("dos.library", 0) ;
        DOSBase = base->DOSBase ;
#endif
        base->hcd_Unit.du_Unit.unit_OpenCnt ++ ;
        base->hcd_Unit.du_Task = NULL ;

        sprintf(base->hcd_Unit.du_NameL0, "subtask%d_level0", unitnumber) ;
        sprintf(base->hcd_Unit.du_NameL1, "subtask%d_level1", unitnumber) ;

        base->hcd_Unit.du_Unit.unit_MsgPort.mp_Node.ln_Type = NT_MSGPORT ;
        base->hcd_Unit.du_Unit.unit_MsgPort.mp_Flags = PA_SIGNAL ;
        base->hcd_Unit.du_Unit.unit_MsgPort.mp_SigBit = AllocSignal(-1) ;
        NewList(&base->hcd_Unit.du_Unit.unit_MsgPort.mp_MsgList) ;
        base->hcd_Unit.du_Unit.unit_flags = 0 ;
        base->hcd_Unit.du_Unit.unit_pad   = 0 ;

#if HCDDEMOPROCESS
        segptr = (struct SegList *)((UBYTE *)base->segdata + 4) ;
        segptr = (struct SegList *)MKBADDR(segptr) ;
        segptr = (struct SegList *)BADDR(segptr) ;
        segptr->length   = 16 ;
        segptr->next     = 0 ;
        segptr->jumpcode = 0x4ef9 ;
        segptr->entry    = (APTR) procmainloop ;
      
        process = CreateProc(base->hcd_Unit.du_NameL1, 0, MKBADDR(segptr), 8000) ;
        if (process == NULL)
        {
          base->hcd_Unit.du_Task = NULL ;
        }
        else
        {
          base->hcd_Unit.du_Task = (struct Task *)(((UBYTE *)process) - sizeof(struct Task)) ;
        }
#if TRACE
        sprintf(cTmp, "Process level 1 launched 0x%08lx\n", base->hcd_Unit.du_Task) ;
        MyTrace(cTmp) ;
#endif
#else
        base->hcd_Unit.du_Task = CreateTask(base->hcd_Unit.du_NameL1,
                                            0,
                                            procmainloop,
                                            8000) ;
#if TRACE
        sprintf(cTmp, "Task level 1 launched 0x%08lx\n", base->hcd_Unit.du_Task) ;
        MyTrace(cTmp) ;
#endif
#endif

        base->hcd_Unit.du_uhc124Task = CreateTask(base->hcd_Unit.du_NameL0,
                                                  0,
                                                  procuhc124loop,
                                                  4096) ;
#if TRACE
        sprintf(cTmp, "Task level 0 launched 0x%08lx\n", base->hcd_Unit.du_uhc124Task) ;
        MyTrace(cTmp) ;
#endif
        if (base->hcd_Unit.du_uhc124Task != NULL)
        {
          base->hcd_Unit.du_uhc124Task->tc_UserData = base ;

          Signal(base->hcd_Unit.du_uhc124Task, SIGF_SINGLE) ;
        }

        base->hw = NULL ;

        if (base->hcd_Unit.du_Task != NULL)
        {
          base->hcd_Unit.du_Unit.unit_MsgPort.mp_SigTask = base->hcd_Unit.du_Task ;
          base->hcd_Unit.du_Task->tc_UserData = base ;

          Signal(base->hcd_Unit.du_Task, SIGF_SINGLE) ;

          SendCmd(base, &base->hcd_Unit, CMD_OpenUnit) ;
        }

        ior->io_Unit = (struct Unit *)&base->hcd_Unit ;
        ior->io_Message.mn_Node.ln_Type = NT_REPLYMSG ;

        base->hcd_Library.lib_Flags &= ~LIBF_DELEXP ;
        result = 0 ;
      }
    }
    else
    {
      // in use
      base->hcd_Unit.du_Unit.unit_OpenCnt ++ ;

      ior->io_Unit = (struct Unit *)&base->hcd_Unit ;

      result = 0 ;
    }
  }

  if (0 != result)
  {
    ior->io_Device = NULL ;
    ior->io_Unit   = NULL ;
  }

  ior->io_Error = result ;

  return result ;
}

#ifdef OKHOSTDLL
APTR uae_rombase  = (APTR) 0x00f00000 ;
APTR dll_calltrap = (APTR) 0x00f0ffc0 ;
#endif

/* Initialize device driver. */
static struct HCDBase * ASM SDS DevInit(
A0 BPTR seglist,
D0 struct HCDBase *base,
A6 struct Library *ExecBase
)
{
  struct HCDBase *result = NULL;

#if TRACE
  MyTrace("HCD_DevInit\n") ;
#endif

  base->hcd_SysBase = ExecBase ;
  base->hcd_SegList = seglist;
  base->hcd_Library.lib_Version  = VERSION ;
  base->hcd_Library.lib_Revision = REVISION;

  base->hcd_Library.lib_Node.ln_Type = NT_DEVICE ;
  base->hcd_Library.lib_Node.ln_Name = DevName ;
  base->hcd_Library.lib_Flags = LIBF_SUMUSED|LIBF_CHANGED ;
  base->hcd_Library.lib_IdString = DevID ;
  
  base->hcd_Counter = 0;

  memset(&base->hcd_Unit, 0, sizeof(base->hcd_Unit)) ;
  base->hcd_Unit.du_Task = NULL ;

  result = base ;
#ifdef OKHOSTDLL
  if (1)
  {
    long version = 0 ;
    long __stdargs (*calltrap)(long) = (long (*)(long))0x00f0ff60 ;
    APTR oldtrap ;
    struct Task *me ;
    UWORD myuglytrap[] = {0x588f, 0x4e73} ;
    struct uaebase
    {
      struct Library uae_lib ;
      UWORD uae_version ;
      UWORD uae_revision ;
      UWORD uae_subrevision ;
      UWORD zero ;
      APTR uae_rombase ;
    } ;
    struct uaebase *uaebase ;
    struct ExecBase *SysBase = *(struct ExecBase **) 4 ;

    uaebase = (struct uaebase *)FindName(&SysBase->ResourceList, "uae.resource") ;
    if (uaebase != NULL)
    {
      uae_rombase  = uaebase->uae_rombase ;
      dll_calltrap = (APTR)((ULONG)uaebase->uae_rombase + 0xffc0) ;
      calltrap = (long (*)(...))((ULONG)uaebase->uae_rombase + 0xff60) ;
    }
    else
    {
      me = FindTask(NULL) ;
      oldtrap = me->tc_TrapCode ;
      me->tc_TrapCode = myuglytrap ;

      if ((*(ULONG *)calltrap & 0xf000ffff) != 0xa0004e75)
      {
        calltrap = NULL ;
      }
      me->tc_TrapCode = oldtrap ;
    }

    if (calltrap != NULL)
    {
      version = calltrap(0) ;
    }
    else
    {
      result = NULL ;
    }
  
    if (result != NULL)
    {
      if (((version >> 24) & 0xff) > 0)
      {
        base->dllhandle = DLLInit() ;
        if (base->dllhandle != NULL)
        {
          /* done by open later */
        }
        else
        {
          result = NULL ;
        }
      }
      else
      {
        /* Too old WinUAE version */
        result = NULL ;
      }
    }

    if (result == NULL)
    {
      struct Library *IntuitionBase = OldOpenLibrary("intuition.library") ;
      UBYTE *c, tmp[200] ;

      if (IntuitionBase != NULL)
      {
        c = tmp ;
        *c++ = 0 ;
        *c++ = 20 ;
        *c++ = 20 ;
        if (version == 0)
        {
          c += sprintf(c, "Sorry, I need WinUAE (emulib) and hostusb.dll to work") ;
        }
        else
        {
          c += sprintf(c, "Sorry, got WinUAE %ld.%ld.%ld, but hostusb.dll is missing",
                       version >> 24 & 0xff,
                       version >> 16 & 0xff,
                       version     & 0xffff) ;
        } 
        *c++ = 0 ;
        *c++ = 0 ;

        if (DisplayAlert(0xdeadbeef, tmp, 50))
        {
        }

        CloseLibrary(IntuitionBase) ;
      }
    }
  }
#endif

  

  if (result == NULL)
  {
    FreeMem((BYTE *)base - base->hcd_Library.lib_NegSize,
             base->hcd_Library.lib_NegSize + base->hcd_Library.lib_PosSize);
  }

  return result ;
}

static APTR DevFunctionVector[]=
{
  /* -006   -6 */ HCD_Open,
  /* -00c  -12 */ HCD_Close,
  /* -012  -18 */ HCD_Expunge,
  /* -018  -24 */ HCD_Reserved,
  /* -01e  -30 */ HCD_BeginIO,
  /* -024  -36 */ HCD_AbortIO,
  /* -02A  -42 */ HCD_AddFunction,   /* NOT USED */
  /* -030  -48 */ HCD_RemFunction,   /* NOT USED */
  /* -036  -54 */ HCD_AddEndPoint,   /* NOT USED */
  /* -03C  -60 */ HCD_RemEndPoint,   /* NOT USED */
  /* -042  -66 */ HCD_GetAttrs,  
  /* -048  -72 */ HCD_InitRootHub,   /* NOT USED */
  /* -04E  -78 */ HCD_UninitRootHub, /* NOT USED */
  (APTR)-1
} ;

struct DevInitData
{
  ULONG did_LibraryBaseSize ;
  APTR  did_FunctionVector ;
  APTR  did_InitTable ;
  APTR  did_InitRoutine ;
} ;

struct DevInitData DevInitData =
{
  sizeof(struct HCDBase),
  DevFunctionVector,
  NULL,
  DevInit
} ;


struct uhc124Message
{
  struct Message Message ;
  int   Command ;
  int   Status ;
  int   Error ;
  UWORD Control ;
  UWORD DevAddr ;
  UWORD EPAddr ;

  UBYTE *Data ;
  UWORD Length ;

} ;

void Senduhc124Cmd(struct MsgPort *uport, struct uhc124Message *msg)
{
  struct MsgPort   port ;

  memset(&port, 0, sizeof(port)) ;
  port.mp_Node.ln_Type = NT_MSGPORT ;
  port.mp_Flags   = PA_SIGNAL ;
  port.mp_SigBit  = SIGB_SINGLE ;
  port.mp_SigTask = FindTask(NULL) ;
  NewList(&port.mp_MsgList) ;

  msg->Message.mn_ReplyPort = &port ;
  msg->Message.mn_Length    = sizeof(struct uhc124Message) ;

  SetSignal(0, SIGF_SINGLE) ;

  PutMsg(uport, (struct Message *)msg) ;
  WaitPort(&port) ;
}

static UBYTE vers[]       ={"$VER:" DEV_VSTRING "" } ;
static UBYTE AckTxt[]     ={"<ACK>"} ;
static UBYTE NackTxt[]    ={"<NACK>"} ;
static UBYTE TimeOutTxt[] ={"<TIMEOUT>"} ;
static UBYTE ErrorTxt[]   ={"<ERROR>"} ;
static UBYTE OverflowTxt[]={"<OVERFLOW>"} ;
static UBYTE StallTxt[]   ={"<STALL>"} ;
static UBYTE LFTxt[]      ={"\n"} ;

/**/
/* hub */
static UBYTE hub_dd[] = {
0x12,       /* bLength */
0x01,       /* bDescriptorType */
0x10, 0x01, /* bcdUSB */
0x09,       /* bDeviceClass */
0x00,       /* bDeviceSubClass */
0x00,       /* bDeviceProtocol */
0x08,       /* bMaxPacketSize0 */
0xeb, 0x03, /* idVendor */
0x12, 0x33, /* idProduct */
0x00, 0x03, /* bcdDevice */
0x01,       /* iManufacturer */
0x02,       /* iProduct */
0x03,       /* iSerialNumber */
0x01,       /* bNumConfigurations */
} ;

static UBYTE hub_id[] = {
0x09,       /* bLength */
0x02,       /* bDescriptorType CONFIGURATION */
0x19, 0x00, /* wTotalLength */
0x01,       /* bNumInterfaces */
0x01,       /* bConfigurationValue */
0x00,       /* iConfiguration */
0xe0,       /* bmAttributes */
0x20,       /* bMaxPower */
0x09,       /* bLength */
0x04,       /* bDescriptorType INTERFACE */
0x00,       /* bInterfaceNumber */
0x00,       /* bAlternateSetting */
0x01,       /* bNumEndpoints */
0x09,       /* bInterfaceClass */
0x00,       /* bInterfaceSubClass */
0x00,       /* bInterfaceProtocol */
0x00,       /* iInterface */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x81,       /* bEndpointAddress */
0x03,       /* bmAttributes INTERRUPT */
0x01, 0x00, /* wMaxPacketSize */
0xff,       /* bInterval */
} ;

/**/
static UBYTE hub_hd[] = {
0x09,       /* bLength */
0x29,       /* bDescriptor HUB */
0x04,       /* hd_NumPorts */
0x09, 0x00, /* hd_Characteristics */
0x32,       /* hd_PwrOnToPwrGood */
0x40,       /* hd_HubCtrlCurrent */
0x00,
0x1e
} ;

#ifdef OKMOUSE
/* mouse */
static UBYTE ms_dd[] = {
0x12,       /* bLength */
0x01,       /* bDescriptorType */
0x10, 0x01, /* bcdUSB */
0x00,       /* bDeviceClass */
0x00,       /* bDeviceSubClass */
0x00,       /* bDeviceProtocol */
0x08,       /* bMaxPacketSize0 */
0x4f, 0x04, /*0x6d, 0x04,*/ /* idVendor */
0x01, 0xc0, /* idProduct */
0x10, 0x40, /* bcdDevice */
0x01,       /* iManufacturer */
0x02,       /* iProduct */
0x03,       /* iSerialNumber */
0x01,       /* bNumConfigurations */
} ;

static UBYTE ms_id[] = {
0x09,       /* bLength */
0x02,       /* bDescriptorType CONFIGURATION */
0x22, 0x00, /* wTotalLength */
0x01,       /* bNumInterfaces */
0x01,       /* bConfigurationValue */
0x05,       /* iConfiguration */
0xa0,       /* bmAttributes */
0x19,       /* bMaxPower */
0x09,       /* bLength */
0x04,       /* bDescriptorType INTERFACE */
0x00,       /* bInterfaceNumber */
0x00,       /* bAlternateSetting */
0x01,       /* bNumEndpoints */
0x03,       /* bInterfaceClass */
0x01,       /* bInterfaceSubClass */
0x02,       /* bInterfaceProtocol */
0x04,       /* iInterface */
0x09,       /* bLength */
0x21,       /* bDescriptorType HID DESCRIPTOR */
0x10, 0x01, /* bcdHID */
0x00,       /* bCountryCode */
0x01,       /* bNumDescriptorType */
0x22,       /* bXDescriptorType */
0x44,       /* bXDescriptorLengthL */
0x00,       /* bXDescriptorLengthH */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x81,       /* bEndpointAddress */
0x03,       /* bmAttributes INTERRUPT */
0x04, 0x00, /* wMaxPacketSize */
0x0a,       /* bInterval */
} ;

static UBYTE ms_hid[] = {
0x44,       /* bLength */
0x22,       /* bDescriptorType REPORT */
0x05,0x01,0x09,0x02, 0xa1,0x01,0x09,0x01, 0xa1,0x00,0x05,0x09, 0x19,0x01,0x29,0x03,
0x15,0x00,0x25,0x01, 0x95,0x03,0x75,0x01, 0x81,0x02,0x95,0x01, 0x75,0x05,0x81,0x01,
0x05,0x01,0x09,0x30, 0x09,0x31,0x09,0x38, 0x15,0x81,0x25,0x7f, 0x75,0x08,0x95,0x03,
0x81,0x06,0xc0,0x09, 0x3c,0x15,0x00,0x25, 0x01,0x75,0x01,0x95, 0x01,0xb1,0x22,0x95,
0x07,0xb1,0x01,0xc0
} ;
#endif

#ifdef OKPRINTER
/* printer */
static UBYTE pr_dd[] = {
0x12,       /* bLength */
0x01,       /* bDescriptorType */
0x10, 0x01, /* bcdUSB */
0x00,       /* bDeviceClass */
0x00,       /* bDeviceSubClass */
0x00,       /* bDeviceProtocol */
0x08,       /* bMaxPacketSize0 */
0x7b, 0x06, /* idVendor */
0x05, 0x23, /* idProduct */
0x02, 0x02, /* bcdDevice */
0x01,       /* iManufacturer */
0x02,       /* iProduct */
0x00,       /* iSerialNumber */
0x01,       /* bNumConfigurations */
} ;

static UBYTE pr_id[] = {
0x09,       /* bLength */
0x02,       /* bDescriptorType CONFIGURATION */
0x4e, 0x00, /* wTotalLength */
0x01,       /* bNumInterfaces */
0x01,       /* bConfigurationValue */
0x00,       /* iConfiguration */
0xa0,       /* bmAttributes */
0x32,       /* bMaxPower */
0x09,       /* bLength */
0x04,       /* bDescriptorType INTERFACE */
0x00,       /* bInterfaceNumber */
0x00,       /* bAlternateSetting */
0x01,       /* bNumEndpoints */
0x07,       /* bInterfaceClass */
0x01,       /* bInterfaceSubClass */
0x01,       /* bInterfaceProtocol */
0x00,       /* iInterface */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x01,       /* bEndpointAddress */
0x02,       /* bmAttributes BULK */
0x40, 0x00, /* wMaxPacketSize */
0x00,       /* bInterval */
0x09,       /* bLength */
0x04,       /* bDescriptorType INTERFACE */
0x00,       /* bInterfaceNumber */
0x01,       /* bAlternateSetting */
0x02,       /* bNumEndpoints */
0x07,       /* bInterfaceClass */
0x01,       /* bInterfaceSubClass */
0x02,       /* bInterfaceProtocol */
0x00,       /* iInterface */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x01,       /* bEndpointAddress */
0x02,       /* bmAttributes BULK */
0x40, 0x00, /* wMaxPacketSize */
0x00,       /* bInterval */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x82,       /* bEndpointAddress */
0x02,       /* bmAttributes BULK */
0x40, 0x00, /* wMaxPacketSize */
0x00,       /* bInterval */
0x09,       /* bLength */
0x04,       /* bDescriptorType INTERFACE */
0x00,       /* bInterfaceNumber */
0x02,       /* bAlternateSetting */
0x03,       /* bNumEndpoints */
0xff,       /* bInterfaceClass */
0x00,       /* bInterfaceSubClass */
0xff,       /* bInterfaceProtocol */
0x00,       /* iInterface */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x01,       /* bEndpointAddress */
0x02,       /* bmAttributes BULK */
0x40, 0x00, /* wMaxPacketSize */
0x00,       /* bInterval */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x82,       /* bEndpointAddress */
0x02,       /* bmAttributes BULK */
0x40, 0x00, /* wMaxPacketSize */
0x00,       /* bInterval */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x83,       /* bEndpointAddress */
0x03,       /* bmAttributes BULK */
0x04, 0x00, /* wMaxPacketSize */
0x01,       /* bInterval */
} ;
#endif

#ifdef OKPSC2200
/* PSC 2200 Series */
static UBYTE pr6_dd[] = {
0x12,       /* bLength */
0x01,       /* bDescriptorType */
0x00, 0x02, /* bcdUSB */
0x00,       /* bDeviceClass */
0x00,       /* bDeviceSubClass */
0x00,       /* bDeviceProtocol */
0x08,       /* bMaxPacketSize0 */
0xf0, 0x03, /* idVendor */
0x11, 0x29, /* idProduct */
0x00, 0x01, /* bcdDevice */
0x01,       /* iManufacturer */
0x02,       /* iProduct */
0x03,       /* iSerialNumber */
0x01,       /* bNumConfigurations */
} ;

static UBYTE pr6_id[] = {
0x09,       /* bLength */
0x02,       /* bDescriptorType CONFIGURATION */
0x7a, 0x00, /* wTotalLength */
0x04,       /* bNumInterfaces */
0x01,       /* bConfigurationValue */
0x00,       /* iConfiguration */
0xc0,       /* bmAttributes */
0x01,       /* bMaxPower */
0x09,       /* bLength */
0x04,       /* bDescriptorType INTERFACE */
0x00,       /* bInterfaceNumber */
0x00,       /* bAlternateSetting */
0x03,       /* bNumEndpoints */
0xff,       /* bInterfaceClass */
0xcc,       /* bInterfaceSubClass */
0x00,       /* bInterfaceProtocol */
0x00,       /* iInterface */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x01,       /* bEndpointAddress */
0x02,       /* bmAttributes BULK */
0x40, 0x00, /* wMaxPacketSize */
0x00,       /* bInterval */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x81,       /* bEndpointAddress */
0x02,       /* bmAttributes BULK */
0x40, 0x00, /* wMaxPacketSize */
0x00,       /* bInterval */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x82,       /* bEndpointAddress */
0x03,       /* bmAttributes INT */
0x08, 0x00, /* wMaxPacketSize */
0x0a,       /* bInterval */
0x09,       /* bLength */
0x04,       /* bDescriptorType INTERFACE */
0x01,       /* bInterfaceNumber */
0x00,       /* bAlternateSetting */
0x03,       /* bNumEndpoints */
0x07,       /* bInterfaceClass */
0x01,       /* bInterfaceSubClass */
0x02,       /* bInterfaceProtocol */
0x00,       /* iInterface */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x03,       /* bEndpointAddress */
0x02,       /* bmAttributes BULK */
0x40, 0x00, /* wMaxPacketSize */
0x00,       /* bInterval */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x83,       /* bEndpointAddress */
0x02,       /* bmAttributes BULK */
0x40, 0x00, /* wMaxPacketSize */
0x00,       /* bInterval */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x84,       /* bEndpointAddress */
0x03,       /* bmAttributes INT */
0x08, 0x00, /* wMaxPacketSize */
0x0a,       /* bInterval */
0x09,       /* bLength */
0x04,       /* bDescriptorType INTERFACE */
0x02,       /* bInterfaceNumber */
0x00,       /* bAlternateSetting */
0x03,       /* bNumEndpoints */
0xff,       /* bInterfaceClass */
0xff,       /* bInterfaceSubClass */
0xff,       /* bInterfaceProtocol */
0x00,       /* iInterface */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x05,       /* bEndpointAddress */
0x02,       /* bmAttributes BULK */
0x40, 0x00, /* wMaxPacketSize */
0x00,       /* bInterval */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x85,       /* bEndpointAddress */
0x02,       /* bmAttributes BULK */
0x40, 0x00, /* wMaxPacketSize */
0x00,       /* bInterval */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x86,       /* bEndpointAddress */
0x03,       /* bmAttributes INT */
0x04, 0x00, /* wMaxPacketSize */
0x0a,       /* bInterval */
0x09,       /* bLength */
0x04,       /* bDescriptorType INTERFACE */
0x03,       /* bInterfaceNumber */
0x00,       /* bAlternateSetting */
0x02,       /* bNumEndpoints */
0x08,       /* bInterfaceClass */
0x06,       /* bInterfaceSubClass */
0x50,       /* bInterfaceProtocol */
0x00,       /* iInterface */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x07,       /* bEndpointAddress */
0x02,       /* bmAttributes BULK */
0x40, 0x00, /* wMaxPacketSize */
0x00,       /* bInterval */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x87,       /* bEndpointAddress */
0x02,       /* bmAttributes BULK */
0x40, 0x00, /* wMaxPacketSize */
0x00,       /* bInterval */
} ;
#endif

#if OKMASS
static UBYTE mass_dd[] = {
0x12,       /* bLength */
0x01,       /* bDescriptorType */
0x10, 0x01, /* bcdUSB */
0x00,       /* bDeviceClass */
0x00,       /* bDeviceSubClass */
0x00,       /* bDeviceProtocol */
0x40,       /* bMaxPacketSize0 */
0xad, 0xde, /* idVendor */
0xef, 0xbe, /* idProduct */
0x02, 0x02, /* bcdDevice */
0x01,       /* iManufacturer */
0x02,       /* iProduct */
0x03,       /* iSerialNumber */
0x01,       /* bNumConfigurations */
} ;

static UBYTE mass_id[] = {
0x09,       /* bLength */
0x02,       /* bDescriptorType CONFIGURATION */
0x20, 0x00, /* wTotalLength */
0x01,       /* bNumInterfaces */
0x01,       /* bConfigurationValue */
0x00,       /* iConfiguration */
0xc0,       /* bmAttributes */
0xfc,       /* bMaxPower */
0x09,       /* bLength */
0x04,       /* bDescriptorType INTERFACE */
0x00,       /* bInterfaceNumber */
0x00,       /* bAlternateSetting */
0x02,       /* bNumEndpoints */
0x08,       /* bInterfaceClass */
0x06,       /* bInterfaceSubClass */
0x50,       /* bInterfaceProtocol */
0x00,       /* iInterface */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x07,       /* bEndpointAddress */
0x02,       /* bmAttributes BULK */
0x40, 0x00, /* wMaxPacketSize */
0x00,       /* bInterval */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x87,       /* bEndpointAddress */
0x02,       /* bmAttributes BULK */
0x40, 0x00, /* wMaxPacketSize */
0x00,       /* bInterval */
} ;
#endif

#if OKPTP
/* PTP */
static UBYTE ptp_dd[] = {
0x12,       /* bLength */
0x01,       /* bDescriptorType */
0x10, 0x01, /* bcdUSB */
0x06,       /* bDeviceClass */
0x01,       /* bDeviceSubClass */
0x01,       /* bDeviceProtocol */
0x40,       /* bMaxPacketSize0 */
0xad, 0xde, /* idVendor */
0xef, 0xbe, /* idProduct */
0x02, 0x02, /* bcdDevice */
0x01,       /* iManufacturer */
0x02,       /* iProduct */
0x03,       /* iSerialNumber */
0x01,       /* bNumConfigurations */
} ;

static UBYTE ptp_id[] = {
0x09,       /* bLength */
0x02,       /* bDescriptorType CONFIGURATION */
0x27, 0x00, /* wTotalLength */
0x01,       /* bNumInterfaces */
0x01,       /* bConfigurationValue */
0x00,       /* iConfiguration */
0xa0,       /* bmAttributes */
0x32,       /* bMaxPower */
0x09,       /* bLength */
0x04,       /* bDescriptorType INTERFACE */
0x00,       /* bInterfaceNumber */
0x02,       /* bAlternateSetting */
0x03,       /* bNumEndpoints */
0x06,       /* bInterfaceClass */
0x01,       /* bInterfaceSubClass */
0x01,       /* bInterfaceProtocol */
0x00,       /* iInterface */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x01,       /* bEndpointAddress */
0x02,       /* bmAttributes BULK */
0x40, 0x00, /* wMaxPacketSize */
0x00,       /* bInterval */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x82,       /* bEndpointAddress */
0x02,       /* bmAttributes BULK */
0x40, 0x00, /* wMaxPacketSize */
0x00,       /* bInterval */
0x07,       /* bLength */
0x05,       /* bDescriptorType ENDPOINT */
0x83,       /* bEndpointAddress */
0x03,       /* bmAttributes INT */
0x40, 0x00, /* wMaxPacketSize */
0x40,       /* bInterval */
} ;
#endif

#define MYLIBUSB        0
#define MYHUBADDR       1
#define MYMOUSEADDR     2
#define MYPRINTER1ADDR  3
#define MYPRINTER2ADDR  4
#define MYMASSADDR      5
#define MYPRINTER6ADDR  7
#define MYPTPADDR       8

void ASM SDS MakeString(
A0 struct USBIOReq *ior,
A1 UBYTE *cstr,
A6 struct HCDBase *base
)
{
  struct Library *AnaiisPrivateBase = base->AnaiisPrivateBase ;

  if ((ior->io_Data != NULL) && (ior->io_Length > 0))
  {
    struct USBBusDscHead *cTmp = NULL ;

    cTmp = (struct USBBusDscHead *)AP_AllocVec(strlen(cstr)*2 + 2, MEMF_CLEAR) ;
    if (cTmp != NULL)
    {
      AP_CStr(cTmp, cstr) ;
      memcpy(ior->io_Data, cTmp, ior->io_Length) ;
      ior->io_Actual = ior->io_Length ;
      ior->io_Error = 0 ;
      AP_FreeVec(cTmp) ;
    }
  }
}

BOOL ASM SDS copydata(
A0 struct USBIOReqHCD *ior,
A1 char *data,
D0 long eplen
)
{
  BOOL ret = TRUE ;
  long eplentodo ;

  if (ior->io_Data != NULL)
  {
    if (ior->io_Length < eplen)
    {
      memcpy(&((UBYTE *)ior->io_Data)[ior->io_Actual],
             &data[ior->io_Actual],
             ior->io_Length) ;
      ior->io_Actual += ior->io_Length ;
    }
    else
    {
      eplentodo = eplen ;
      if ( ior->io_Actual + eplen > ior->io_Length )
      {
        eplentodo = ior->io_Length - ior->io_Actual ;
      }

      memcpy(&((UBYTE *)ior->io_Data)[ior->io_Actual],
             &data[ior->io_Actual], eplentodo) ;
      ior->io_Actual += eplentodo ;
    }

    if (ior->io_Actual < ior->io_Length)
    {
      ret = FALSE ;                        
    }
  }

  return ret ;
}

LONG ASM SDS emulMass(
A0 struct USBIOReqHCD *ior,
A6 struct HCDBase *base
)
{
#if HCDDEMOPROCESS
  struct Library *DOSBase           = base->DOSBase ;
#endif
  struct Library *AnaiisPrivateBase = base->AnaiisPrivateBase ;

  switch (base->hcd_Unit.mass_state)
  {
    case 0 :
    {
      if (ior->io_Command == CMD_WRITE)
      {
        memcpy(base->hcd_Unit.mass_scsi, ior->io_Data, ior->io_Length) ;
        ior->io_Actual = ior->io_Length ;
        ior->io_Error  = 0 ;

        switch (base->hcd_Unit.mass_scsi[15])
        {
          case 0x00 : /* Test Unit Ready */
          case 0x1b : /* Spin up ? */
          {
            /* no data phase */
            base->hcd_Unit.mass_state = 2 ;
            break ;
          }

          default :
          {
            base->hcd_Unit.mass_state = 1 ;
            break ;
          }
        }
      }
#if SIMULTIME
      AP_USBDelay(10) ;
#endif
      break ;
    }

    case 1 :
    {
      if ((base->hcd_Unit.mass_scsi[0] == 'U') &&
          (base->hcd_Unit.mass_scsi[1] == 'S') &&
          (base->hcd_Unit.mass_scsi[2] == 'B') &&
          (base->hcd_Unit.mass_scsi[3] == 'C'))
      {
        if ((ior->io_Command == CMD_READ) ||
            (ior->io_Command == CMD_WRITE))
        {
          switch (base->hcd_Unit.mass_scsi[15])
          {
            case 0x00 : /* Test Unit Ready */
            case 0x1b : /* Spin up ? */
            case 0x12 : /* Inquiry */
            case 0x23 : /* Get max capacity */
            case 0x25 : /* Get capacity */
            case 0x28 : /* Read(10) */
            case 0x2a : /* Write(10) */
            case 0xa8 : /* Read(12) */
            case 0xaa : /* Write(12) */
            {
              switch (base->hcd_Unit.mass_scsi[15])
              {
                case 0x00 : /* Test Unit Ready */
                case 0x1b : /* Spin up ? */
                {
                  break ;
                }

                case 0x12 : /* Inquiry */
                {
                  base->hcd_Unit.mass_data[ 0] = 0x00 ;
                  base->hcd_Unit.mass_data[ 1] = 0x80 ;
                  base->hcd_Unit.mass_data[ 2] = 0x02 ;
                  base->hcd_Unit.mass_data[ 3] = 0x02 ;
                  base->hcd_Unit.mass_data[ 4] = 0x1f ;
                  base->hcd_Unit.mass_data[ 5] = 0x00 ;
                  base->hcd_Unit.mass_data[ 6] = 0x00 ;
                  base->hcd_Unit.mass_data[ 7] = 0x00 ;

                  /* Vendor Information */
                  memset(&base->hcd_Unit.mass_data[ 8], ' ', 8) ;
                  memcpy(&base->hcd_Unit.mass_data[ 8], "PIPO", 4) ; 

                  /* Product Identification */
                  memset(&base->hcd_Unit.mass_data[16], ' ', 16) ;
                  memcpy(&base->hcd_Unit.mass_data[16], "PIPO", 4) ;

                  /* Product Revision Level */
                  memset(&base->hcd_Unit.mass_data[32], ' ',  4) ;
                  memcpy(&base->hcd_Unit.mass_data[32], "0.01", 4) ;
 
                  break ;
                }

                case 0x23 : /* get max capacities */
                {
                  ULONG nb       = 8 ;
                  ULONG filesize = 0 ;
                  ULONG sectorsz = 512 | 0x03000000 ;
                  BPTR file = NULL ;

#ifdef OKHOSTDLL
                  if (file == NULL)
                  {
                    file = DLLFOpen("umass.img", "rb") ;
                  }
#else
                  if (file == NULL)
                  {
#if HCDDEMOPROCESS
                    file = Open("PIPO:umass.img", MODE_OLDFILE) ;
#endif
                  }
#endif
                  if (file != NULL)
                  {
#ifdef OKHOSTDLL
                    filesize = DLLSeek(file, 0, 1) ;
                    filesize = DLLSeek(file, 0, -1) ;
#else
#if HCDDEMOPROCESS
                    filesize = Seek(file, 0, OFFSET_END) ;
                    filesize = Seek(file, 0, OFFSET_BEGINNING) ;
#endif
#endif
                    base->hcd_Unit.mass_filesize = filesize ;
                    filesize /= 512 ;
                    if (filesize > 0) filesize -- ;
#ifdef OKHOSTDLL
                    DLLClose(file) ;
#else
#if HCDDEMOPROCESS
                    Close(file) ;
#endif
#endif
                  }

                  /* motorola */
                  base->hcd_Unit.mass_data[ 0] = (nb       >> 24) & 0xff ;
                  base->hcd_Unit.mass_data[ 1] = (nb       >> 16) & 0xff ;
                  base->hcd_Unit.mass_data[ 2] = (nb       >>  8) & 0xff ;
                  base->hcd_Unit.mass_data[ 3] = (nb       >>  0) & 0xff ;
                  base->hcd_Unit.mass_data[ 4] = (filesize >> 24) & 0xff ;
                  base->hcd_Unit.mass_data[ 5] = (filesize >> 16) & 0xff ;
                  base->hcd_Unit.mass_data[ 6] = (filesize >>  8) & 0xff ;
                  base->hcd_Unit.mass_data[ 7] = (filesize >>  0) & 0xff ;
                  base->hcd_Unit.mass_data[ 8] = (sectorsz >> 24) & 0xff ;
                  base->hcd_Unit.mass_data[ 9] = (sectorsz >> 16) & 0xff ;
                  base->hcd_Unit.mass_data[10] = (sectorsz >>  8) & 0xff ;
                  base->hcd_Unit.mass_data[11] = (sectorsz >>  0) & 0xff ;
                  break ;
                }

                case 0x25 : /* get capacity */
                {
                  ULONG filesize = 0 ;
                  ULONG sectorsz = 512 ;
                  BPTR file = NULL ;

#ifdef OKHOSTDLL
                  if (file == NULL)
                  {
                    file = DLLFOpen("umass.img", "rb") ;
                  }
#else
                  if (file == NULL)
                  {
#if HCDDEMOPROCESS
                    file = Open("PIPO:umass.img", MODE_OLDFILE) ;
#endif
                  }
#endif

                  if (file != NULL)
                  {
#ifdef OKHOSTDLL
                    filesize = DLLSeek(file, 0, 1) ;
                    filesize = DLLSeek(file, 0, -1) ;
#else
#if HCDDEMOPROCESS
                    filesize = Seek(file, 0, OFFSET_END) ;
                    filesize = Seek(file, 0, OFFSET_BEGINNING) ;
#endif
#endif
                    base->hcd_Unit.mass_filesize = filesize ;
                    filesize /= 512 ;
                    if (filesize > 0) filesize -- ;
#ifdef OKHOSTDLL
                    DLLClose(file) ;
#else
#if HCDDEMOPROCESS
                    Close(file) ;
#endif
#endif
                  }

                  /* motorola */
                  base->hcd_Unit.mass_data[ 0] = (filesize >> 24) & 0xff ;
                  base->hcd_Unit.mass_data[ 1] = (filesize >> 16) & 0xff ;
                  base->hcd_Unit.mass_data[ 2] = (filesize >>  8) & 0xff ;
                  base->hcd_Unit.mass_data[ 3] = (filesize >>  0) & 0xff ;
                  base->hcd_Unit.mass_data[ 4] = (sectorsz >> 24) & 0xff ;
                  base->hcd_Unit.mass_data[ 5] = (sectorsz >> 16) & 0xff ;
                  base->hcd_Unit.mass_data[ 6] = (sectorsz >>  8) & 0xff ;
                  base->hcd_Unit.mass_data[ 7] = (sectorsz >>  0) & 0xff ;
                  break ;
                }

                case 0x08 : /* Read(6) */
                case 0x0a : /* Write(6) */
                case 0x28 : /* Read(10) */
                case 0x2a : /* Write(10) */
                case 0x88 : /* Read(16) */
                case 0x8a : /* Write(16) */
                case 0xa8 : /* Read(12) */ 
                case 0xaa : /* Write(12) */
                {
                  BPTR file = NULL ;

#ifdef OKHOSTDLL
                  switch (base->hcd_Unit.mass_scsi[15])
                  {
                    case 0x08 : /* Read(6) */  
                    case 0x28 : /* Read(10) */
                    case 0x88 : /* Read(16) */
                    case 0xa8 : /* Read(12) */ 
                    {
                      file = DLLFOpen("umass.img", "rb+") ;
                      break ;
                    }

                    case 0x0a : /* Write(6) */
                    case 0x2a : /* Write(10) */
                    case 0x8a : /* Write(16) */
                    case 0xaa : /* Write(12) */
                    {
                      file = DLLFOpen("umass.img", "rb+") ;
                      break ;
                    }
                  }
#else
#if HCDDEMOPROCESS
                  file = Open("PIPO:umass.img", MODE_OLDFILE) ;
#endif
#endif
                      
                  if (file != NULL)
                  {
                    ULONG offset ;
                    ULONG length ;

                    switch (base->hcd_Unit.mass_scsi[15])
                    {
                      case 0x08 : /* READ_6 */
                      case 0x0a : /* WRITE_6 */
                      {
                        offset = (base->hcd_Unit.mass_scsi[15 +  1] << 16) |
                                 (base->hcd_Unit.mass_scsi[15 +  2] <<  8) |
                                 (base->hcd_Unit.mass_scsi[15 +  3] <<  0) ;
                        length =  base->hcd_Unit.mass_scsi[15 +  4] ;
                        break ;
                      }

                      case 0x28 : /* READ_10 */
                      case 0x2a : /* WRITE_10 */
                      {
                        offset = (base->hcd_Unit.mass_scsi[15 +  2] << 24) |
                                 (base->hcd_Unit.mass_scsi[15 +  3] << 16) |
                                 (base->hcd_Unit.mass_scsi[15 +  4] <<  8) |
                                 (base->hcd_Unit.mass_scsi[15 +  5] <<  0) ;

                        length = (base->hcd_Unit.mass_scsi[15 +  7] <<  8) |
                                 (base->hcd_Unit.mass_scsi[15 +  8] <<  0) ;
                        break ;
                      }

                      case 0x88 : /* READ_16 */
                      case 0x8a : /* WRITE_16 */
                      {
                        offset = (base->hcd_Unit.mass_scsi[15 +  6] << 24) |
                                 (base->hcd_Unit.mass_scsi[15 +  7] << 16) |
                                 (base->hcd_Unit.mass_scsi[15 +  8] <<  8) |
                                 (base->hcd_Unit.mass_scsi[15 +  9] <<  0) ;

                        length = (base->hcd_Unit.mass_scsi[15 + 10] << 24) |
                                 (base->hcd_Unit.mass_scsi[15 + 11] << 16) |
                                 (base->hcd_Unit.mass_scsi[15 + 12] <<  8) |
                                 (base->hcd_Unit.mass_scsi[15 + 13] <<  0) ;
                        break ;
                      }

                      case 0xa8 : /* READ_12 */
                      case 0xaa : /* WRITE_12 */
                      {
                        offset = (base->hcd_Unit.mass_scsi[15 +  2] << 24) |
                                 (base->hcd_Unit.mass_scsi[15 +  3] << 16) |
                                 (base->hcd_Unit.mass_scsi[15 +  4] <<  8) |
                                 (base->hcd_Unit.mass_scsi[15 +  5] <<  0) ;

                        length = (base->hcd_Unit.mass_scsi[15 +  6] << 24) |
                                 (base->hcd_Unit.mass_scsi[15 +  7] << 16) |
                                 (base->hcd_Unit.mass_scsi[15 +  8] <<  8) |
                                 (base->hcd_Unit.mass_scsi[15 +  9] <<  0) ;
                        break ;
                      }
                    }

                    offset *= 512 ;
                    if (offset <= base->hcd_Unit.mass_filesize)
                    {
#ifdef OKHOSTDLL
                      DLLSeek(file, offset, -1) ;
#else
#if HCDDEMOPROCESS
                      Seek(file, offset, OFFSET_BEGINNING) ;
#endif
#endif
                      switch (base->hcd_Unit.mass_scsi[15])
                      {
                        case 0x08 : /* Read(6) */
                        case 0x28 : /* Read(10) */
                        case 0x88 : /* Read(16) */
                        case 0xa8 : /* Read(12) */
                        {
#ifdef OKHOSTDLL
                          DLLRead(file, ior->io_Data, length*512) ;
#else
#if HCDDEMOPROCESS
                          Read(file, ior->io_Data, length*512) ;
#endif
#if SIMULTIME
                          AP_USBDelay(80) ;
#endif
#endif
                          ior->io_Actual += length*512 ;
                          break ;
                        }

                        case 0x0a : /* Write(6) */
                        case 0x2a : /* Write(10) */
                        case 0x8a : /* Write(16) */
                        case 0xaa : /* Write(12) */
                        {
#ifdef OKHOSTDLL
                          DLLWrite(file, ior->io_Data, length*512) ;
#else
#if HCDDEMOPROCESS
                          Write(file, ior->io_Data, length*512) ;
#endif
#if SIMULTIME
                          AP_USBDelay(100) ;
#endif
#endif
                          ior->io_Actual += length*512 ;
                          break ;
                        }
                      }
                      ior->io_Error = 0 ;
                    }
                    else
                    {
                      ior->io_Error = -32 ;
                    }
#ifdef OKHOSTDLL
                    DLLClose(file) ;
#else
#if HCDDEMOPROCESS
                    Close(file) ;
#endif
#endif

                    base->hcd_Unit.mass_state = 2 ;
                  }
                  else
                  {
                    ior->io_Error = -32 ;
                  }
                  break ;
                }

                
              }

              switch (base->hcd_Unit.mass_scsi[15])
              {
                case 0x08 :
                case 0x0a :
                case 0x28 :
                case 0x2a :
                case 0x88 :
                case 0x8a :
                case 0xa8 :
                case 0xaa :
                {
                  break ;
                }

                default :
                {
                  ior->io_Error = 0 ;
                  if (ior->io_Command == CMD_READ)
                  {
                    if ((ior->io_Data != NULL) && (ior->io_Length > 0))
                    {
                      memcpy(ior->io_Data, base->hcd_Unit.mass_data, ior->io_Length) ;
                      ior->io_Actual = ior->io_Length ;
                      ior->io_Error = 0 ;
                    }
                  }
                  base->hcd_Unit.mass_state = 2 ;               
                  break ;
                }
              }
            }
          }
        }
      }
      break ;      
    }

    case 2 :
    {
      if ((base->hcd_Unit.mass_scsi[0] == 'U') &&
          (base->hcd_Unit.mass_scsi[1] == 'S') &&
          (base->hcd_Unit.mass_scsi[2] == 'B') &&
          (base->hcd_Unit.mass_scsi[3] == 'C'))
      {
        memset(base->hcd_Unit.mass_status, 0, 13) ;
        base->hcd_Unit.mass_status[0] = 'U' ;
        base->hcd_Unit.mass_status[1] = 'S' ;
        base->hcd_Unit.mass_status[2] = 'B' ;
        base->hcd_Unit.mass_status[3] = 'S' ;
        base->hcd_Unit.mass_status[4] = base->hcd_Unit.mass_scsi[4] ;
        base->hcd_Unit.mass_status[5] = base->hcd_Unit.mass_scsi[5] ;
        base->hcd_Unit.mass_status[6] = base->hcd_Unit.mass_scsi[6] ;
        base->hcd_Unit.mass_status[7] = base->hcd_Unit.mass_scsi[7] ;

        ior->io_Error = 0 ;
        ior->io_Actual = 0 ;

        if ((ior->io_Data != NULL) && (ior->io_Length > 0))
        {
          memcpy(ior->io_Data, base->hcd_Unit.mass_status, ior->io_Length) ;
          ior->io_Actual = ior->io_Length ; 
#if SIMULTIME
          AP_USBDelay(10) ;
#endif
        }

        base->hcd_Unit.mass_state = 0 ;
      }                
      break ;
    }
  }

  return ior->io_Error ;
}

LONG ASM SDS emulPTP(
A0 struct USBIOReqHCD *ior,
A6 struct HCDBase *base
)
{
#if HCDDEMOPROCESS
  struct Library *DOSBase           = base->DOSBase ;
#endif
  struct Library *AnaiisPrivateBase = base->AnaiisPrivateBase ;
  BOOL complete ;

  switch (ior->io_Command)
  {
    case CMD_READ :
    {
      ior->io_Error = -33 ;


      switch (LE_WORD(*(UWORD *)&base->hcd_Unit.ptp_op[6]))
      {
        case 0x1001 : /* ??? */
        {
#ifdef PTP_IPAD
          static UBYTE mydata[] = {
          0xe5, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x20, 0x44, 0x00, 0x65, 0x00, 0x76, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65,
          0x00, 0x20, 0x00, 0x68, 0x00, 0x61, 0x00, 0x73, 0x00, 0x20, 0x00, 0x6e, 0x00, 0x6f, 0x00, 0x20,
          0x00, 0x76, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x20, 0x00, 0x65,
          0x00, 0x78, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e,
          0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x01, 0x10, 0x02, 0x10, 0x03,
          0x10, 0x04, 0x10, 0x05, 0x10, 0x06, 0x10, 0x07, 0x10, 0x08, 0x10, 0x09, 0x10, 0x0a, 0x10, 0x0b,
          0x10, 0x14, 0x10, 0x15, 0x10, 0x1b, 0x10, 0x01, 0x00, 0x00, 0x00, 0x06, 0x40, 0x00, 0x00, 0x00,
          0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x38, 0x0b, 0x38, 0x0d, 0x38, 0x03, 0x00, 0x00, 0x00, 0x01,
          0x38, 0x0b, 0x38, 0x0d, 0x38, 0x0b, 0x41, 0x00, 0x70, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x65, 0x00,
          0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x0b, 0x41, 0x00, 0x70,
          0x00, 0x70, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, 0x69, 0x00, 0x50, 0x00, 0x61, 0x00, 0x64,
          0x00, 0x00, 0x00, 0x04, 0x33, 0x00, 0x2e, 0x00, 0x32, 0x00, 0x00, 0x00, 0x0c, 0x47, 0x00, 0x42,
          0x00, 0x30, 0x00, 0x32, 0x00, 0x36, 0x00, 0x52, 0x00, 0x33, 0x00, 0x53, 0x00, 0x5a, 0x00, 0x33,
          0x00, 0x41, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x20, 0x4f, 0x00, 0xbb,
          0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x0c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} ;
#endif
#ifdef PTP_KODAK
          static UBYTE mydata[] = {
          0x5f, 0x01, 0x00, 0x00, 0x02, 0x00, 0x01, 0x10, 0x4f, 0x08, 0xee, 0xd4, 0x64, 0x00, 0x01, 0x00,
          0x00, 0x00, 0x2c, 0x01, 0x1d, 0x45, 0x00, 0x61, 0x00, 0x73, 0x00, 0x74, 0x00, 0x6d, 0x00, 0x61,
          0x00, 0x6e, 0x00, 0x20, 0x00, 0x4b, 0x00, 0x6f, 0x00, 0x64, 0x00, 0x61, 0x00, 0x6b, 0x00, 0x20,
          0x00, 0x50, 0x00, 0x54, 0x00, 0x50, 0x00, 0x20, 0x00, 0x45, 0x00, 0x78, 0x00, 0x74, 0x00, 0x65,
          0x00, 0x6e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x22, 0x00, 0x00, 0x00, 0x01, 0x10, 0x02, 0x10, 0x03, 0x10, 0x04, 0x10, 0x05, 0x10, 0x06,
          0x10, 0x07, 0x10, 0x08, 0x10, 0x09, 0x10, 0x0a, 0x10, 0x0b, 0x10, 0x0c, 0x10, 0x0d, 0x10, 0x0f,
          0x10, 0x12, 0x10, 0x13, 0x10, 0x14, 0x10, 0x15, 0x10, 0x16, 0x10, 0x17, 0x10, 0x1b, 0x10, 0x05,
          0x90, 0x06, 0x90, 0x07, 0x90, 0x08, 0x90, 0x09, 0x90, 0x0a, 0x90, 0x0b, 0x90, 0x0c, 0x90, 0x0d,
          0x90, 0x0e, 0x90, 0x0f, 0x90, 0x10, 0x90, 0x11, 0x90, 0x09, 0x00, 0x00, 0x00, 0x01, 0x40, 0x02,
          0x40, 0x03, 0x40, 0x04, 0x40, 0x05, 0x40, 0x06, 0x40, 0x09, 0x40, 0x0e, 0x40, 0x01, 0xc0, 0x07,
          0x00, 0x00, 0x00, 0x01, 0x50, 0x11, 0x50, 0x06, 0xd0, 0x07, 0xd0, 0x08, 0xd0, 0x09, 0xd0, 0x0a,
          0xd0, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x30, 0x01, 0x38, 0x16, 0x45, 0x00,
          0x61, 0x00, 0x73, 0x00, 0x74, 0x00, 0x6d, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x4b, 0x00,
          0x6f, 0x00, 0x64, 0x00, 0x61, 0x00, 0x6b, 0x00, 0x20, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x6d, 0x00,
          0x70, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x79, 0x00, 0x00, 0x00, 0x1b, 0x44, 0x00, 0x58, 0x00, 0x37,
          0x00, 0x35, 0x00, 0x39, 0x00, 0x30, 0x00, 0x20, 0x00, 0x5a, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x6d,
          0x00, 0x20, 0x00, 0x44, 0x00, 0x69, 0x00, 0x67, 0x00, 0x69, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6c,
          0x00, 0x20, 0x00, 0x43, 0x00, 0x61, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x72, 0x00, 0x61, 0x00, 0x00,
          0x00, 0x08, 0x30, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00,
          0x00, 0x00, 0x0e, 0x4b, 0x00, 0x43, 0x00, 0x54, 0x00, 0x44, 0x00, 0x4c, 0x00, 0x34, 0x00, 0x33,
          0x00, 0x36, 0x00, 0x33, 0x00, 0x31, 0x00, 0x35, 0x00, 0x35, 0x00, 0x33, 0x00, 0x00, 0x00, 0x0c,
          0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x20, 0x4f, 0x08, 0xee, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00} ;
#endif
          if (base->hcd_Unit.ptp_index < 320)
          {
            if (ior->io_Length < 64)
            {
              ior->io_Error = -36 ;
            }
            else
            {
              copydata(ior, &mydata[base->hcd_Unit.ptp_index], ior->io_Length) ;
              base->hcd_Unit.ptp_index += ior->io_Length ;
              ior->io_Error = 0 ;

              if ((ior->io_Data != NULL) && (ior->io_Length > 12))
              {
                *(ULONG *)((ULONG)ior->io_Data + 8) = *(ULONG *)(&base->hcd_Unit.ptp_op[8]) ;
              }
#ifdef PTP_IPAD
              ior->io_Actual = 241 ;
#endif
#ifdef PTP_KODAK
              ior->io_Actual = 363 ;
#endif
            }
          }    
          else
          {
            ior->io_Error = -34 ;
          }
          break ;
        }

        default :
        {
          break ;
        }
      }
      break ;
    }

    case CMD_WRITE :
    {
      /* !!! CODE TO DO !!! */
      BPTR file = NULL ;

      ior->io_Error = -33 ;

      memcpy(&base->hcd_Unit.ptp_op[0], ior->io_Data, ior->io_Length) ;
      base->hcd_Unit.ptp_index = 0 ;

#if HCDDEMOPROCESS
      file = Open("PIPO:ptp.out", MODE_OLDFILE) ;
      if (file == NULL)
      {
        file = Open("PIPO:ptp.out", MODE_NEWFILE) ;
      }

      if (file != NULL)
      {
        Seek(file, 0, OFFSET_END) ;
        Write(file, ior->io_Data, ior->io_Length) ;
        Close(file) ;
      
        ior->io_Actual = ior->io_Length ;
        ior->io_Error  = 0 ;
      }
#endif
      break ;
    }
  }

  return ior->io_Error ;
}

BOOL ASM SDS emulUSBIOReq(
A0 struct USBIOReqHCD *ior,
A6 struct HCDBase *base
)
{
  BOOL ret = TRUE ;
  struct USBBusSetupData *setup ;
  long dvnum = 0 ;
  long epnum = 0 ;
  long eptyp = 0 ;
  long eplen = 0 ;
  long epinterval = 0 ;
  int speed ;
  long interfacenum = 0 ;
  long alternatenum = 0 ;
  struct Node *device = NULL ;
  struct Node *interf = NULL ;
  long retry = 0 ;
  long phase = 0 ;
  uint64 num ;
  BOOL traceit = FALSE ;
  ULONG actual ;
  UBYTE cTxt[80] ;
  long i     = 0 ;
  UBYTE *c ;
  struct Library *AnaiisPrivateBase = base->AnaiisPrivateBase ;
#ifdef OKHOSTDLL
  ULONG hdev       = NULL ;
  ULONG hdevhandle = NULL ;
#endif

  if ((AnaiisPrivateBase != NULL) && (ior != NULL))
  {
    
    if (ior != NULL)
    {
      if (ior->io_Flags & USB_IOF_TRACE)
      {
        traceit = TRUE ;
      }
    }

    if (ior->io_EndPoint != NULL)
    {
      AP_GetAttrs(ATYPE_ENDPOINT, (struct Node *)ior->io_EndPoint,
                  USBA_Device, &device,
                  USBA_Interface, &interf,
                  USBA_Address, &epnum,
                  USBA_Attributes, &eptyp,
                  USBA_PacketSize, &eplen,
                  USBA_Interval, &epinterval,
                  USBA_Data1, &dvnum,
#ifdef OKHOSTDLL
                  USBA_Data2, &hdev,
                  USBA_Data3, &hdevhandle,
#endif
                  TAG_DONE) ;

      if (device != NULL)
      {
        struct Node *hcd = NULL ;

        AP_GetAttrs(ATYPE_DEVICE, device,
                    USBA_HCD, &hcd,
                    USBA_DeviceSpeed, &speed,   
                    TAG_DONE) ;

        if (base->hw == NULL)
        { 
          if (hcd != NULL)
          {
            long toto = 7 ;
#ifdef OKPSC2200
            toto = 14 ;
#endif
#ifdef OKMOUSE
            toto = 6 ;
#endif
#ifdef OKHOSTDLL
            toto = 1 ;
#endif

            base->hw = hcd ;

#if TRACE
            MyTrace("GOT HARDWARE INFO, TIME TO SET SOME STUFF INTO\n") ;
#endif
            Forbid() ;
            AP_SetAttrs(ATYPE_HARDWARE, base->hw,
                        USBA_MaxTransactions, toto,
#ifdef OKHOSTDLL
                        USBA_ClaimInterfacePtr, emul_ClaimInterface,
                        USBA_ReleaseInterfacePtr, emul_ReleaseInterface,
#endif
                        TAG_DONE) ;

            Permit() ;
#if TRACE
            if (1)
            {
              char cBuf[80] ;
              ULONG d1 = 0 ;
              ULONG d2 = 0 ;
              ULONG d3 = 0 ;

              AP_GetAttrs(ATYPE_HARDWARE, base->hw,
                          USBA_MaxTransactions, &d1,
                          USBA_ClaimInterfacePtr, &d2,
                          USBA_ReleaseInterfacePtr, &d3,
                          TAG_DONE) ;

              sprintf(cBuf, "retrieve stuff %08lx %08lx %08lx\n", d1, d2, d3) ;
              MyTrace(cBuf) ;
#ifdef OKHOSTDLL
              sprintf(cBuf, "PTRs %08lx %08lx\n", emul_ClaimInterface, emul_ReleaseInterface) ;
              MyTrace(cBuf) ;
#endif
            }
#endif
          }
        }

#ifdef OKHOSDLL

#else
        if ((speed < USB_SPEED_HIGH) && (eplen > 64) && (eptyp == USBEPTT_BULK))
        {
          AP_SetAttrs(ATYPE_DEVICE, device,
                      USBA_DeviceSpeed, USB_SPEED_HIGH+1,
                      TAG_DONE) ;
        }
#endif
      }

      if (interf != NULL)
      {
        AP_GetAttrs(ATYPE_INTERFACE, interf,
                    USBA_InterfaceNum, &interfacenum,
                    USBA_AlternateNum, &alternatenum,
                    TAG_DONE) ;
      }
    }

#ifdef OKHOSTDLL

#if TRACE
    if (1)
    {
      char buf[80] ;

       
      sprintf(buf, "[%ld,%ld]", dvnum, epnum) ;
      MyTrace(buf) ;
    }
#endif

    if ((dvnum == 0) && (hdev == NULL))
    {
      /* enumeration */

      if (base->hcd_Unit.dev0maxlibusb > 0)
      {
        if (base->hcd_Unit.dev0step <= 1)
        {
          dvnum = MYHUBADDR ;
          hdev  = NULL ;
        }
        else
        {
          if (base->hcd_Unit.dev0steplibusb < base->hcd_Unit.dev0maxlibusb)
          {
            ULONG hdevhandle = 0 ;

            dvnum = 0 ;

            // skip bad devices
            do
            {
              hdev  = getdev(base, base->hcd_Unit.dev0steplibusb) ;
              hdevhandle = USB_open(hdev) ;
              if (hdevhandle)
              {
#if LIBUSBX
                long speed = libusb_get_device_speed(hdevhandle) ;
                             
#if TRACE
                if (1)
                {
                  char cBuf[80] ;

                  sprintf(cBuf, "speed %ld\n", speed+1) ;
                  MyTrace(cBuf) ;
                }
#endif
#endif
                USB_close(hdevhandle) ;
              }
              else
              {
                base->hcd_Unit.dev0steplibusb ++ ;
              }
            } while ((hdevhandle == 0) && 
                     (base->hcd_Unit.dev0steplibusb < base->hcd_Unit.dev0maxlibusb)) ;
            
            if (hdevhandle == 0)
            {
              dvnum = base->hcd_Unit.dev0step ;
              hdev  = NULL ;
            }
          }
          else
          {
            dvnum = base->hcd_Unit.dev0step ;
            hdev  = NULL ;
          }
        }
      }
      else
      {
        if (base->hcd_Unit.dev0step <= 1)
        {
          dvnum = MYHUBADDR ;
          hdev  = NULL ;
        }
        else
        {
          dvnum = base->hcd_Unit.dev0step ;
          hdev  = NULL ;
        }
      }
    }
#else
    if (dvnum == 0)
    {
      /* enumeration */
      //traceit = TRUE ;
      dvnum = base->hcd_Unit.dev0step ;

      if (dvnum == 0)
      {
        //base->hcd_Unit.dev0step = MYHUBADDR ;
        dvnum = MYHUBADDR ;
      }
    }

    switch (dvnum)
    {
      case MYHUBADDR :
      //case MYPRINTER1ADDR :
      //case MYPRINTER2ADDR :
      //case MYPRINTER6ADDR :
      case MYPTPADDR :
      {
        traceit = TRUE ;
        break ;
      }

      default :
      {
        break ;
      }
    }
#endif

    retry = (ior->io_Flags & USB_IOF_RETRYMSK) >> USB_IOS_RETRYSFT ;
    phase = (ior->io_Flags & USB_IOF_PHASEMSK) >> USB_IOS_PHASESFT ;

    if ((phase == USB_SETUP_PHASE) &&
        (ior->io_SetupData == NULL) &&
        (ior->io_SetupLength == 0))
    {
      ior->io_Error  = 0 ;
      ior->io_Actual = 0 ;
      phase = USB_DATA_PHASE ;
      retry = 0 ;
    }

#if TRACE
    if (1)
    {
      char buf[256] ;
      char *pc ;

      pc = &buf[0] ;

#ifdef OKHOSTDLL
      pc += sprintf(pc, "EMUL cmd=%ld (%ld %08lx %08lx)", ior->io_Command, dvnum, hdev, hdevhandle) ;
#else
      pc += sprintf(pc, "EMUL cmd=%ld (%ld)", ior->io_Command, dvnum) ;
#endif

      switch (phase)
      {
        case USB_SETUP_PHASE :
        {
          if (ior->io_SetupData != NULL)
          {
            unsigned char *ptr = (unsigned char *)ior->io_SetupData ;
            int i ;

            pc += sprintf(pc, " ") ;

            for ( i = 0 ; i < ior->io_SetupLength ; i++ )
            {
              pc += sprintf(pc, "%02lx", ptr[i]) ;
            }
          }

          pc += sprintf(pc, "\n") ;
          break ;
        }

        case USB_DATA_PHASE :
        {
          pc += sprintf(pc, " data\n") ;
          break ;
        }

        case USB_STATUS_PHASE :
        {
          pc += sprintf(pc, " status\n") ;
          break ;
        }
      }

      MyTrace(buf) ;
    }
#endif

    switch (phase)
    {
      case USB_SETUP_PHASE :
      {
        ior->io_Error  = 0 ;
        ior->io_Actual = 0 ;

        num.lo = 1 ;
        num.hi = 0 ;
        AP_Add64(&num, &base->hcd_Unit.audit.SendPackets) ;

        num.lo = ior->io_SetupLength ;
        num.hi = 0 ;
        AP_Add64(&num, &base->hcd_Unit.audit.SendBytes) ;
        
#if TRACE
        if (traceit)
        {
          sprintf(cTxt, "<SETUP,DEV%ld,EP%ld><DATA[", dvnum, epnum & 0x0f) ;
          MyTrace(cTxt) ;
          c = ior->io_SetupData ;
          for (i = 0 ; i < ior->io_SetupLength ; i++, c++)
          {
            sprintf(cTxt, "%02lx", *c) ;
            MyTrace(cTxt) ;
          }
          MyTrace("]>") ;
          MyTrace(AckTxt) ;
          MyTrace(LFTxt) ;
        }
#endif

        phase = USB_DATA_PHASE ;
        ret = FALSE ;
        break ;
      }
    
      case USB_DATA_PHASE :
      {
        actual = ior->io_Actual ;

        if (ior->io_SetupData == NULL)
        {
          switch (ior->io_Command)
          {
            case CMD_READ  :
            {        
              /* IN */
              switch (dvnum)
              {
                case 0 :
                {
                  ior->io_Error = -33 ;
#ifdef OKHOSTDLL
                  if (hdev != NULL)
                  {
                    int liberr = 0 ;
                    ULONG localhdevhandle = NULL ;
                  
                    if (hdevhandle == NULL)
                    {
                      localhdevhandle = USB_open(hdev) ;
                    }
                    else
                    {
                      localhdevhandle = hdevhandle ;
                    }

                    if (localhdevhandle != NULL)
                    {
                      switch (eptyp)
                      {
                        case USBEPTT_CONTROL :
                        {
                          ior->io_Error = USBERR_XFERFAIL ;
                          break ;
                        }

                        case USBEPTT_ISOCHRONOUS :
                        {
                          ior->io_Error = USBERR_XFERFAIL ;
                          break ;
                        }

                        case USBEPTT_BULK :
                        case USBEPTT_INTERRUPT :
                        {
                          char *data      = base->hcd_Unit.datachip ;
#if LIBUSBX
                          char *actualptr = base->hcd_Unit.datachip2 ;
#endif
 
                          if (data != NULL)
                          {
                            switch (eptyp)
                            {
                              case USBEPTT_BULK :
                              {
#if LIBUSBX
                                liberr = libusb_bulk_transfer(localhdevhandle,
                                                              epnum,
                                                              (ULONG)(DLL_GetChipOffset()+data),
                                                              eplen,
                                                              (ULONG)(DLL_GetChipOffset()+actualptr),
                                                              1000) ; 
#else
                                liberr = usb_bulk_read(localhdevhandle, epnum, (ULONG)(DLL_GetChipOffset()+data), eplen, 1000) ;
#endif
                                break ;
                              }

                              case USBEPTT_INTERRUPT :
                              {
#if LIBUSBX
                                liberr = libusb_interrupt_transfer(localhdevhandle,
                                                                   epnum,
                                                                   (ULONG)(DLL_GetChipOffset()+data),
                                                                   eplen,
                                                                   (ULONG)(DLL_GetChipOffset()+actualptr),
                                                                   epinterval) ;
#else
                                liberr = usb_interrupt_read(localhdevhandle, epnum, (ULONG)(DLL_GetChipOffset()+data), eplen, epinterval) ;
#endif
                                break ;
                              }
                            }

#if LIBUSBX
                            switch (liberr)
                            {
                              case 0 :
                              {
                                if (*(ULONG*)actualptr < ior->io_Length)
                                {
                                  memcpy(ior->io_Data, data, *(ULONG*)actualptr) ;
                                  ior->io_Actual = *(ULONG*)actualptr ;
                                }
                                else
                                {
                                  memcpy(ior->io_Data, data, ior->io_Length) ;
                                  ior->io_Actual = ior->io_Length ;
                                }
                                ior->io_Error = 0 ;
                                break ;
                              }
                            
                              case -1 :
                              {
                                AP_NotifyUSBInterface((struct USBInterface*)interf, USBNM_TYPE_INTERFACEDETACH) ;
                                AP_NotifyUSBDevice((struct USBDevice*)device, USBNM_TYPE_FUNCTIONDETACH) ;
                                AP_USBDelay(100) ;
                                ior->io_Error = USBERR_XFERFAIL ;
                                break ;
                              }

                              default :
                              {
                                ior->io_Error = USBERR_XFERFAIL ;
                                break ;
                              }
                            }
#else
                            if (liberr > 0)
                            {
                              if (liberr < ior->io_Length)
                              {
                                memcpy(ior->io_Data, data, liberr) ;
                                ior->io_Actual = liberr ;
                              }
                              else
                              {
                                memcpy(ior->io_Data, data, ior->io_Length) ;
                                ior->io_Actual = ior->io_Length ;
                              }
                              ior->io_Error = 0 ;
                            }
                            else
                            {
                              switch (liberr)
                              {
                                case -5 :   ior->io_Error = USBERR_IOERROR  ; break ;
                                case -116 : ior->io_Error = USBERR_TIMEOUT  ; break ;
                                default :   ior->io_Error = USBERR_XFERFAIL ; break ;
                              }
                            }
#endif
#if TRACE
                            if (1)
                            {
                              char cBuf[80] ;
                              sprintf(cBuf, "usb_%s_read %08lx ep=%ld size=%ld error=%ld\n", 
                                      (eptyp==USBEPTT_INTERRUPT)?"interrupt":
                                      (eptyp==USBEPTT_BULK)?"bulk":"?", localhdevhandle, epnum, eplen, liberr) ;
                              MyTrace(cBuf) ;
                            }
#endif
                          }
                          break ;
                        }
                      }
                    }

                    if (hdevhandle == NULL)
                    {
                      if (localhdevhandle != NULL)
                      {
                        USB_close(localhdevhandle) ;
                        localhdevhandle = NULL ;
                      }
                    }
                  }
#endif
                  break ;
                }

                case MYHUBADDR : /* hub */
                {
                  /* no changes */
                  ior->io_Actual = 0 ;
                  ior->io_Error  = 0 ;
                  break ;
                }

#ifdef OKMOUSE
                case MYMOUSEADDR : /* mouse */
                {
                  ULONG mouse0 = 0 ;
                  ULONG mouse1 = 0 ;
                  ULONG mouse2 = 0 ;
                  char oldX, oldY, X, Y ;
                  UBYTE *data ;

                  ior->io_Actual = 0 ;

                  if (1)
                  {
                    UBYTE pa      = *(UBYTE *)0x00bfe001 ;
                    UWORD joy0dat = *(UWORD *)0x00dff00a ;
                    UWORD joy1dat = *(UWORD *)0x00dff00c ;
                    UWORD potin   = *(UWORD *)0x00dff016 ;

                    mouse0  = 0x20000000 ;
                    mouse0 |= joy0dat ; 
                    mouse0 |= ((pa & 0x40)     ?0:0x00400000) ;
                    mouse0 |= ((potin & 0x0400)?0:0x00800000) ;
                    mouse0 |= ((potin & 0x0100)?0:0x00020000) ;

                    mouse1  = 0x20000000 ;
                    mouse1 |= joy1dat ; 
                    mouse1 |= ((pa & 0x80)     ?0:0x00400000) ;
                    mouse1 |= ((potin & 0x4000)?0:0x00800000) ;
                    mouse1 |= ((potin & 0x1000)?0:0x00020000) ;
                  }
                  else
                  {
                    mouse1 = AP_OldReadJoyPort(1) ;
                  }

                  if (mouse1 & 0x20000000)
                  {
                    mouse2 = base->hcd_Unit.mouse_old ;
                    oldX = (mouse2 >> 8) & 0xff ;
                    oldY = (mouse2 >> 0) & 0xff ;
                  
                    if (mouse1 != mouse2)
                    {
                      data = ior->io_Data ;
                      if (data)
                      {
                        if (ior->io_Length > 0)
                        {
                          X = (char)((mouse1 >> 8) & 0xff) - oldX ;
                          Y = (char)((mouse1 >> 0) & 0xff) - oldY ;

                          data[0]  = ((mouse1 & 0x00400000)?1:0) ;
                          data[0] |= ((mouse1 & 0x00800000)?2:0) ;

                          if (ior->io_Length > 1)
                          {
                            data[1] = Y ;
                            if (ior->io_Length > 2)
                            {
                              data[2] = X ;
                              if (ior->io_Length > 3)
                              {
                                data[3] = 0 ;
                              }
                            }
                          }
                        }
                        ior->io_Actual = ior->io_Length ;
                        ior->io_Error  = 0 ;
                      }

                      base->hcd_Unit.mouse_old = mouse1 ;
                    }
                  }
                  break ;
                }
#endif

                case MYPRINTER6ADDR :
                case MYMASSADDR     :
                {
                  ior->io_Error = -33 ;
                  if (epnum == 0x87)
                  {
                    emulMass(ior, base) ;
                  }
                  break ;
                }

                case MYPTPADDR :
                {
                  ior->io_Error = -33 ;
                  if (epnum == 0x82)
                  {
                    emulPTP(ior, base) ;
                  }
                  break ;
                }

                default :
                {
                  ior->io_Error = -33 ;
                  break ;
                }
              }
              break ;
            }

            case CMD_WRITE :
            {
              /* OUT */
              switch (dvnum)
              {
                case 0 :
                {
                  ior->io_Error = -33 ;
#ifdef OKHOSTDLL
                  if (hdev != NULL)
                  {
                    int liberr = 0 ;

                    ULONG localhdevhandle = NULL ;
                  
                    if (hdevhandle == NULL)
                    {
                      localhdevhandle = USB_open(hdev) ;
                    }
                    else
                    {
                      localhdevhandle = hdevhandle ;
                    }

                    if (localhdevhandle != NULL)
                    {
                      switch (eptyp)
                      {
                        case USBEPTT_CONTROL :
                        {
                          ior->io_Error = USB_control_msg(ior, hdev, localhdevhandle, base) ;

#if TRACE
                          if (1)
                          {
                            char cBuf[80] ;

                            sprintf(cBuf, "usb_control %08lx ep=%ld size=%ld error=%ld\n", 
                                    localhdevhandle, epnum, eplen, ior->io_Error) ;
                            MyTrace(cBuf) ;
                          }
#endif                         
                          break ;
                        }

                        case USBEPTT_ISOCHRONOUS :
                        {
                          ior->io_Error = - 33 ;
                          break ;
                        }

                        case USBEPTT_BULK :
                        case USBEPTT_INTERRUPT :
                        {
                          char *data      = base->hcd_Unit.datachip ;
#if LIBUSBX
                          char *actualptr = base->hcd_Unit.datachip2 ;
#endif
 
                          if (data != NULL)
                          {
                            memcpy(data, ior->io_Data, eplen) ;

                            switch (eptyp)
                            {
                              case USBEPTT_BULK :
                              {
#if LIBUSBX
                                liberr = libusb_bulk_transfer(localhdevhandle,
                                                              epnum,
                                                              (ULONG)(DLL_GetChipOffset()+data),
                                                              eplen,
                                                              (ULONG)(DLL_GetChipOffset()+actualptr),
                                                              1000) ; 
#else
                                liberr = usb_bulk_write(localhdevhandle, epnum, (ULONG)(DLL_GetChipOffset()+data), eplen, 1000) ;
#endif
                                break ;
                              }

                              case USBEPTT_INTERRUPT :
                              {
#if LIBUSBX
                                liberr = libusb_interrupt_transfer(localhdevhandle,
                                                                   epnum,
                                                                   (ULONG)(DLL_GetChipOffset()+data),
                                                                   eplen,
                                                                   (ULONG)(DLL_GetChipOffset()+actualptr),
                                                                   1000) ;
#else
                                liberr = usb_interrupt_write(localhdevhandle, epnum, (ULONG)(DLL_GetChipOffset()+data), eplen, 1000) ;
#endif
                                break ;
                              }
                            }

#if LIBUSBX
                            switch (liberr)
                            {
                              case 0 :
                              {
                                if (*(ULONG*)actualptr < eplen)
                                {
                                  ior->io_Actual = *(ULONG*)actualptr ;
                                }
                                else
                                {
                                  ior->io_Actual = eplen ;
                                }
                                ior->io_Error = 0 ;
                                break ;
                              }

                              case -1 :
                              {
                                AP_NotifyUSBInterface((struct USBInterface*)interf, USBNM_TYPE_INTERFACEDETACH) ;
                                AP_NotifyUSBDevice((struct USBDevice*)device, USBNM_TYPE_FUNCTIONDETACH) ;
                                AP_USBDelay(100) ;
                                ior->io_Error = USBERR_XFERFAIL ;
                                break ;
                              }

                              default :
                              {
                                ior->io_Error = USBERR_XFERFAIL ;
                                break ;
                              }
                            }
#else
                            if (liberr > 0)
                            {
                              if (liberr < eplen)
                              {
                                ior->io_Actual = liberr ;
                              }
                              else
                              {
                                ior->io_Actual = eplen ;
                              }
                              ior->io_Error = 0 ;
                            }
                            else
                            {
                              switch (liberr)
                              {
                                case -5 :   ior->io_Error = USBERR_IOERROR  ; break ;
                                case -116 : ior->io_Error = USBERR_TIMEOUT  ; break ;
                                default :   ior->io_Error = USBERR_XFERFAIL ; break ;
                              }
                            }
#endif
#if TRACE
                            if (1)
                            {
                              char cBuf[80] ;

                              sprintf(cBuf, "usb_%s_write %08lx ep=%ld size=%ld error=%ld\n", 
                                      (eptyp==USBEPTT_INTERRUPT)?"interrupt":
                                      (eptyp==USBEPTT_BULK)?"bulk":"?", localhdevhandle, epnum, eplen, liberr) ;
                              MyTrace(cBuf) ;
                            }
#endif
                          }
                          break ;
                        }
                      }
                    }

                    if (hdevhandle == NULL)
                    {
                      if (localhdevhandle != NULL)
                      {
                        USB_close(localhdevhandle) ;
                        localhdevhandle = NULL ;
                      }
                    }
                  }
#endif
                  break ;
                }

                case MYHUBADDR : /* hub */
                {
                  break ;
                }

#ifdef OKPRINTER
                case MYPRINTER1ADDR :
                case MYPRINTER2ADDR :
                case MYPRINTER6ADDR :
                case MYMASSADDR     :
                {
                  BPTR f = NULL ;
                  char cName[32] ;
                  int xferlength, xfertodo ;

#if HCDDEMOPROCESS
                  struct Library *DOSBase = base->DOSBase ;
#endif
                  ior->io_Error    = -33 ;
                  if ((dvnum == MYPRINTER6ADDR) && (epnum == 0x07) ||
                      (dvnum == MYMASSADDR))
                  {
                    /* disk */
                    emulMass(ior, base) ;
                  }
                  else
                  {
                    /* printer */
                    if (ior->io_Length == 0)
                    {
                      ior->io_Error = 0 ;
                    }
                    else
                    {
                      sprintf(cName, "out%ld.pcl", dvnum) ;
#ifdef OKHOSTDLL 
                      f = DLLFOpen(cName, "rb+") ;
                      if (f == NULL)
                      {
                        f = DLLFOpen(cName, "wb") ;
                      }

                      if (f != NULL)
                      {
                        DLLSeek(f, 0, 1) ;
                      }
#else
#if HCDDEMOPROCESS
                      f = Open(cName, MODE_OLDFILE) ;
                      if (f == NULL)
                      {
                        f = Open(cName, MODE_NEWFILE) ; 
                      }

                      if (f != NULL)
                      {
                        Seek(f, 0, OFFSET_END) ;
                      }
#else
                      sprintf(cName, "PIPO:out%ld.txt", dvnum) ;
                      f = MyOpen(cName, 2) ;
#endif
#endif 
                      if (ior->io_Actual < ior->io_Length)
                      {
                        xfertodo   = ior->io_Length - ior->io_Actual ;
                        xferlength = (xfertodo > eplen) ? eplen : xfertodo ;
          
                        if (f != NULL)
                        {
                          // Ca craint !!!
#if SIMULTIME
                          AP_USBDelay(10) ;
#endif
#ifdef OKHOSTDLL
                          DLLWrite(f,
                          (UBYTE *)((ULONG)(ior->io_Data) + ior->io_Actual),
                          xferlength) ; 
#else
#if HCDDEMOPROCESS
                          Write(f, 
                          (UBYTE *)((ULONG)(ior->io_Data) + ior->io_Actual),
                          xferlength) ;
#else
                          MyWrite(f, 
                          (UBYTE *)((ULONG)(ior->io_Data) + ior->io_Actual),
                          xferlength) ;
#endif
#endif
                        }
     
                        ior->io_Actual += xferlength ;
                        ior->io_Error = 0 ;
                      
                        if (ior->io_Actual < ior->io_Length)
                        {
                          ret = FALSE ;
                        }
                      }
                      else
                      {
                        /* buffer overflow */
                        ior->io_Error = -36 ;
                      }

                      if (f != NULL)
                      {
#ifdef OKHOSTDLL
                        DLLClose(f) ;
#else
#if HCDDEMOPROCESS
                        Close(f) ;
#else
                        MyClose(f) ;
#endif
#endif
                        f = NULL ;
                      }
                    }
                  }
                  break ;
                }
#endif

                case MYPTPADDR :
                {
                  ior->io_Error = -33 ;
                  if (epnum == 0x01)
                  {
                    emulPTP(ior, base) ;
                  }
                  break ;
                }

                default :
                {
                  ior->io_Error = -33 ;
                  break ;
                }
              }
              break ;
            }
          }
        }
        else
        {
          setup = ior->io_SetupData ;
          
          switch (ior->io_Command)
          {
            case CMD_READ :
            {
              switch (setup->sd_Request)
              {
                case USBREQC_GET_STATUS : /* 0 GET_STATUS */
                {
                  switch (dvnum)
                  {
                    case 0 :
                    {
#ifdef OKHOSTDLL
                      ior->io_Error = USB_control_msg(ior, hdev, hdevhandle, base) ;
#if TRACE

                      MyTrace("Getstatus [0]\n") ;
#endif
#endif
                      break ;
                    }

                    case MYHUBADDR : /* hub */
                    {
                      switch (setup->sd_RequestType)
                      {
                        case 0xa3 :
                        {
                          ULONG value ;
                          UBYTE data[4] ;
                          int portnum ;

                          portnum = LE_WORD(setup->sd_Index) ;
                          switch (portnum)
                          {
                            case  1 :
                            case  2 :
                            case  3 :
                            case  4 :
                            case  5 :
                            case  6 :
                            case  7 :
                            case  8 :
                            case  9 :
                            case 10 :
                            {
                              value = base->hcd_Unit.hub_port[portnum] ;
                              if (base->hcd_Unit.hub_port[portnum] == 0x00010000)
                              {
#ifdef OKMOUSE
#endif
#ifdef OKPRINTER
#endif
#ifdef OKPSC2200 
#endif
#ifdef OKMASS 
#endif
#ifdef OKPTP
#endif

                                if (1)
                                { 
                                  base->hcd_Unit.hub_port[portnum] = 0x01030100 ;
                                }

                              }

                              if (base->hcd_Unit.hub_port[portnum] == 0x01030100)
                              {
                                //LOW
                                base->hcd_Unit.hub_port[portnum] = 0x03031100 ;

                                //HIGH
                                //base->hcd_Unit.hub_port[portnum] = 0x03051100 ;
                              }
                              break ;
                            }

                            default :
                            {
                              value = 0 ;
                              break ;
                            }
                          }

                          data[0] = (value >> 24) & 0xff ;
                          data[1] = (value >> 16) & 0xff ;
                          data[2] = (value >>  8) & 0xff ;
                          data[3] = (value >>  0) & 0xff ;

                          ret = copydata(ior, data, eplen) ;
                          break ;
                        }
                      }
                      break ;
                    }

                    case MYPRINTER1ADDR :
                    case MYPRINTER2ADDR :
                    case MYPRINTER6ADDR :
                    case MYMASSADDR     :
                    {
                      UBYTE data[80] ;
                      int len ;

                      strcpy(&data[2], (dvnum == MYPRINTER1ADDR)?"":
                                       (dvnum == MYPRINTER2ADDR)?"gnagnagna gningningnin":
                                       (dvnum == MYPRINTER6ADDR)?"HP way":
                                                                 "dead or alive stuff?") ;
                      len = strlen(&data[2]) ;
                      *(UWORD *)&data[0] = LE_WORD(len) ;

                      ret = copydata(ior, data, eplen) ;
                      break ;
                    }
                  }
                  break ;
                }

                case USBREQC_GET_PORT_STATUS : /* 1 */
                {
                  switch (dvnum)
                  {
                    case 0 :
                    {
#ifdef OKHOSTDLL
                      ior->io_Error = USB_control_msg(ior, hdev, hdevhandle, base) ;
#if TRACE
                      MyTrace("Getportstatus [0]\n") ;
#endif
#endif
                      break ;
                    }

                    case MYPRINTER1ADDR :
                    case MYPRINTER2ADDR :
                    case MYPRINTER6ADDR :
                    {
                      if ((ior->io_Length > 0) && (ior->io_Data != NULL))
                      {
                        UBYTE *data = (UBYTE *)ior->io_Data ;
                        data[0]        = 0x18 ;
                        ior->io_Actual = 1 ;
                        ior->io_Error  = 0 ;
                      }
                      break ;
                    }
                  }
                  break ;
                }

                case USBREQC_GET_DESCRIPTOR : /* 6 GET_DESCRIPTOR */
                {
                  switch (dvnum)
                  {
                    case 0 :
                    {
#ifdef OKHOSTDLL
                      ior->io_Error = USB_control_msg(ior, hdev, hdevhandle, base) ;
#if TRACE
                      if (1)
                      {
                        char cBuf[80] ;

                        sprintf(cBuf, "Getdescriptor [0] len=%ld actual=%ld => %ld\n", ior->io_Length, ior->io_Actual, ior->io_Error) ;
                        MyTrace(cBuf) ;
                      }
#endif
#endif
                      break ; 
                    }

                    case MYHUBADDR : /* hub */
                    {
                      switch ((LE_WORD(setup->sd_Value) >> 8) & 0xff)
                      {
                        case USBDESC_DEVICE : /* 1 */
                        {
                          ret = copydata(ior, hub_dd, eplen) ;
                          break ;
                        }

                        case USBDESC_CONFIGURATION : /* 2 */
                        {
                          ret = copydata(ior, hub_id, eplen) ;
                          break ;
                        }

                        case USBDESC_STRING : /* 3 */
                        {
                          switch ((LE_WORD(setup->sd_Value) >> 0) & 0xff)
                          {
                            case 0 :
                            {
                              MakeString((struct USBIOReq *)ior, "\x09\x04", base) ;
                              break ;
                            }

                            case 1 :
                            {
                              MakeString((struct USBIOReq *)ior, "GP", base) ;
                              break ;
                            }

                            case 2 :
                            {
                              MakeString((struct USBIOReq *)ior, "Root hub", base) ;
                              break ;
                            }

                            case 3 :
                            {
                              MakeString((struct USBIOReq *)ior, "zZ", base) ;
                              break ;
                            }

                            default :
                            {
                              break ;
                            }
                          }
                          break ;
                        }

                        case 0x29 :
                        {
                          UBYTE localhub_hd[10] ;

                          memcpy(&localhub_hd[0], &hub_hd[0], 9) ;

#ifdef OKPTP
                          localhub_hd[2] = 7 ;
#endif
     
#ifdef OKHOSTDLL
                          localhub_hd[2] = base->hcd_Unit.dev0maxlibusbok + 4 ;
#endif                     

                          ret = copydata(ior, localhub_hd, eplen) ;
                          break ;
                        }

                        default :
                        {
                          break ;
                        }
                      }
                      break ;
                    }

#ifdef OKMOUSE
                    case MYMOUSEADDR : /* mouse */
                    {
                      switch ((LE_WORD(setup->sd_Value) >> 8) & 0xff)
                      {
                        case USBDESC_DEVICE : /* 1 */
                        {
                          ret = copydata(ior, ms_dd, eplen) ;
                          break ;
                        }

                        case USBDESC_CONFIGURATION : /* 2 */
                        {
                          ret = copydata(ior, ms_id, eplen) ;
                          break ;
                        }

                        case USBDESC_STRING : /* 3 */
                        {
                          switch ((LE_WORD(setup->sd_Value) >> 0) & 0xff)
                          {
                            case 0 :
                            {
                              MakeString((struct USBIOReq *)ior, "\x09\x04", base) ;
                              break ;
                            }

                            case 1 :
                            {
                              MakeString((struct USBIOReq *)ior, "GP Mouse", base) ;
                              break ;
                            }

                            case 2 :
                            {
                              MakeString((struct USBIOReq *)ior, "Mickey Mou$e", base) ;
                              break ;
                            }

                            case 3 :
                            {
                              MakeString((struct USBIOReq *)ior, "zZ", base) ;
                              break ;
                            }

                            case 4 :
                            {
                              MakeString((struct USBIOReq *)ior, "Mickey Mou$e interface name", base) ;
                              break ;
                            }

                            case 5 :
                            {
                              MakeString((struct USBIOReq *)ior, "Mickey Mou$e configuration name", base) ;
                              break ;
                            }

                            default :
                            {
                              break ;
                            } 
                          }
                          break ;
                        }

                        case 0x22 :
                        {
                          ret = copydata(ior, ms_hid, eplen) ;
                          break ;
                        }

                        default :
                        {
                          break ;
                        }
                      }
                      break ;
                    }
#endif

#ifdef OKPRINTER
                    case MYPRINTER1ADDR :
                    case MYPRINTER2ADDR :
                    case MYPRINTER6ADDR :
                    {
                      switch ((LE_WORD(setup->sd_Value) >> 8) & 0xff)
                      {
                        case USBDESC_DEVICE :
                        {
                          ret = copydata(ior, (dvnum==MYPRINTER6ADDR)?pr6_dd:pr_dd, eplen) ;
                          break ;
                        }

                        case USBDESC_CONFIGURATION :
                        {
                          ret = copydata(ior, (dvnum==MYPRINTER6ADDR)?pr6_id:pr_id, eplen) ;
                          break ;
                        }

                        case USBDESC_STRING :
                        {
                          switch ((LE_WORD(setup->sd_Value) >> 0) & 0xff)
                          {
                            case 0 :
                            {
                              MakeString((struct USBIOReq *)ior, "\x09\x04", base) ;
                              break ;
                            }

                            case 1 :
                            {
                              MakeString((struct USBIOReq *)ior,
                                         (dvnum==MYPRINTER1ADDR)?"Lone Printer":
                                         (dvnum==MYPRINTER2ADDR)?"Printer":
                                         (dvnum==MYPRINTER6ADDR)?"HPPSC2210 =)":
                                         "unknown",
                                         base) ;
                              break ;
                            }

                            case 2 :
                            {
                              MakeString((struct USBIOReq *)ior,
                                         (dvnum==MYPRINTER1ADDR)?"Printer":
                                         "unknown", base) ;
                              break ;
                            }

                            case 3 :
                            {
                              MakeString((struct USBIOReq *)ior,
                                         "serial #deadbeef",
                                         base) ;
                              break ;
                            }

                            default :
                            {
                              break ;
                            } 
                          }
                          break ;
                        }
                      }
                      break ;
                    }
#endif
#ifdef OKMASS
                    case MYMASSADDR :
                    {
                      switch ((LE_WORD(setup->sd_Value) >> 8) & 0xff)
                      {
                        case USBDESC_DEVICE :
                        {
                          ret = copydata(ior, mass_dd, eplen) ;
                          break ;
                        }

                        case USBDESC_CONFIGURATION :
                        {
                          ret = copydata(ior, mass_id, eplen) ;
                          break ;
                        }

                        case USBDESC_STRING :
                        {
                          switch ((LE_WORD(setup->sd_Value) >> 0) & 0xff)
                          {
                            case 0 :
                            {
                              MakeString((struct USBIOReq *)ior, "\x09\x04", base) ;
                              break ;
                            }

                            case 1 :
                            {
                              MakeString((struct USBIOReq *)ior, "masstoc", base) ;
                              break ;
                            }

                            case 2 :
                            {
                              MakeString((struct USBIOReq *)ior, "thumb", base) ;
                              break ;
                            }

                            case 3 :
                            {
                              MakeString((struct USBIOReq *)ior, "serial #deadbeef", base) ;
                              break ;
                            }

                            default :
                            {
                              break ;
                            } 
                          }
                          break ;
                        }
                      }
                      break ;
                    }
#endif
#ifdef OKPTP
                    case MYPTPADDR :
                    {
                      switch ((LE_WORD(setup->sd_Value) >> 8) & 0xff)
                      {
                        case USBDESC_DEVICE :
                        {
                          ret = copydata(ior, ptp_dd, eplen) ;
                          break ;
                        }

                        case USBDESC_CONFIGURATION :
                        {
                          ret = copydata(ior, ptp_id, eplen) ;
                          break ;
                        }

                        case USBDESC_STRING :
                        {
                          switch ((LE_WORD(setup->sd_Value) >> 0) & 0xff)
                          {
                            case 0 :
                            {
                              MakeString((struct USBIOReq *)ior, "\x09\x04", base) ;
                              break ;
                            }

                            case 1 :
                            {
                              MakeString((struct USBIOReq *)ior,
                                         "PTP",
                                         base) ;
                              break ;
                            }

                            case 2 :
                            {
                              MakeString((struct USBIOReq *)ior,
                                         "PTP of the death", base) ;
                              break ;
                            }

                            case 3 :
                            {
                              MakeString((struct USBIOReq *)ior,
                                         "serial #deadbeef",
                                         base) ;
                              break ;
                            }

                            default :
                            {
                              break ;
                            } 
                          }
                          break ;
                        }
                      }
                      break ;
                    }
#endif
                  }
                  break ;
                }

                case USBREQC_GET_CONFIGURATION : /* 8 GET_CONFIGURATION */
                {
                  switch (dvnum)
                  {
                    case 0 :
                    {
#ifdef OKHOSTDLL
                      ior->io_Error = USB_control_msg(ior, hdev, hdevhandle, base) ;
#if TRACE
                      MyTrace("Getconfiguration [0]\n") ;
#endif
#endif
                      break ; 
                    }

                    case MYHUBADDR : /* hub */
                    {
                      char data[1] ;
                      data[0] = base->hcd_Unit.hub_config ;
                      ret = copydata(ior, data, eplen) ;  

                      //sprintf(cTxt, "GetConfig %ld %ld\n",
                      //        dvnum,
                      //        base->hcd_Unit.hub_config) ;
                      //MyTrace(cTxt) ;   
                      break ;
                    }
#ifdef OKMOUSE
                    case MYMOUSEADDR : /* mouse */
                    {
                      char data[1] ;
                      data[0] = base->hcd_Unit.mouse_config ;
                      ret = copydata(ior, data, eplen) ;     
                      break ;
                    }
#endif
#ifdef OKPRINTER
                    case MYPRINTER1ADDR : /* printer */
                    {
                      char data[1] ;
                      data[0] = base->hcd_Unit.printer1_config ;
                      ret = copydata(ior, data, eplen) ;     
                      break ;
                    }
#endif
#ifdef OKPRINTER
                    case MYPRINTER2ADDR : /* printer */
                    {
                      char data[1] ;
                      data[0] = base->hcd_Unit.printer2_config ;
                      ret = copydata(ior, data, eplen) ;     
                      break ;
                    }
#endif
#ifdef OKPSC2200
                    case MYPRINTER6ADDR : /* printer */
                    {
                      char data[1] ;
                      data[0] = base->hcd_Unit.printer6_config ;
                      ret = copydata(ior, data, eplen) ;     
                      break ;
                    }
#endif
#ifdef OKMASS
                    case MYMASSADDR : /* thumb */
                    {
                      char data[1] ;
                      data[0] = base->hcd_Unit.mass_config ;
                      ret = copydata(ior, data, eplen) ;     
                      break ;
                    }
#endif
#ifdef OKPTP
                    case MYPTPADDR : /* PTP */
                    {
                      char data[1] ;
                      data[0] = base->hcd_Unit.ptp_config ;
                      ret = copydata(ior, data, eplen) ;     
                      break ;
                    }
#endif
                  }  
                  break ;
                }

                case 0xfe :
                {
                  switch (dvnum)
                  {
                    case 0 :
                    {
#ifdef OKHOSTDLL
                      ior->io_Error = USB_control_msg(ior, hdev, hdevhandle, base) ;
                      if (ior->io_Error != 0)
                      {
                        /* Allez, soyons bon prince... */
                        if ((ior->io_Data != NULL) && (ior->io_Length > 0))
                        {
                          memset(ior->io_Data, 0, ior->io_Length) ;
                          ior->io_Actual = ior->io_Length ;
                          ior->io_Error = 0 ;
                        }
                      }
#else
                      ior->io_Error = -33 ;
#endif
#if TRACE
                      MyTrace("Getmaxlun [0]\n") ;
#endif
                      break ;
                    }

                    case MYPRINTER6ADDR :
                    case MYMASSADDR     : /* Sometimes not */
                    {
                      char data[1] ;
                      data[0] = 0 ;

                      /* get max lun */
                      ior->io_Error = 0 ;
                      ret = copydata(ior, data, eplen) ;
                      break ;
                    }

                    default :
                    {
                      ior->io_Error = -33 ;
                      break ;
                    }
                  }
                  break ;
                }

                default :
                {
#ifdef OKHOSTDLL
                  ior->io_Error = USB_control_msg(ior, hdev, hdevhandle, base) ;
#if TRACE
                  MyTrace("Getdefault [0]\n") ;
#endif
#else
                  ior->io_Error = -33 ;
#endif
                  break ;
                }
              }
              break ;
            }

            case CMD_WRITE :
            {     
              switch (setup->sd_Request)
              {
                case USBREQC_CLEAR_FEATURE : /* 1 CLEAR_FEATURE */
                {
                  switch (dvnum)
                  {
                    case 0 :
                    {
#ifdef OKHOSTDLL
                      if ((setup->sd_Value == 0x00) && (setup->sd_RequestType == 0x02))
                      {
                        int liberr = 0;

#if LIBUSBX
                        liberr = libusb_clear_halt(hdevhandle, (LE_WORD(setup->sd_Index) & 0xff)) ;
                        if (liberr < 0)
                        {
                          ior->io_Error = -33 ;
                        }
                        else
                        {
                          ior->io_Error = 0 ;
                        }
#else
                        liberr = usb_clear_halt(hdevhandle, (LE_WORD(setup->sd_Index) & 0xff)) ;
                        
                        if (liberr < 0)
                        {
                          ior->io_Error = -33 ;
                        }
                        else
                        {
                          ior->io_Error = 0 ;
                        }
#endif
                        
#if TRACE
                        if (1)
                        {
                          char cBuf[80] ;

                          sprintf(cBuf, "usb_clear_halt(%08lx,%02x) => %ld\n", hdevhandle, (LE_WORD(setup->sd_Index) & 0xff), liberr) ;
                          MyTrace(cBuf) ;
                        }
#endif

                      }
                      else
                      {    
                        ior->io_Error = USB_control_msg(ior, hdev, hdevhandle, base) ;
                      }
#if TRACE
                      MyTrace("Clearfeature [0]\n") ;
#endif
#else
                      ior->io_Error = -33 ;
#if TRACE
                      MyTrace("Clearfeature [0]\n") ;
#endif                  
#endif
                      break ;
                    }

                    case MYHUBADDR :
                    {
                      //base->hcd_Unit.hub_config = LE_WORD(setup->sd_Value) ;
                      break ;
                    }

                    case MYPRINTER6ADDR :
                    {
#if TRACE
                      sprintf(cTxt, "ClearFeature %ld %ld %ld\n",
                              epnum,
                              LE_WORD(setup->sd_Value),
                              LE_WORD(setup->sd_Index)) ;
                      MyTrace(cTxt) ;
#endif
                      break ;
                    }
                  }
                  break ;
                }

                case USBREQC_SET_FEATURE : /* 3 SET_FEATURE */
                {
                  switch (dvnum)
                  {
                    case 0 :
                    {
#ifdef OKHOSTDLL
                      ior->io_Error = USB_control_msg(ior, hdev, hdevhandle, base) ;
#if TRACE
                      MyTrace("Setfeature [0]\n") ;
#endif
#else
                      ior->io_Error = -33 ;
#if TRACE
                      MyTrace("Setfeature [0]\n") ;
#endif                 
#endif
                      break ; 
                    }

                    case MYHUBADDR :
                    {
                      ior->io_Error = 0 ;
                      switch (setup->sd_RequestType)
                      {
                        case 0x23 :
                        {
                          switch (LE_WORD(setup->sd_Value))
                          {
                            case USBFEAT_HUB_PORT_POWER : /* 8 */
                            {
                              int portnum ;

                              portnum = LE_WORD(setup->sd_Index) ;
                              switch(portnum)
                              {
                                case  1 :
                                case  2 :
                                case  3 :
                                case  4 :
                                case  5 :
                                case  6 :
                                case  7 :
                                case  8 :
                                case  9 :
                                case 10 :
                                {
                                  base->hcd_Unit.hub_port[portnum] = 0x00010000 ;
                                  break ;
                                }

        
                              }
                              break ;
                            }

                            case USBFEAT_HUB_C_PORT_CONNECTION : /* 16 */
                            case USBFEAT_HUB_C_PORT_RESET : /* 20 */
                            {
                              break ;
                            }
                          }
                          break ;
                        }
                      }
                      break ;
                    }
                  }
                  break ;
                }

                case USBREQC_SET_ADDRESS : /* 5 SET_ADDRESS */
                {
                  ior->io_Error = 0 ;

#if TRACE
                  if (1)
                  {
                    char buf[180] ;
                    
                    sprintf(buf, "SetAddress() dev=0x%08lx %ld [%ld %ld %ld]\n",
                            device,
                            dvnum,
                            base->hcd_Unit.dev0step,
                            base->hcd_Unit.dev0steplibusb,
                            base->hcd_Unit.dev0maxlibusb) ;
                    MyTrace(buf) ;
                  }
#endif

                  if (base->hcd_Unit.dev0maxlibusb > 0)
                  {
                    if (base->hcd_Unit.dev0step == 0)
                    {
                      /* root hub */
                      AP_SetAttrs(ATYPE_DEVICE, (struct Node *)device,
                                  USBA_Data1, MYHUBADDR /*base->hcd_Unit.dev0step*/,
                                  USBA_Data2, 0,
                                  USBA_Data3, 0,
                                  TAG_DONE) ;

#if TRACE
                      if (1)
                      {
                        char buf[80] ;
                        ULONG d1, d2, d3 ;

                        AP_GetAttrs(ATYPE_DEVICE, (struct Node *)device,
                                    USBA_Data1, &d1,
                                    USBA_Data2, &d2,
                                    USBA_Data3, &d3,
                                    TAG_DONE) ;
                        sprintf(buf, "SetAddressA() [%08lx %08lx %08lx]\n", d1, d2, d3) ;
                        MyTrace(buf) ;
                      }
#endif
                      base->hcd_Unit.dev0step = MYHUBADDR ;
                      base->hcd_Unit.dev0step ++ ;
                    }
                    else
                    {
#ifdef OKHOSTDLL
                      if (base->hcd_Unit.dev0steplibusb < base->hcd_Unit.dev0maxlibusb)
                      {
                        /* libusb devices */
                        AP_SetAttrs(ATYPE_DEVICE, (struct Node *)device,
                                    USBA_Data1, 0,
                                    USBA_Data2, (ULONG)getdev(base, base->hcd_Unit.dev0steplibusb),
                                    USBA_Data3, 0,
                                    TAG_DONE) ;

#if TRACE
                        if (1)
                        {
                          char buf[80] ;
                          ULONG d1, d2, d3 ;

                          AP_GetAttrs(ATYPE_DEVICE, (struct Node *)device,
                                      USBA_Data1, &d1,
                                      USBA_Data2, &d2,
                                      USBA_Data3, &d3,
                                      TAG_DONE) ;

                          sprintf(buf, "SetAddressB() [%08lx %08lx %08lx]\n", d1, d2, d3) ;
                          MyTrace(buf) ;
                        }
#endif
                        base->hcd_Unit.dev0steplibusb ++ ;
                      }
                      else
#endif
                      {
                        /* other devices */
                        AP_SetAttrs(ATYPE_DEVICE, (struct Node *)device,
                                    USBA_Data1, base->hcd_Unit.dev0step,
                                    USBA_Data2, 0,
                                    USBA_Data3, 0,
                                    TAG_DONE) ;
#if TRACE
                        if (1)
                        {
                          char buf[80] ;
                          ULONG d1, d2, d3 ;

                          AP_GetAttrs(ATYPE_DEVICE, (struct Node *)device,
                                      USBA_Data1, &d1,
                                      USBA_Data2, &d2,
                                      USBA_Data3, &d3,
                                      TAG_DONE) ;
                          sprintf(buf, "SetAddressC() [%08lx %08lx %08lx]\n", d1, d2, d3) ;
                          MyTrace(buf) ;
                        }
#endif

                        base->hcd_Unit.dev0step ++ ;
                      }
                    }
                  }
                  else
                  {
                    base->hcd_Unit.dev0step ++ ;

                    AP_SetAttrs(ATYPE_DEVICE, (struct Node *)device,
                                USBA_Data1, base->hcd_Unit.dev0step,
                                USBA_Data2, 0,
                                USBA_Data3, 0,
                                TAG_DONE) ;
                  
#if TRACE
                    if (1)
                    {
                      char buf[80] ;
                      ULONG d1, d2, d3 ;

                      AP_GetAttrs(ATYPE_DEVICE, (struct Node *)device,
                                  USBA_Data1, &d1,
                                  USBA_Data2, &d2,
                                  USBA_Data3, &d3,
                                  TAG_DONE) ;
                      sprintf(buf, "SetAddressD() [%08lx %08lx %08lx]\n", d1, d2, d3) ;
                      MyTrace(buf) ;
                    }
#endif

                    /* oupss on n'itere pas ici */   
                  }  
                  break ;
                }

                case USBREQC_SET_CONFIGURATION : /* 9 SET_CONFIGURATION */
                {
                  ior->io_Error = 0 ;
                  switch (dvnum)
                  {
                    case 0 :
                    {
#ifdef OKHOSTDLL
                      if ((setup->sd_Index  == 0) && 
                          (setup->sd_Length == 0))
                      {
                        if (hdev != NULL)
                        {
                          int configuration = LE_WORD(setup->sd_Value) ;

                          if (hdevhandle == NULL)
                          {
                            hdevhandle = USB_open(hdev) ;

                            AP_SetAttrs(ATYPE_DEVICE, device,
                                        USBA_Data3, hdevhandle,
                                        TAG_DONE) ;

#if LIBUSBX
                            if (hdevhandle != NULL)
                            {
                              //long speed = libusb_get_device_speed(hdevhandle) ;
                              //AP_SetAttrs(ATYPE_DEVICE, device,
                              //            USBA_DeviceSpeed, speed+1,
                              //            TAG_DONE) ;
#if TRACE
                              //if (1)
                              //{
                              //  char cBuf[80] ;
                              //
                              //  sprintf(cBuf, "Set speed %08lx %ld\n", device, speed+1) ;
                              //  MyTrace(cBuf) ;
                              //}
#endif
                            }
#endif
                          }

                          if (hdevhandle != NULL)
                          {
                            int liberr ;

#if LIBUSBX
#else
                            liberr = usb_set_configuration(hdevhandle, configuration) ;
#endif
#if TRACE
                            if (1)
                            {
                              char cBuf[80] ;
#if LIBUSBX
#else
                              sprintf(cBuf, "usb_set_configuration(%08lx,%ld) => %ld (hdev=%08lx)\n",
                                      hdevhandle,
                                      configuration,
                                      liberr,
                                      hdev) ;
#endif
                              MyTrace(cBuf) ;
                            }
#endif
                          }
                          else
                          {
#if TRACE
                            if (1)
                            {
                              char cBuf[80] ;

                              sprintf(cBuf, "Setconfiguration(%ld) hdev=%08lx failed\n",
                                      configuration,
                                      hdev) ;
                              MyTrace(cBuf) ;
                            }
#endif
                          }
                        }
                      }
                      else
                      {
                        ior->io_Error = USB_control_msg(ior, hdev, hdevhandle, base) ;
                      }
#else
#if TRACE
                      MyTrace("Setconfiguration [0] !!!!!\n") ;
#endif
#endif

                      break ;
                    }

                    case MYHUBADDR :
                    {
                      base->hcd_Unit.hub_config = LE_WORD(setup->sd_Value) ;
     
                      //sprintf(cTxt, "SetConfig %ld %ld\n",
                      //        dvnum,
                      //        base->hcd_Unit.hub_config) ;
                      //MyTrace(cTxt) ;
                      break ;
                    }

#ifdef OKMOUSE
                    case MYMOUSEADDR :
                    {
                      base->hcd_Unit.mouse_config = LE_WORD(setup->sd_Value) ;
                      break ;
                    }
#endif
#ifdef OKPRINTER
                    case MYPRINTER1ADDR :
                    {
                      base->hcd_Unit.printer1_config = LE_WORD(setup->sd_Value) ;
                      break ;
                    }
#endif
#ifdef OKPRINTER
                    case MYPRINTER2ADDR :
                    {
                      base->hcd_Unit.printer2_config = LE_WORD(setup->sd_Value) ;
                      break ;
                    }
#endif
#ifdef OKPSC2200
                    case MYPRINTER6ADDR :
                    {
                      base->hcd_Unit.printer6_config = LE_WORD(setup->sd_Value) ;
                      break ;
                    }
#endif
#ifdef OKMASS
                    case MYMASSADDR :
                    {
                      base->hcd_Unit.mass_config = LE_WORD(setup->sd_Value) ;
                      break ;
                    }
#endif
#ifdef OKPTP
                    case MYPTPADDR :
                    {
                      base->hcd_Unit.ptp_config = LE_WORD(setup->sd_Value) ;
                      break ;
                    }
#endif
                  }
                  break ;
                }

                case USBREQC_SET_INTERFACE : /* 11 SET_INTERFACE */
                {
                  ior->io_Error = 0 ;
                  switch (dvnum)
                  {
                    case 0 :
                    {
#ifdef OKHOSTDLL
                      if (hdev != NULL)
                      {
                        int altsetting = LE_WORD(setup->sd_Value) ;
                        int internum   = LE_WORD(setup->sd_Index) ;
                        ULONG claimed ;
                        ULONG configured ;

                        AP_GetAttrs(ATYPE_DEVICE, device,
                                    USBA_Configured, &configured,
                                    TAG_DONE) ;

                        if (hdevhandle == NULL)
                        {
                          hdevhandle = USB_open(hdev) ;

                          AP_SetAttrs(ATYPE_DEVICE, device,
                                      USBA_Data3, hdevhandle,
                                      TAG_DONE) ;
                        }


                        AP_GetAttrs(ATYPE_INTERFACE, interf,
                                    USBA_Claimed, &claimed,
                                    TAG_DONE) ;

                        if (hdevhandle != NULL)
                        {
                          int liberr = 0 ;

                          if (claimed == 0)
                          {
#if LIBUSBX
#else
                            liberr = usb_claim_interface(hdevhandle, internum) ;
#endif
                            if (liberr == 0)
                            {
                              claimed = TRUE ;
                              AP_SetAttrs(ATYPE_INTERFACE, interf,
                                          USBA_Claimed, claimed,
                                          TAG_DONE) ;
                            }
                          }

#if TRACE
                          if (1)
                          {
                            char cBuf[280] ;
#if LIBUSBX
                            sprintf(cBuf, "libusb_claim_interface(%08lx,%ld) => %ld (hdev=%08lx handle=%08lx %ld %ld)\n",
                                    hdevhandle,
                                    internum,
                                    liberr,
                                    hdev,
                                    hdevhandle,
                                    claimed, configured) ;
#else
                            sprintf(cBuf, "usb_claim_interface(%08lx,%ld) => %ld (hdev=%08lx handle=%08lx %ld %ld)\n",
                                    hdevhandle,
                                    internum,
                                    liberr,
                                    hdev,
                                    hdevhandle,
                                    claimed, configured) ;
#endif
                            MyTrace(cBuf) ;
                          }
#endif

                          liberr = USB_set_altinterface(hdevhandle, internum, altsetting) ;
#if TRACE
                          if (1)
                          {
                            char cBuf[280] ;
#if LIBUSBX
                            sprintf(cBuf, "libusb_set_interface_alt_setting(%08lx,%ld,%ld) => %ld (hdev=%08lx handle=%08lx)\n",
                                    hdevhandle,
                                    internum,
                                    altsetting,
                                    liberr,
                                    hdev,
                                    hdevhandle) ;
#else
                            sprintf(cBuf, "usb_set_altinterface(%08lx,%ld) => %ld (hdev=%08lx handle=%08lx)\n",
                                    hdevhandle,
                                    altsetting,
                                    liberr,
                                    hdev,
                                    hdevhandle) ;
#endif
                            MyTrace(cBuf) ;
                          }
#endif
                        }
                        else
                        {
#if TRACE
                          if (1)
                          {
                            char cBuf[80] ;

                            sprintf(cBuf, "Setinterface(%ld,%ld) hdev=%08lx failed\n",
                                    internum,
                                    altsetting,
                                    hdev) ;
                            MyTrace(cBuf) ;
                          }
#endif
                        }
                      }
#else
#if TRACE
                      MyTrace("SetInterface [0] !!!!!\n") ;
#endif
#endif
                      break ;
                    }

                    case MYHUBADDR :
                    {
                      base->hcd_Unit.hub_altsetting = LE_WORD(setup->sd_Value) ;
                      base->hcd_Unit.hub_interface  = LE_WORD(setup->sd_Index) ;
                      break ;
                    }
#ifdef OKMOUSE
                    case MYMOUSEADDR :
                    {
                      base->hcd_Unit.mouse_altsetting  = LE_WORD(setup->sd_Value) ;
                      base->hcd_Unit.mouse_interface   = LE_WORD(setup->sd_Index) ;
                      break ;
                    }
#endif
#ifdef OKPRINTER
                    case MYPRINTER1ADDR :
                    {
                      base->hcd_Unit.printer1_altsetting = LE_WORD(setup->sd_Value) ;
                      base->hcd_Unit.printer1_interface  = LE_WORD(setup->sd_Index) ;

                      //sprintf(cTxt, "SetInterface %ld %ld %ld\n",
                      //        dvnum,
                      //        base->hcd_Unit.printer1_altsetting,
                      //        base->hcd_Unit.printer1_interface) ;
                      //MyTrace(cTxt) ;
                      break ;
                    }
#endif
#ifdef OKPRINTER
                    case MYPRINTER2ADDR :
                    {
                      base->hcd_Unit.printer2_altsetting = LE_WORD(setup->sd_Value) ;
                      base->hcd_Unit.printer2_interface  = LE_WORD(setup->sd_Index) ;

                      //sprintf(cTxt, "SetInterface %ld %ld %ld\n",
                      //        dvnum,
                      //        base->hcd_Unit.printer2_altsetting,
                      //        base->hcd_Unit.printer2_interface) ;
                      //MyTrace(cTxt) ;
                      break ;
                    }
#endif
#ifdef OKPSC2200
                    case MYPRINTER6ADDR :
                    {
                      base->hcd_Unit.printer6_altsetting = LE_WORD(setup->sd_Value) ;
                      base->hcd_Unit.printer6_interface  = LE_WORD(setup->sd_Index) ;

                      //sprintf(cTxt, "SetInterface %ld %ld %ld\n",
                      //        dvnum,
                      //        base->hcd_Unit.printer6_altsetting,
                      //        base->hcd_Unit.printer6_interface) ;
                      //MyTrace(cTxt) ;
                      break ;
                    }
#endif
#ifdef OKMASS
                    case MYMASSADDR :
                    {
                      base->hcd_Unit.mass_altsetting = LE_WORD(setup->sd_Value) ;
                      base->hcd_Unit.mass_interface  = LE_WORD(setup->sd_Index) ;

                      //sprintf(cTxt, "SetInterface %ld %ld %ld\n",
                      //        dvnum,
                      //        base->hcd_Unit.mass_altsetting,
                      //        base->hcd_Unit.mass_interface) ;
                      //MyTrace(cTxt) ;
                      break ;
                    }
#endif
#ifdef OKPTP
                    case MYPTPADDR :
                    {
                      base->hcd_Unit.ptp_altsetting = LE_WORD(setup->sd_Value) ;
                      base->hcd_Unit.ptp_interface  = LE_WORD(setup->sd_Index) ;

                      //sprintf(cTxt, "SetInterface %ld %ld %ld\n",
                      //        dvnum,
                      //        base->hcd_Unit.ptp_altsetting,
                      //        base->hcd_Unit.ptp_interface) ;
                      //MyTrace(cTxt) ;
                      break ;
                    }
#endif
                  }
                  break ;
                }

                case 0xff :
                {
                  switch (dvnum)
                  {
                    case 0 :
                    {
#ifdef OKHOSTDLL

                      /* CODE TO DO RESET */
                      //ior->io_Error = USB_control_msg(ior, hdev, hdevhandle, base) ;

                      ior->io_Error = 0 ;
#if TRACE
                      MyTrace("Set 0xff [0]\n") ;
#endif
#else
                      ior->io_Error = -33 ;
#if TRACE
                      MyTrace("Set 0xff [0]\n") ;
#endif                 
#endif
                      break ;
                    }

                    case MYPRINTER6ADDR :
                    case MYMASSADDR     :
                    {
                      /* reset */
#if TRACE
                      MyTrace("scsi reset\n") ;
#endif
                      base->hcd_Unit.mass_state = 0 ;
                      ior->io_Error = 0 ;
                      break ;
                    }

                    default :
                    {
                      ior->io_Error = -33 ;
                      break ;
                    }
                  }
                  break ;
                }

                default :
                {
#ifdef OKHOSTDLL
                  ior->io_Error = USB_control_msg(ior, hdev, hdevhandle, base) ;
#if TRACE
                  MyTrace("Setdefault [0]\n") ;
#endif
#else
                  ior->io_Error = -33 ;
#if TRACE
                  MyTrace("Setdefault [0]\n") ;
#endif                 
#endif
                  break ;
                }
              }
              break ;	
            }
          }
        }

        switch (ior->io_Command)
        {
          case CMD_READ :
          {
            num.lo = 1 ;
            num.hi = 0 ;
            AP_Add64(&num, &base->hcd_Unit.audit.ReadPackets) ;

            num.lo = ior->io_Actual - actual ;
            num.hi = 0 ;
            AP_Add64(&num, &base->hcd_Unit.audit.ReadBytes) ;
            break ;
          }

          case CMD_WRITE :
          {
            num.lo = 1 ;
            num.hi = 0 ;
            AP_Add64(&num, &base->hcd_Unit.audit.SendPackets) ;

            num.lo = ior->io_Actual - actual ;
            num.hi = 0 ;
            AP_Add64(&num, &base->hcd_Unit.audit.SendBytes) ;
            break ;
          }
        }

#if TRACE
        if (traceit)
        {
          if ((ior->io_Data != NULL) && (ior->io_Length > 0))
          {
            sprintf(cTxt, "<%s,DEV%ld,EP%ld>", 
                    (ior->io_Command==CMD_READ)?"IN":"OUT",
                    dvnum, epnum & 0x0f) ;
            MyTrace(cTxt) ;
       
            if (ior->io_Error == 0)
            {
              MyTrace("<DATAx[") ;
              for ( c = (UBYTE *)ior->io_Data + actual ;
                    c < (UBYTE *)ior->io_Data + ior->io_Actual ;
                    c++ )
              {
                sprintf(cTxt, "%02lx", (ULONG) *c) ;
                MyTrace(cTxt) ;
              }
              MyTrace("]>") ;
              MyTrace(AckTxt) ;
            }
            else
            {
              sprintf(cTxt, "<%ld>", ior->io_Error) ;
              MyTrace(cTxt) ; 
            }
            MyTrace(LFTxt) ;
          }
        }
#endif

        if (ior->io_Error == 0)
        {
          ret = FALSE ;
          if (ior->io_Length == 0)
          {
            phase = USB_STATUS_PHASE ;
          }
          else
          {
            if (ior->io_Actual == 0)
            {
              /* nothing */
              ret = TRUE ;
            }
            else
            {
              if (ior->io_Actual < ior->io_Length)
              {
                phase = USB_DATA_PHASE ;
              }
              else
              {
                if ((ior->io_SetupData != NULL) && (ior->io_SetupLength > 0))
                {
                  phase = USB_STATUS_PHASE ;
                }
                else
                {
                  ret = TRUE ;
                }
              }
            }
          }
        }
        else
        {
          ret = TRUE ;
        }
        break ;
      }

      case USB_STATUS_PHASE :
      {
        switch (ior->io_Command)
        {
          case CMD_READ :
          {
            num.lo = 1 ;
            num.hi = 0 ;
            AP_Add64(&num, &base->hcd_Unit.audit.SendPackets) ;

            //num.lo = 0 ;
            //num.hi = 0 ;
            //AP_Add64(&num, &base->hcd_Unit.audit.SendBytes) ;
            break ;
          }

          case CMD_WRITE :
          { 
            num.lo = 1 ;
            num.hi = 0 ;
            AP_Add64(&num, &base->hcd_Unit.audit.ReadPackets) ;

            //num.lo = 0 ;
            //num.hi = 0 ;
            //AP_Add64(&num, &base->hcd_Unit.audit.ReadBytes) ;
            break ;
          }
        }

#if TRACE
        if (traceit)
        {
          switch (ior->io_Command)
          {
            case CMD_READ :
            {
              sprintf(cTxt, "<OUT,DEV%ld,EP%ld><DATA1[]>", dvnum, epnum) ;
              MyTrace(cTxt) ;
              break ;
            }

            case CMD_WRITE :
            {
              sprintf(cTxt, "<IN,DEV%ld,EP%ld><DATA1[]>", dvnum, epnum) ;
              MyTrace(cTxt) ;
              break ;
            }
          }

          switch (ior->io_Error)
          {
            case   0 : MyTrace(AckTxt) ; break ;
            case -32 : MyTrace("<STALL>") ; break ;
            case -33 : MyTrace("<FAIL>") ; break ;
            case -34 : MyTrace("<NAK>") ; break ;
            case -35 : MyTrace("<TIMEOUT>") ; break ;
            case -36 : MyTrace("<OVERFLOW>") ; break ;
            default  : sprintf(cTxt,"<%ld>", ior->io_Error) ; MyTrace(cTxt) ; break ;
          }
          MyTrace(LFTxt) ;
        }
#endif

        phase = 0 ;
        retry = 0 ;
        ret = TRUE ;
        break ;
      }
    }

    if (ret)
    {
      phase = 0 ;
      retry = 0 ;
    }

    phase &= 0x03 ;
    ior->io_Flags &= ~USB_IOF_PHASEMSK ;
    ior->io_Flags |= phase << USB_IOS_PHASESFT ;

    retry &= 0x07 ;
    ior->io_Flags &= ~USB_IOF_RETRYMSK ;
    ior->io_Flags |= retry << USB_IOS_RETRYSFT ;

  }

  return ret ;
}

/***/

void ASM SDS procmainloop(void)
{
  struct HCDBase   *hcdbase  = NULL ;
  struct IOStdReq  *ior      = NULL ;
  struct Task      *me       = NULL ;
  BOOL             loop      = FALSE ;
  BOOL            replyit    = FALSE ;
  struct uhc124Message umsg ;
  struct Library *AnaiisPrivateBase = NULL ;

  Wait(SIGF_SINGLE) ;
  
  me = FindTask(NULL) ;
  hcdbase = me->tc_UserData ;

  AnaiisPrivateBase = hcdbase->AnaiisPrivateBase ;

  SetTaskPri(me, 80) ;

  loop = TRUE ;
  do
  {
    WaitPort(&hcdbase->hcd_Unit.du_Unit.unit_MsgPort) ;

    do
    { 
      ior = (struct IOStdReq *)GetMsg(&hcdbase->hcd_Unit.du_Unit.unit_MsgPort) ;
      if (ior != NULL)
      {
        replyit = TRUE ;
        switch (ior->io_Command)
        {
          case CMD_OpenUnit :
          {
#if TRACE
            MyTrace("OpenUnit>\n") ;
#endif
#if TRACE
            MyTrace("OpenUnit<\n") ;
#endif
            break ;
          }

          case CMD_CloseUnit :
          {
#if TRACE
            MyTrace("CloseUnit>\n") ;
#endif
            memset(&umsg, 0, sizeof(umsg)) ;
            umsg.Command = CMD_STOP ;

            Senduhc124Cmd(hcdbase->hcd_Unit.du_uhc124Port, &umsg) ;

#if TRACE
            MyTrace("CloseUnit<\n") ;
#endif
            loop = FALSE ;
            break ;
          }

          case CMD_CLEAR :
          {
#if TRACE
            MyTrace("Clear>\n") ;
#endif
#if TRACE
            MyTrace("Clear<\n") ;
#endif
            break ;
          }

          case CMD_RESET :
          {
            short i ;
            long  a ;
            char *data ;
            char *c ;
            struct timeval tbeg, tend ;
#if TRACE
            MyTrace("Reset>\n") ;
#endif
            data = AP_AllocVec(2048, MEMF_CLEAR) ;
            if (data != NULL)
            {
              Forbid() ;
              hcdbase->buswidth = 32 ;

              /* read 8 bits access */
              c = data ;
              AP_GetSysTime(&tbeg) ;
              for ( i = 0 ; i < 2048 ; i ++ )
              {
                a = *c++ ;
              }
              AP_GetSysTime(&tend) ;
              AP_SubTime(&tend, &tbeg) ;
              hcdbase->read8 = tend ;

              c = data ;
              a = 0xff ;
              /* write 8 bits access */
              AP_GetSysTime(&tbeg) ;
              for ( i = 0 ; i < 2048 ; i ++ )
              {
                *c++ = a ;
              }
              AP_GetSysTime(&tend) ;
              AP_SubTime(&tend, &tbeg) ;
              hcdbase->write8 = tend ;

              c = data ;
              /* read 16 bits access */
              AP_GetSysTime(&tbeg) ;
              for ( i = 0 ; i < 1024 ; i ++ )
              {
                a = *(UWORD *)c ;
                c += 2 ;
              }
              AP_GetSysTime(&tend) ;
              AP_SubTime(&tend, &tbeg) ;
              hcdbase->read16 = tend ;

              c = data ;
              a = 0xdead ;
              /* write 16 bits access */
              AP_GetSysTime(&tbeg) ;
              for ( i = 0 ; i < 1024 ; i ++ )
              {
                *(UWORD *)c = a ;
                c += 2 ;
              }
              AP_GetSysTime(&tend) ;
              AP_SubTime(&tend, &tbeg) ;
              hcdbase->write16 = tend ;

              c = data ;
              /* read 32 bits access */
              AP_GetSysTime(&tbeg) ;
              for ( i = 0 ; i < 512 ; i ++ )
              {
                a = *(ULONG *)c ;
                c += 4 ;
              }
              AP_GetSysTime(&tend) ;
              AP_SubTime(&tend, &tbeg) ;
              hcdbase->read32 = tend ;

              c = data ;
              a = 0xdeadbeef ;
              /* write 32 bits access */
              AP_GetSysTime(&tbeg) ;
              for ( i = 0 ; i < 512 ; i ++ )
              {
                *(ULONG *)c = a ;
                c += 4 ;
              }
              AP_GetSysTime(&tend) ;
              AP_SubTime(&tend, &tbeg) ;
              hcdbase->write32 = tend ;

              /* read 8 bits access */
              AP_GetSysTime(&tbeg) ;
              AP_USBDelay(200) ;
              AP_GetSysTime(&tend) ;
              AP_SubTime(&tend, &tbeg) ;
              hcdbase->ccread8 = tend ;

              /* write 8 bits access */
              AP_GetSysTime(&tbeg) ;
              AP_USBDelay(220) ;
              AP_GetSysTime(&tend) ;
              AP_SubTime(&tend, &tbeg) ;
              hcdbase->ccwrite8 = tend ;

              /* read 16 bits access */
              AP_GetSysTime(&tbeg) ;
              AP_USBDelay(150) ;
              AP_GetSysTime(&tend) ;
              AP_SubTime(&tend, &tbeg) ;
              hcdbase->ccread16 = tend ;

              /* write 16 bits access */
              AP_GetSysTime(&tbeg) ;
              AP_USBDelay(180) ;
              AP_GetSysTime(&tend) ;
              AP_SubTime(&tend, &tbeg) ;
              hcdbase->ccwrite16 = tend ;

              /* read block */
              AP_GetSysTime(&tbeg) ;
              AP_USBDelay(700) ;
              AP_GetSysTime(&tend) ;
              AP_SubTime(&tend, &tbeg) ;
              hcdbase->ccreadblk = tend ;
 
              /* write block */
              AP_GetSysTime(&tbeg) ;
              AP_USBDelay(800) ;
              AP_GetSysTime(&tend) ;
              AP_SubTime(&tend, &tbeg) ;
              hcdbase->ccwriteblk = tend ;
              Permit() ;

              AP_FreeVec(data) ;
            }

            memset(&umsg, 0, sizeof(umsg)) ;
            umsg.Command = CMD_RESET ;

            Senduhc124Cmd(hcdbase->hcd_Unit.du_uhc124Port, &umsg) ;

#if TRACE
            MyTrace("Reset<\n") ;
#endif
            break ;
          }

          case CMD_READ  :
          case CMD_WRITE :
          {
            replyit = emulUSBIOReq((struct USBIOReqHCD *)ior, hcdbase) ;
            break ;
          }
        }

        if (replyit)
        {
          /* This message can be replied */
          ReplyMsg((struct Message *)ior) ;          
        }
        else
        {
          /* This message is in progress */
          PutMsg(&hcdbase->hcd_Unit.du_Unit.unit_MsgPort, (struct Message *)ior) ;
        }
      }
    } while (ior != NULL) ;
  } while (loop) ;

  Forbid() ;
  hcdbase->hcd_Unit.du_Task = NULL ;
}

void ASM SDS procuhc124loop(void)
{
  struct HCDBase       *hcdbase = NULL ;
  struct uhc124Message *umsg    = NULL ;
  struct Task          *me      = NULL ;
  BOOL                 loop     = FALSE ;
  uint64 num ;
  struct Library *AnaiisPrivateBase = NULL ;

  Wait(SIGF_SINGLE) ;
  Forbid() ;
  me = FindTask(NULL) ;
  hcdbase = me->tc_UserData ;
  AnaiisPrivateBase = hcdbase->AnaiisPrivateBase ;

  SetTaskPri(me, 80) ;

  hcdbase->hcd_Unit.du_uhc124Port = AP_CreateMsgPort() ;

  loop = TRUE ;
  do
  {
    WaitPort(hcdbase->hcd_Unit.du_uhc124Port) ;

    do
    {
      umsg = (struct uhc124Message *)GetMsg(hcdbase->hcd_Unit.du_uhc124Port) ;
      if (umsg != NULL)
      {
        switch (umsg->Command)
        {
          case CMD_STOP :
          {
#if TRACE
            MyTrace(" STOP\n") ;
#endif
            loop = FALSE ;
            break ;
          }

          case CMD_RESET :
          {
            ULONG d ;
            ULONG dh ;
            int i ;

            umsg->Error = 0 ;

            hcdbase->hcd_Unit.dev0step   = 0 ;
#ifdef OKHOSTDLL
            hcdbase->hcd_Unit.dev0steplibusb = 0 ;
#if LIBUSBX
            if (hcdbase->hcd_Unit.libusbx_devs != 0)
            {
              libusb_free_device_list(hcdbase->hcd_Unit.libusbx_devs, 1) ;
              hcdbase->hcd_Unit.libusbx_devs    = 0 ;
              hcdbase->hcd_Unit.libusbx_devscnt = 0 ;
            }

            hcdbase->hcd_Unit.libusbx_devscnt = countdev(&hcdbase->hcd_Unit.libusbx_devs) ;
            hcdbase->hcd_Unit.dev0maxlibusb   = hcdbase->hcd_Unit.libusbx_devscnt ;
            hcdbase->hcd_Unit.dev0maxlibusbok = 0 ;
            for ( i = 0 ; i < hcdbase->hcd_Unit.dev0maxlibusb ; i ++ )
            {
              d = getdev(hcdbase, i) ;
              dh = USB_open(d) ;
              if (dh)
              {
                hcdbase->hcd_Unit.dev0maxlibusbok ++ ;
                USB_close(dh) ;
              }
            }
#else
            hcdbase->hcd_Unit.dev0maxlibusb   = countdev(NULL) ;
            hcdbase->hcd_Unit.dev0maxlibusbok = hcdbase->hcd_Unit.dev0maxlibusb ; 
#endif    
#endif

            hcdbase->hcd_Unit.mass_state = 0 ;
            memset(&hcdbase->hcd_Unit.audit, 0, sizeof(hcdbase->hcd_Unit.audit)) ;

            //hcdbase->hcd_Unit.audit.SendBytes.hi = 0x00000001 ;
            //hcdbase->hcd_Unit.audit.SendBytes.lo = 0x00000000 ;
#if TRACE
            MyTrace(" RESET\n") ;
#endif
#ifdef OKHOSTDLL
#if TRACE
            if (1)
            {
              char buf[50] ;
              sprintf(buf, " #of devs %ld\n", hcdbase->hcd_Unit.dev0maxlibusb) ;
              MyTrace(buf) ;

              for ( i = 0 ; i < hcdbase->hcd_Unit.dev0maxlibusb ; i ++)
              {
                d = getdev(hcdbase, i) ;
                dh = USB_open(d) ;
                if (dh)
                {
                  USB_close(dh) ;
                }
                sprintf(buf, "[%ld] %08lx %s\n", i, d, (dh != 0)?"ok":"KO") ;
                MyTrace(buf) ;
              }
            }
#endif
#endif
            break ;
          }

          case CMD_READ :
          {
            break ;
          }

          case CMD_WRITE :
          {
            break ;
          }
        }
      
        ReplyMsg((struct Message *)umsg) ;
      }
    } while (umsg != NULL) ;
  } while (loop) ;

  do
  {
    umsg = (struct uhc124Message *)GetMsg(hcdbase->hcd_Unit.du_uhc124Port) ;
    if (umsg != NULL)
    {
      ReplyMsg((struct Message *)umsg) ;
    }
  } while (umsg != NULL) ;

  Forbid() ;
  AP_DeleteMsgPort(hcdbase->hcd_Unit.du_uhc124Port) ;
  hcdbase->hcd_Unit.du_uhc124Port = NULL ;
  hcdbase->hcd_Unit.du_uhc124Task = NULL ;
}

