/* SCCSID = "src/dev/usb/UHCI/UHCINIT.C, usb, c.basedd 98/07/10" */
/*
*   Licensed Material -- Property of IBM
*
*   (c) Copyright IBM Corp. 1997, 1998  All Rights Reserved
*/
/************************** START OF SPECIFICATIONS ***************************/
/*                                                                            */
/*   SOURCE FILE NAME:  UHCINIT.C                                             */
/*                                                                            */
/*   DESCRIPTIVE NAME:  UHCI compliant USB Hub device driver initialization   */
/*                      routines.                                             */
/*                                                                            */
/*   FUNCTION: These routines initialize UHCI compliant USB Hub device driver.*/
/*                                                                            */
/*   NOTES:                                                                   */
/*      DEPENDENCIES: None                                                    */
/*      RESTRICTIONS: None                                                    */
/*                                                                            */
/*   ENTRY POINTS:                                                            */
/*             UHCIInit                                                       */
/*                                                                            */
/*   EXTERNAL REFERENCES:                                                     */
/*                                                                            */
/* Change Log                                                                 */
/*                                                                            */
/*  Mark    yy/mm/dd  Programmer      Comment                                 */
/*  ----    --------  ----------      -------                                 */
/*          98/01/31  MB                                                      */
/*                                                                            */
/**************************** END OF SPECIFICATIONS ***************************/

#include "uhci.h"

static BOOL RegisterUHCI(void);
static BOOL BusResourcesUsed(void);

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  UHCIInit                                         */
/*                                                                    */
/* DESCRIPTIVE NAME:  Initializes the UHCi compliant USB Host         */
/*                    device driver.                                  */
/*                                                                    */
/*   FUNCTION: This routine initializes UHCI compliant USB Hub device */
/*             driver:                                                */
/*             1) analyzes BASEDEV= line parameters;                  */
/*             2) searches PCI bus for USB host, driver fails to      */
/*                initialize if USB host not found, disables legacy   */
/*                keyboard support mode;                              */
/*             3) stops USB Host Controller;                          */
/*             4) sets IRQ procesing routine;                         */
/*             5) creates RM driver and adapter reserving I/O base    */
/*                addresses, IRQ numbers.                             */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Initialization time                                       */
/*                                                                    */
/* ENTRY POINT:  UHCIInit                                             */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  pRP-> kernel request packet                                */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  pRPO->CodeEnd = end of code segment                      */
/*           pRPO->DataEnd = end of data segment                      */
/*           pRP->Status = STATUS_DONE                                */
/*           pRP->Status = STDON + STERR + ERROR_I24_GEN_FAILURE      */
/*                                                                    */
/* INTERNAL REFERENCES:  CheckPCI                                     */
/*                       RegisterUHCI                                 */
/*                                                                    */
/* EXTERNAL REFERENCES:  ProcessConfigString                          */
/*                       SetLongValue                                 */
/*                       AddToMsgArray                                */
/*                       setmem                                       */
/*                       DevHelp_TickCount                            */
/*                       DevHelp_AllocateCtxHook                      */
/*                       DevHelp_SetIRQ                               */
/*                       TTYWrite                                     */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
#pragma optimize("eglt", off)
void UHCIInit( RPH FAR *pRP)
{
   PRPINITOUT      pRPO;          /* output request packet far pointer */
   PRPINITIN       pRPI;          /* input request packet far pointer */
   KeyData         keyData[2]={  "V", CFSTR_TYPE_DEC,0,0,
                                 "FS",CFSTR_TYPE_DEC,0,0  };
   PSZ             cmdLine;
   ULONG           cmdRStatus, errColumn;
   USHORT          cmdRc;
   USHORT          timerOffset=0;

#ifdef   DEBUG
   dsPrint(DBG_HLVLFLOW, "UHCI: UHCIInit started\r\n");
#endif

   pRP->Status = STATUS_DONE;
   if (ghDriver)   // already initialized
      return;

   pRPI = (PRPINITIN) pRP;
   pRPO = (PRPINITOUT) pRP;

   Device_Help = ((PRPINITIN)pRP)->DevHlpEP;  /* save devhlp entry point */

   // process CONFIG.SYS BASEDEV= line parameters
   cmdLine=(PSZ) MAKEP( SELECTOROF(pRPI->InitArgs),
                        OFFSETOF(((PDDD_PARM_LIST)pRPI->InitArgs)->cmd_line_args) );
   cmdRStatus=ProcessConfigString(cmdLine, sizeof(keyData)/sizeof(keyData[0]), (KeyData FAR *)&keyData);
   cmdRc=LOUSHORT(cmdRStatus); errColumn=(ULONG)HIUSHORT(cmdRStatus);
   switch (cmdRc)  // set cmd line processing errors
   {
   case CFSTR_UNKWN_KEYS:
      SetLongValue( gVMessages[INIT_MESSAGE_UNKNOWNKWD], errColumn );
      gMessageCount=AddToMsgArray( gMessageIDs, INIT_MESSAGE_UNKNOWNKWD, gMessageCount, MAX_INIT_MESSAGE_COUNT );
      break;
   case CFSTR_CONVERR:
      SetLongValue( gVMessages[INIT_MESSAGE_INVNUMERIC], errColumn );
      gMessageCount=AddToMsgArray( gMessageIDs, INIT_MESSAGE_INVNUMERIC, gMessageCount, MAX_INIT_MESSAGE_COUNT );
      break;
   default:
      break;
   }
   gVerbose= keyData[0].keyStatus!=CFSTR_STATUS_NOTFOUND;
   gStopHostOnShutDown= keyData[1].keyStatus!=CFSTR_STATUS_NOTFOUND;

   // search PCI bus for UHCI compliant USB Host Controller(s)
   if (pRP->Status == STATUS_DONE)
   {
      if (CheckPCI())
      {  // if failed set message IDs and return code
         if (gDevicesFound>1)
         {
            gMessageCount=AddToMsgArray( gMessageIDs, INIT_MESSAGE_NOSDEVICE, gMessageCount, MAX_INIT_MESSAGE_COUNT );
            SetLongValue( gVMessages[INIT_MESSAGE_PCISPECS], (ULONG)gPCIMajorVer );
            SetLongValue( gVMessages[INIT_MESSAGE_PCISPECS], (ULONG)gPCIMinorVer );
            SetLongValue( gVMessages[INIT_MESSAGE_PCISPECS], (ULONG)gMaxPCIBuses );
            SetLongValue( gVMessages[INIT_MESSAGE_PCISPECS], (ULONG)gDevicesFound );
            gMessageCount=AddToMsgArray( gMessageIDs, INIT_MESSAGE_PCISPECS, gMessageCount, MAX_INIT_MESSAGE_COUNT );

            pRP->Status = STATUS_DONE | STERR | ERROR_I24_QUIET_INIT_FAIL;
         }
         else
         {
            gMessageCount=AddToMsgArray( gMessageIDs, INIT_MESSAGE_NODEVICE, gMessageCount, MAX_INIT_MESSAGE_COUNT );
            pRP->Status = STATUS_DONE | STERR | STATUS_ERR_UNKCMD;
         }
      }
   }

   // install context thread routines
   if (pRP->Status == STATUS_DONE)
   {
      USHORT         ctxOffset;
      USHORT         rc;

      ctxOffset=(USHORT)(LONG)(UHCICtxHookRtn); // IRQ processing thread
      rc = DevHelp_AllocateCtxHook((NPFN)ctxOffset, &gCTXHookHandle);

      if (!rc)
      {
         ctxOffset=(USHORT)(LONG)(RHubCtxHookRtn); // root hub processing thread
         rc = DevHelp_AllocateCtxHook((NPFN)ctxOffset, &gRHubHookHandle);
      }

      if (!rc)
      {
         ctxOffset=(USHORT)(LONG)(AddIsoHookRtn); // root hub processing thread
         rc = DevHelp_AllocateCtxHook((NPFN)ctxOffset, &gAddIsoHookHandle);
      }

      if (!rc)
      {
         ctxOffset=(USHORT)(LONG)(IsoIRQHookRtn); // root hub processing thread
         rc = DevHelp_AllocateCtxHook((NPFN)ctxOffset, &gIsoIrqHookHandle);
      }

      if (rc)
      {
         pRP->Status = STATUS_DONE | STERR | STATUS_ERR_UNKCMD;
         gMessageCount=AddToMsgArray( gMessageIDs, INIT_MESSAGE_SETCTXFAILED, gMessageCount, MAX_INIT_MESSAGE_COUNT );
#ifdef DEBUG
      dsPrint(DBG_CRITICAL, "UHCI: UHCIInit failed to allocate CTX hook routine(s)\r\n");
#endif
      }
   }

   // stop host controller and set IRQ procesing routine
   if (pRP->Status == STATUS_DONE)
   {
      USHORT         irqOffset;
      USHORT         rc;

      // disable USB host interrupts
      outp16(gusbIntrReg, 0);
      // stop USB Host Controller
      outp16(gusbCmdReg, 0);
      // clear status register to prevent IRQ processing
      outp16(gusbStsReg, UHCI_USBSTS_HALTED | UHCI_USBSTS_HCPE |
          UHCI_USBSTS_HSE | UHCI_USBSTS_RDE | UHCI_USBSTS_USBEI | UHCI_USBSTS_USBI);

      irqOffset=(USHORT)(LONG)(UHCIInterrupt);
      rc = DevHelp_SetIRQ( (NPFN)irqOffset,
                           (USHORT) gusbIRQ,
                           (USHORT) TRUE );
      if(rc)   // if shared IRQ processing fails, try exclusive
      {
         gIRQShared=FALSE;
         rc = DevHelp_SetIRQ( (NPFN)irqOffset,
                              (USHORT) gusbIRQ,
                              (USHORT) FALSE );
      }

      if (rc)
      {
         pRP->Status = STATUS_DONE | STERR | STATUS_ERR_UNKCMD;
         gMessageCount=AddToMsgArray( gMessageIDs, INIT_MESSAGE_SETIRQFAILED, gMessageCount, MAX_INIT_MESSAGE_COUNT );
#ifdef DEBUG
      dsPrint(DBG_CRITICAL, "UHCI: UHCIInit failed to set IRQ routine\r\n");
#endif
      }
   }

   // install timer callback function to serve root hub requests
   if (pRP->Status == STATUS_DONE)
   {
      USHORT         rc;
      USHORT         rootReqIndex;

      setmem((PSZ)&gRootHubRP[0], 0, sizeof(gRootHubRP[0]));
      gRootHubRP[0].rph.Cmd=CMDGenIOCTL;   // IOCTL
      gRootHubRP[0].rph.Status=0;   // mark as processed (free)
      gRootHubRP[0].Category=USB_IDC_CATEGORY_HOST;
      gRootHubRP[0].Function=USB_IDC_FUNCTION_PRCIRQ;
      gRootHubRP[0].ParmPacket=(PVOID)&gRootHubRB[0];
      for (rootReqIndex=1; rootReqIndex<ROOT_MAX_REQ; rootReqIndex++)
      {
         movmem((PSZ)&gRootHubRP[rootReqIndex], (PSZ)&gRootHubRP[0], sizeof(gRootHubRP[rootReqIndex]));
         gRootHubRP[rootReqIndex].ParmPacket=(PVOID)&gRootHubRB[rootReqIndex];
      }

      timerOffset=(USHORT)(LONG)(UHCIRootHubTimer);
      rc = DevHelp_TickCount((NPFN)timerOffset, ROOT_HUB_TIME_INTERVAL);

      if (rc)
      {  // if failed to install timer callback routine set message IDs and return code
         pRP->Status = STATUS_DONE | STERR | STATUS_ERR_UNKCMD;
         gMessageCount=AddToMsgArray( gMessageIDs, INIT_MESSAGE_SETTMEFAILED, gMessageCount, MAX_INIT_MESSAGE_COUNT );
#ifdef DEBUG
      dsPrint(DBG_CRITICAL, "UHCI: UHCIInit failed to set timer routine\r\n");
#endif
      }
      else
         timerOffset=0;
   }

   /*---------------------------------------------------*/
   /* Register device driver with resource manager      */
   /*---------------------------------------------------*/
   if (pRP->Status == STATUS_DONE)
      RegisterUHCI();

   if (pRP->Status == STATUS_DONE)
   {
      // change driver's name if several instances loaded
      if (gDevicesFound>1)
         gDevName[6]=(UCHAR)('0'+gDevicesFound);

      pRPO->CodeEnd = ((USHORT) &UHCIInit) - 1;       /* set end of code segment */
      pRPO->DataEnd = ((USHORT) &gInitDataStart) - 1; /* set end of data segment */

      SetLongValue( gVMessages[INIT_MESSAGE_LOADED], (ULONG)gDriverStruct.MajorVer );
      SetLongValue( gVMessages[INIT_MESSAGE_LOADED], (ULONG)gDriverStruct.MinorVer );
      gMessageCount=AddToMsgArray( gMessageIDs, INIT_MESSAGE_LOADED, gMessageCount, MAX_INIT_MESSAGE_COUNT );

      SetLongValue( gVMessages[INIT_MESSAGE_LOADED_DET0], (ULONG)gBusNum );
      SetLongValue( gVMessages[INIT_MESSAGE_LOADED_DET0], (ULONG)gusbIOBase );
      SetLongValue( gVMessages[INIT_MESSAGE_LOADED_DET0], (ULONG)gusbIRQ );
      gMessageCount=AddToMsgArray( gMessageIDs, INIT_MESSAGE_LOADED_DET0, gMessageCount, MAX_INIT_MESSAGE_COUNT );
   }
   else
   {  //    failed to initialize
      pRPO->CodeEnd = 0;      /* set end of code segment */
      pRPO->DataEnd = 0;      /* set end of data segment */

      // release allocated handles/resources
      DevHelp_UnSetIRQ( (USHORT) gusbIRQ );
      if(timerOffset)
         DevHelp_ResetTimer((NPFN)timerOffset);
      if(gCTXHookHandle)
         DevHelp_FreeCtxHook(gCTXHookHandle);
      if(gRHubHookHandle)
         DevHelp_FreeCtxHook(gRHubHookHandle);
      if(gAddIsoHookHandle)
         DevHelp_FreeCtxHook(gAddIsoHookHandle);
      if(gIsoIrqHookHandle)
         DevHelp_FreeCtxHook(gIsoIrqHookHandle);
   }

   TTYWrite(gVMessages, gMessageIDs, gMessageCount);  // write out console messages

#ifdef   DEBUG
   dsPrint1(DBG_HLVLFLOW,"UHCI: UHCIInit ended. Status=%x\r\n",pRP->Status);
#endif
}
#pragma optimize("", on)

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  CheckPCI                                         */
/*                                                                    */
/* DESCRIPTIVE NAME:  Check PCI bus for UHCI compliant USB host.      */
/*                                                                    */
/*   FUNCTION: This routine searches for UHCI compliant USB host      */
/*             controller on PCI bus using OEMHLP$ driver             */
/*             PCI service calls:                                     */
/*             1) locates OEMHLP$ driver IDC routine address;         */
/*             2) calls OEMHLP$ to get PCI bus count;                 */
/*             3) calls FindPCIDevice to browse bus;                  */
/*             4) reads PCI device registers for UHCI controller;     */
/*             5) disables legacy support if found on.                */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Initialization time                                       */
/*                                                                    */
/* ENTRY POINT:  CheckPCI                                             */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  none                                                       */
/*                                                                    */
/* EXIT-NORMAL: FALSE - UHCI controller found                         */
/*                                                                    */
/* EXIT-ERROR:  TRUE - no UHCI compliant USB controller found on PCI  */
/*                     bus                                            */
/*                                                                    */
/* EFFECTS:  Sets globals gusbIRQ, gusbPIN, gusbIOBase and            */
/*           calculates gusbCmdReg,gusbStsReg,gusbIntrReg,            */
/*           gusbFrnumReg,gusbBaseAddReg,gusbSofModReg,               */
/*           gusbPortSc1Reg,gusbPortSc2Reg when host found            */
/*                                                                    */
/* INTERNAL REFERENCES:  CallOEMHlp                                   */
/*                       FindPCIDevice                                */
/*                                                                    */
/* EXTERNAL REFERENCES:  none                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
BOOL CheckPCI()
{
   BOOL              rc = FALSE;
   RP_GENIOCTL       IOCtlRP;
   PRPH              pRPH = (PRPH)&IOCtlRP;
   PCI_DATA          PCIDataPkt;
   PCI_PARM_FIND_DEV PCIParmPkt;
   UCHAR             usbVersion;
   USHORT            usbVendor;
   USHORT            usbDevice;
   USHORT            usbLegSup;
   ULONG             IOBase;
   UCHAR             hwMech;
   struct
   {
      UCHAR          ucRevision;
      UCHAR          ucProgIF;
      UCHAR          ucSubClass;
      UCHAR          ucBaseClass;
   }                 ConfigReg;

   /* Setup Global OEMHlp Variables */
   if (DevHelp_AttachDD( gOEMDriverName, (NPBYTE)&gDDTable) )
      return (TRUE);    /* Couldn't find OEMHLP's IDC */

   if ((gDDTable.ProtIDCEntry == NULL) || (gDDTable.ProtIDC_DS == 0))
      return (TRUE);    /* Bad Entry Point or Data Segment */

   setmem ( (PBYTE) &PCIDataPkt, 0, sizeof(PCIDataPkt));
   gBusNum=0;
   gDevFunc=0;

   /* Setup Parm Packet */
   PCIParmPkt.PCISubFunc = PCI_GET_BIOS_INFO;

   /* Setup IOCTL Request Packet */
   IOCtlRP.Category = 0x00;
   IOCtlRP.Function = PCI_FUNC;
   IOCtlRP.ParmPacket = (PUCHAR)&PCIParmPkt;
   IOCtlRP.DataPacket = (PUCHAR)&PCIDataPkt;
   IOCtlRP.rph.Len = sizeof(IOCtlRP);
   IOCtlRP.rph.Unit = 0;
   IOCtlRP.rph.Cmd  = CMDGenIOCTL;      /* Generic IOCtl */
   IOCtlRP.rph.Status = 0;

   CallOEMHlp( gDDTable.ProtIDCEntry, gDDTable.ProtIDC_DS, pRPH);

   if (IOCtlRP.rph.Status & STERR)
      rc = TRUE;

   if (PCIDataPkt.bReturn != PCI_SUCCESSFUL)
      rc = TRUE;

   if (!rc)
   {
      gMaxPCIBuses = (UCHAR)(PCIDataPkt.Data_Bios_Info.LastBus + 1);
      gPCIMajorVer = PCIDataPkt.Data_Bios_Info.MajorVer;
      gPCIMinorVer = PCIDataPkt.Data_Bios_Info.MinorVer;
      hwMech = PCIDataPkt.Data_Bios_Info.HWMech;
      rc = FindPCIDevice( gMaxPCIBuses );
   }

   if (!rc) // USB UCHI Compliant Host Controller found
   {
      rc = ReadPCIConfigSpace( gBusNum, gDevFunc, // read USB Host controller interrupt line
                               (UCHAR) PCIREG_INT_LINE,
                               (PULONG) &gusbIRQ, sizeof(gusbIRQ) );
   }

   if (!rc)
      rc = ReadPCIConfigSpace( gBusNum, gDevFunc, // read Host controller's IO base address
                               (UCHAR) PCIREG_USBBA,
                               (PULONG) &IOBase, sizeof(IOBase) );
   if (!rc)
   {
      IOBase&= 0x0000ffe0;
      gusbIOBase=(USHORT)IOBase;
      gusbCmdReg = gusbIOBase + UHCI_IOREGW_USBCMD;         // USB Command register address
      gusbStsReg = gusbIOBase + UHCI_IOREGW_USBSTS;         // USB Status register address
      gusbIntrReg = gusbIOBase + UHCI_IOREGW_USBINTR;       // USB Interrupt Enable register address
      gusbFrnumReg = gusbIOBase + UHCI_IOREGW_FRNUM;        // Frame Number register
      gusbBaseAddReg = gusbIOBase + UHCI_IOREGD_FRBASEADD;  // Frame List Base Address
      gusbSofModReg = gusbIOBase + UHCI_IOREGB_SOFMOD;      // Start of Frame Modify register
      gusbPortSc1Reg = gusbIOBase + UHCI_IOREGW_PORTSC1;    // Port 0 Status & Control
      gusbPortSc2Reg = gusbIOBase + UHCI_IOREGW_PORTSC2;    // Port 1 Status & Control
      rc = ReadPCIConfigSpace( gBusNum, gDevFunc, // get host controller interrupt pin number
                               (UCHAR) PCIREG_INT_PIN,
                               (PULONG) &gusbPIN, sizeof(gusbPIN) );
   }

   if (!rc)
      rc = ReadPCIConfigSpace( gBusNum, gDevFunc,
                               (UCHAR) PCIREG_SBRNUM,
                               (PULONG) &usbVersion, sizeof(usbVersion) );
   if (!rc)
      rc = ReadPCIConfigSpace( gBusNum, gDevFunc,
                               (UCHAR) PCIREG_DEVICE_ID,
                               (PULONG) &usbDevice,
                               sizeof(usbDevice) );
   if (!rc)
      rc = ReadPCIConfigSpace( gBusNum, gDevFunc,
                               (UCHAR) PCIREG_VENDOR_ID,
                               (PULONG) &usbVendor,
                               sizeof(usbVendor) );
   if (!rc)
      rc = ReadPCIConfigSpace( gBusNum, gDevFunc,
                               (UCHAR) PCIREG_CLASS_CODE,
                               (PULONG) &ConfigReg,
                               sizeof(ConfigReg) );
   if (!rc)
      rc = ReadPCIConfigSpace( gBusNum, gDevFunc,
                               (UCHAR) PCIREG_LEGSUP,
                               (PULONG) &usbLegSup,
                               sizeof(usbLegSup) );

   if (!rc)
   {
      if ( (ConfigReg.ucBaseClass == (UCHAR)PCI_SERIAL_BUS_CONTRL) &&
           (ConfigReg.ucSubClass  == (UCHAR)PCI_USB_HCONTROLLER) )
      {
         gRevision = ConfigReg.ucRevision;
      }
      else
         rc=TRUE; // device found has no required characteristics
   }

   if (!rc && usbLegSup&PCI_USBSMIEN)
   {
      usbLegSup&=~PCI_USBSMIEN;     // disable legacy emulation
      usbLegSup|=PCI_USBPIRQDEN;    // USB PIRQ Enable
      rc=WritePCIConfigSpace(  hwMech, gBusNum, gDevFunc,
                               (UCHAR) PCIREG_LEGSUP,
                               (ULONG) usbLegSup, sizeof(usbLegSup) );
   }

#ifdef DEBUG
   if (!rc)
   {
      dsPrint3(DBG_DETAILED, "UHCI: PCI bus count %d, version %d.%d\r\n",(USHORT)gMaxPCIBuses,
               (USHORT)gPCIMajorVer, (USHORT)gPCIMinorVer);
      dsPrint3(DBG_DETAILED, "UHCI: USB I/O base = %x, interrupt line = %d, interrupt pin = %d\r\n", gusbIOBase, (USHORT)gusbIRQ, (USHORT)gusbPIN);
      dsPrint3(DBG_DETAILED, "UHCI: USB version = %d, device ID = %x, vendor ID = %x\r\n", (USHORT)usbVersion, (USHORT)usbDevice, (USHORT)usbVendor);
      dsPrint4(DBG_DETAILED, "UHCI: PCI device BaseClass = %x, SubClass = %x, PI = %x, RID =%x\r\n",
               (USHORT)ConfigReg.ucBaseClass, (USHORT)ConfigReg.ucSubClass,
               (USHORT)ConfigReg.ucProgIF,(USHORT)ConfigReg.ucRevision);
      dsPrint3(DBG_DETAILED, "UHCI: USB bus number %d, DeviceFunction %d, LegSup=%x\r\n",(USHORT)gBusNum,
               (USHORT)gDevFunc, usbLegSup);
   }
#endif

   return ( rc );
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  FindPCIDevice                                    */
/*                                                                    */
/* DESCRIPTIVE NAME:  Registers the HCD device driver resources.      */
/*                                                                    */
/* FUNCTION:  The function of this routine is to locate UHCI compliant*/
/*            USB host on PCI bus.                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Initialization time                                       */
/*                                                                    */
/* ENTRY POINT:  FindPCIDevice                                        */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  UCHAR maxPCIBuses - no of PCI buses                        */
/*                                                                    */
/* EXIT-NORMAL: FALSE - USB Host found on PCI bus                     */
/*                                                                    */
/* EXIT-ERROR:  TRUE - USB host not found on PCI bus                  */
/*                                                                    */
/* EFFECTS:  Fills in gBusNum, gDevFunc                               */
/*                                                                    */
/* INTERNAL REFERENCES:  CallOEMHlp                                   */
/*                       ReadPCIConfigSpace                           */
/*                       CheckResourceUsage                           */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
BOOL NEAR FindPCIDevice( UCHAR maxPCIBuses )
{
   PCI_PARM_FIND_CLASSCODE PCIClassPkt;
   PCI_DATA           PCIDataPkt;
   RP_GENIOCTL        IOCtlRP;     /* From reqpkt.h */
   PRPH               pRPH = (PRPH)&IOCtlRP;
   UCHAR              ucBusNum, ucDevNum, ucIndex = 0, ucFunction;
   UCHAR              rc = TRUE;
   struct
   {
      UCHAR          ucRevision;
      UCHAR          ucProgIF;
      UCHAR          ucSubClass;
      UCHAR          ucBaseClass;
   }                 ConfigReg;

   /* Setup Parm Packet */
   PCIClassPkt.PCISubFunc   = PCI_FIND_CLASS_CODE;
   PCIClassPkt.ClassCode = MAKEULONG(MAKEUSHORT(0,PCI_USB_HCONTROLLER),
                                     MAKEUSHORT(PCI_SERIAL_BUS_CONTRL,PCI_USB_UHCI_PROGIF));
   PCIClassPkt.Index = 0;

   /* Setup IOCTL Request Packet */
   IOCtlRP.Category = 0x00;
   IOCtlRP.Function = PCI_FUNC;
   IOCtlRP.ParmPacket = (PUCHAR)&PCIClassPkt;
   IOCtlRP.DataPacket = (PUCHAR)&PCIDataPkt;
   IOCtlRP.rph.Len = sizeof(IOCtlRP);
   IOCtlRP.rph.Unit = 0;
   IOCtlRP.rph.Cmd  = CMDGenIOCTL;      /* Generic IOCtl */
   IOCtlRP.rph.Status = 0;

   // search for unused UHCI USB host controller
   for (;rc;)
   {
      CallOEMHlp( gDDTable.ProtIDCEntry, gDDTable.ProtIDC_DS, pRPH);

      if ( !(IOCtlRP.rph.Status & STERR) &&
           (PCIDataPkt.bReturn == PCI_SUCCESSFUL) )
      {
         /*
         ** PCI_FIND_DEVICE BIOS function worked so do not need to scan the bus.
         */
         gBusNum  = PCIDataPkt.Data_Find_Dev.BusNum;
         gDevFunc = PCIDataPkt.Data_Find_Dev.DevFunc;
         gDevicesFound++;  // increase found host count

         if (BusResourcesUsed())  // if device already used
         {
            PCIClassPkt.Index++; // search for next one
         }
         else
            rc = FALSE;
      }
      else  // failed to search device
         break;
   }

   if (rc)
   {
      /*
      ** The PCI_FIND_DEVICE BIOS Function is not supported so scan the
      ** bus in attempt to find the device.  DevNum is initialized to -1
      ** so that the search may continue for a another device of
      ** the same vendor and type.
      */
      for ( ucBusNum = 0; ucBusNum < maxPCIBuses; ucBusNum++ )
      {
         for ( ucDevNum = 0; ucDevNum < MAX_PCI_DEVICES; ucDevNum++ )
         {
            for (ucFunction=0; ucFunction<8; ucFunction++)
            {
               gBusNum  = ucBusNum;
               gDevFunc = (UCHAR) (ucDevNum << 3);
               gDevFunc|=ucFunction;
               if ( !(rc = (UCHAR)ReadPCIConfigSpace( gBusNum, gDevFunc,
                                                      (UCHAR) PCIREG_CLASS_CODE,
                                                      (PULONG) &ConfigReg,
                                                      sizeof(ConfigReg) )) )
               {
                  if ( (ConfigReg.ucProgIF == PCI_USB_UHCI_PROGIF) &&    // program interface - UHCI
                       (ConfigReg.ucSubClass == PCI_USB_HCONTROLLER) &&  // universal serial bus
                       (ConfigReg.ucBaseClass == PCI_SERIAL_BUS_CONTRL) )  // serial bus
                  {
                     /* Found it the hard way! */
                     gDevicesFound++;  // increase found host count
                     if (BusResourcesUsed())  // device already used, try next
                        continue;
                     return ( rc );
                  }
               }  /* if( !(rc = ReadPCIConfigSpace( npPCIInfo,... */
            }
         }  /* for( ucDevNum = 0; ucDevNum < MAX_PCI_DEVICES; ucDevNum++ ) */
      }  /* for( ucBusNum = 0; ucBusNum < MaxPCIBuses; ucBusNum++ ) */
      rc = TRUE;

      /*
      ** Scanned the bus "by hand" and still found nothing.
      */
      gBusNum  = 0;
      gDevFunc = -1;
   }

   return ( rc );
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  CallOEMHlp                                       */
/*                                                                    */
/* DESCRIPTIVE NAME:  Call OEM Help routine.                          */
/*                                                                    */
/* FUNCTION:  The function of this routine is to call OEMHlp IDC      */
/*            routine and pass request block address to it.           */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Initialization time                                       */
/*                                                                    */
/* ENTRY POINT:  CallOEMHlp                                           */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  VOID (FAR *pFunctionCall)(VOID) - OEMHlp IDC rtne address  */
/*         USHORT oemHelpDS - OEMHlp rtne DS value                    */
/*         PRPH pRPH - pointer to request block                       */
/*                                                                    */
/* EXIT-NORMAL: none                                                  */
/*                                                                    */
/* EXIT-ERROR:  none                                                  */
/*                                                                    */
/* EFFECTS:  sets error code in pRPH-Status if NULL IDC rtne addr     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
#pragma optimize("eglt", off)
VOID CallOEMHlp( VOID (FAR *pFunctionCall)(VOID), USHORT oemHelpDS, PRPH pRPH )
{
   if (pFunctionCall)
   {
      _asm {push es
         push bx
         push ds
         push di
         push si
         mov  bx, word ptr pRPH[0]
         mov  es, word ptr pRPH[2]
         ;            mov  ds, oemhlpDS
      }

      (*pFunctionCall)();

      _asm {pop si
         pop di
         pop ds
         pop bx
         pop es
      }
   }
   else
   {
      pRPH->Status = STERR + STDON;
   }
}
#pragma optimize("", on)

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  ReadPCIConfigSpace                               */
/*                                                                    */
/* DESCRIPTIVE NAME:  Read PCI Configuration Space routine.           */
/*                                                                    */
/* FUNCTION:  The function of this routine is to read PCI             */
/*            configuration register.                                 */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Initialization time                                       */
/*                                                                    */
/* ENTRY POINT:  ReadPCIConfigSpace                                   */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  UCHAR BusNum - PCI bus number                              */
/*         UCHAR DevFunc - PCI device function                        */
/*         UCHAR ConfigReg - configuration register                   */
/*         PULONG Data - pointer to data buffer                       */
/*         USHORT Size - buffer size (valid values is 1, 2, 4 bytes)  */
/*                                                                    */
/* EXIT-NORMAL: FALSE - register data written                         */
/*                                                                    */
/* EXIT-ERROR:  TRUE - failed to write data                           */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES: CallOEMHlp                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
BOOL NEAR ReadPCIConfigSpace( UCHAR BusNum, UCHAR DevFunc,
                              UCHAR ConfigReg,
                              PULONG Data, USHORT Size )
{

   PCI_PARM_READ_CONFIG PCIParmPkt;
   PCI_DATA             PCIDataPkt;
   RP_GENIOCTL          IOCtlRP;    /* From reqpkt.h */
   PRPH pRPH = (PRPH)&IOCtlRP;

   switch ( Size )
   {
   case 1:
      (UCHAR)*Data = 0;
      break;
   case 2:
      (USHORT)*Data = 0;
      break;
   case 4:
      (ULONG)*Data = 0L;
      break;
   default:
      return (TRUE);
   }

   /* Setup Parm Packet */
   PCIParmPkt.PCISubFunc = PCI_READ_CONFIG;
   PCIParmPkt.BusNum     = BusNum;
   PCIParmPkt.DevFunc    = DevFunc;
   PCIParmPkt.ConfigReg  = ConfigReg;
   PCIParmPkt.Size       = (UCHAR)Size;

   /* Setup IOCTL Request Packet */
   IOCtlRP.Category = 0x00;
   IOCtlRP.Function = PCI_FUNC;
   IOCtlRP.ParmPacket = (PUCHAR)&PCIParmPkt;
   IOCtlRP.DataPacket = (PUCHAR)&PCIDataPkt;
   IOCtlRP.rph.Len = sizeof(IOCtlRP);
   IOCtlRP.rph.Unit = 0;
   IOCtlRP.rph.Cmd  = CMDGenIOCTL;      /* Generic IOCtl */
   IOCtlRP.rph.Status = 0;

   CallOEMHlp( gDDTable.ProtIDCEntry, gDDTable.ProtIDC_DS, pRPH);

   if (IOCtlRP.rph.Status & STERR)
      return ( TRUE );

   if (PCIDataPkt.bReturn != PCI_SUCCESSFUL)
      return ( TRUE );

   switch ( Size )
   {
   case 1:
      (UCHAR)*Data = PCIDataPkt.Data_Read_Config.ucData;
      break;
   case 2:
      (USHORT)*Data = PCIDataPkt.Data_Read_Config.usData;
      break;
   case 4:
      (ULONG)*Data = PCIDataPkt.Data_Read_Config.ulData;
   }

   return ( FALSE );
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  WritePCIConfigSpace                              */
/*                                                                    */
/* DESCRIPTIVE NAME:  Write PCI Configuration Space routine.          */
/*                                                                    */
/* FUNCTION:  The function of this routine is to call OEMHlp IDC      */
/*            routine and pass request block address to it.           */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Initialization time                                       */
/*                                                                    */
/* ENTRY POINT:  WritePCIConfigSpace                                  */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  UCHAR BusNum - PCI bus number                              */
/*         UCHAR DevFunc - PCI device function                        */
/*         UCHAR ConfigReg - configuration register                   */
/*         PULONG Data - pointer to data buffer                       */
/*         USHORT Size - buffer size (valid values is 1, 2, 4 bytes)  */
/*                                                                    */
/* EXIT-NORMAL: FALSE - required data retrieved                       */
/*                                                                    */
/* EXIT-ERROR:  TRUE - failed to read data                            */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES: CallOEMHlp                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
BOOL NEAR WritePCIConfigSpace(  UCHAR HWMech, UCHAR BusNum, UCHAR DevFunc,
                                UCHAR ConfigReg,
                                ULONG Data, UCHAR Size )
{
   BOOL   rc;
   PCI_PARM_WRITE_CONFIG  PCIParmPkt;
   PCI_DATA               PCIDataPkt;
   RP_GENIOCTL            IOCtlRP;    /* From reqpkt.h */
   PRPH pRPH = (PRPH)&IOCtlRP;

   /* Setup Parm Packet */
   PCIParmPkt.PCISubFunc = PCI_WRITE_CONFIG;
   PCIParmPkt.BusNum     = BusNum;
   PCIParmPkt.DevFunc    = DevFunc;
   PCIParmPkt.ConfigReg  = ConfigReg;
   PCIParmPkt.Size       = Size;
   PCIParmPkt.Data       = Data;

   /* Setup IOCTL Request Packet */
   IOCtlRP.Category = 0x00;
   IOCtlRP.Function = PCI_FUNC;
   IOCtlRP.ParmPacket = (PUCHAR)&PCIParmPkt;
   IOCtlRP.DataPacket = (PUCHAR)&PCIDataPkt;
   IOCtlRP.rph.Len = sizeof(IOCtlRP);
   IOCtlRP.rph.Unit = 0;
   IOCtlRP.rph.Cmd  = CMDGenIOCTL;      /* Generic IOCtl */
   IOCtlRP.rph.Status = 0;

   CallOEMHlp( gDDTable.ProtIDCEntry, gDDTable.ProtIDC_DS, pRPH);

   {
      ULONG  ulDataReadBack;

      /*
      ** Read back the value just written and make sure it is same.
      */
      if ( rc = ReadPCIConfigSpace( BusNum, DevFunc, ConfigReg,
                                    &ulDataReadBack, Size ) )
      {
         return ( TRUE );
      }

      switch ( Size )
      {
      case 1 :
         if ( (UCHAR)Data != (UCHAR)ulDataReadBack )
         {
            rc = PciSetReg( HWMech, DevFunc, ConfigReg, Data, Size );
         }
         break;

      case 2 :
         if ( (USHORT)Data != (USHORT)ulDataReadBack )
         {
            rc = PciSetReg( HWMech, DevFunc, ConfigReg, Data, Size );
         }
         break;

      case 4 :
         if ( (ULONG)Data != (ULONG)ulDataReadBack )
         {
            rc = PciSetReg( HWMech, DevFunc, ConfigReg, Data, Size );
         }
         break;

      default:
         if ( Data != ulDataReadBack )
         {
            return ( TRUE );
         }
      } /* end of switch */
   }

   if ( rc )
      return ( TRUE );

   if (IOCtlRP.rph.Status & STERR)
      return ( TRUE );

   if (PCIDataPkt.bReturn != PCI_SUCCESSFUL)
      return ( TRUE );

   return ( FALSE );
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  PciSetRegMech1                                   */
/*                                                                    */
/* DESCRIPTIVE NAME:  Set PCI register.                               */
/*                                                                    */
/* FUNCTION:  The function of this routine is to write PCI            */
/*            configuration register using mechanism 1.               */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Initialization time                                       */
/*                                                                    */
/* ENTRY POINT:  PciSetRegMech1                                       */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  UCHAR DevFunc - PCI device function                        */
/*         UCHAR index - configuration register                       */
/*         ULONG val - data value                                     */
/*         USHORT size - data buffer size (valid values are only      */
/*                       1,2,4 bytes)                                 */
/*                                                                    */
/* EXIT-NORMAL: FALSE - register data written                         */
/*                                                                    */
/* EXIT-ERROR:  TRUE - failed to write data                           */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
#pragma optimize("eglt", off)
void PciSetRegMech1( USHORT regmask, UCHAR index, ULONG val, USHORT size )
{
   register USHORT port;
   UCHAR    byteVal;
   USHORT   wordVal;

   CLI();   // DISABLE
   outp32( PCI_CONFIG_ADDRESS,
           0x80000000 | regmask | (index & 0xfc) );
   port = PCI_CONFIG_DATA + (index & 0x03);

   switch ( size )
   {
   case 1 :
      byteVal=(UCHAR)val;
      outp8(port,byteVal);
      break;
   case 2:
      wordVal=(USHORT)val;
      outp16(port,wordVal);
      break;
   case 4:
      outp32(port,val);
      break;
   default:
      break;
   }
   outp32( PCI_CONFIG_ADDRESS, 0L );
   STI();  // ENABLE
}
#pragma optimize("", on)


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  PciSetRegMech2                                   */
/*                                                                    */
/* DESCRIPTIVE NAME:  Set PCI register.                               */
/*                                                                    */
/* FUNCTION:  The function of this routine is to write PCI            */
/*            configuration register using mechanism 2.               */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Initialization time                                       */
/*                                                                    */
/* ENTRY POINT:  PciSetRegMech2                                       */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  UCHAR DevFunc - PCI device function                        */
/*         UCHAR index - configuration register                       */
/*         ULONG val - data value                                     */
/*         USHORT size - data buffer size (valid values are only      */
/*                       1,2,4 bytes)                                 */
/*                                                                    */
/* EXIT-NORMAL: FALSE - register data written                         */
/*                                                                    */
/* EXIT-ERROR:  TRUE - failed to write data                           */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
#pragma optimize("eglt", off)
void PciSetRegMech2( USHORT regmask, UCHAR index, ULONG val, USHORT size )
{
   register USHORT port;
   UCHAR    byteVal;
   USHORT   wordVal;

   CLI();   // DISABLE
   outp8( PCI_CONFIG_ADDRESS, 0x10 );
   IODelay();
   port = regmask|index;
   switch ( size )
   {
   case 1 :
      byteVal=(UCHAR)val;
      outp8(port,byteVal);
      break;
   case 2:
      wordVal=(USHORT)val;
      outp16(port,wordVal);
      break;
   case 4:
      outp32(port,val);
      break;
   default:
      break;
   }
   IODelay();
   outp8( PCI_CONFIG_ADDRESS, 0x00 );
   STI();  // ENABLE
}
#pragma optimize("", on)


/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  PciSetReg                                        */
/*                                                                    */
/* DESCRIPTIVE NAME:  Set PCI register.                               */
/*                                                                    */
/* FUNCTION:  The function of this routine is to write PCI            */
/*            configuration register.                                 */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Initialization time                                       */
/*                                                                    */
/* ENTRY POINT:  PciSetReg                                            */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  UCHAR HWMech - PCI hardware interface mechanism            */
/*         UCHAR DevFunc - PCI device function                        */
/*         UCHAR ConfigReg - configuration register                   */
/*         ULONG val - data value                                     */
/*         USHORT Size - data buffer size                             */
/*                                                                    */
/* EXIT-NORMAL: FALSE - register data written                         */
/*                                                                    */
/* EXIT-ERROR:  TRUE - failed to write data                           */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES: PciSetRegMech1                                */
/*                      PciSetRegMech2                                */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
BOOL PciSetReg( UCHAR HWMech, UCHAR DevFunc, UCHAR ConfigReg, ULONG val, USHORT size )
{
   USHORT RegMask;

   if ((HWMech & 0x03) == 1)
   {
      /*
       * Use mechnism 1
       */
      RegMask  = ((USHORT)DevFunc) << 8;
      PciSetRegMech1(RegMask,ConfigReg,val,size);
   }
   else if ((HWMech & 0x03) ==  2)
   {
      /*
      * Use mechanism 2
      */
      RegMask = 0xc000 | ((USHORT)DevFunc) << 5;
      PciSetRegMech2( RegMask, ConfigReg, val, size );
   }
   else
   {
      /* Return failed because info is not valid , "TRUE" means "FAILED"*/
      return ( TRUE );
   }
   return ( FALSE );  /* FALSE means OK */
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  RegisterUHCI                                     */
/*                                                                    */
/* DESCRIPTIVE NAME:  Registers the HCD device driver resources.      */
/*                                                                    */
/* FUNCTION:  The function of this routine is to register USBD        */
/*            driver and adapter.                                     */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Initialization time                                       */
/*                                                                    */
/* ENTRY POINT:  RegisterUHCI                                         */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  none                                                       */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  Fills in ghDriver, ghAdapter                             */
/*                                                                    */
/* INTERNAL REFERENCES:  RegisterUHCI                                 */
/*                                                                    */
/* EXTERNAL REFERENCES:  RMCreateDriver                               */
/*                       RMAllocResource                              */
/*                       RMCreateAdapter                              */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
static BOOL RegisterUHCI(void)
{
   APIRET    rc=RMRC_SUCCESS;
   RESOURCESTRUCT Resource;
   UCHAR       ResourceBuf[ 12 ];
   ADJUNCT     AdjAdaptNum;
   PAHRESOURCE pResourceList = (PAHRESOURCE)ResourceBuf;

   rc=RMCreateDriver( &gDriverStruct, &ghDriver);

   if (rc==RMRC_SUCCESS)
   {  // create interrupt resource handle
      if(gIRQShared)
         Resource.IRQResource.IRQFlags  = RS_IRQ_SHARED;
      else
         Resource.IRQResource.IRQFlags  = RS_IRQ_EXCLUSIVE;
      Resource.ResourceType          = RS_TYPE_IRQ;
      Resource.IRQResource.IRQLevel  = gusbIRQ;
      Resource.IRQResource.PCIIrqPin = gusbPIN;
      Resource.IRQResource.Reserved  = 0;
      Resource.IRQResource.pfnIntHandler = 0;
      rc=RMAllocResource( ghDriver, &girqResource, &Resource);
   }

   if (rc==RMRC_SUCCESS)
   {  // create I/O space resource handle
      Resource.ResourceType              = RS_TYPE_IO;
      Resource.IOResource.BaseIOPort     = gusbIOBase;
      Resource.IOResource.NumIOPorts     = USB_PORT_COUNT;
      Resource.IOResource.IOFlags        = RS_IO_EXCLUSIVE;
      Resource.IOResource.IOAddressLines = 16;
      rc=RMAllocResource( ghDriver, &gioResource, &Resource);
   }

   if (rc==RMRC_SUCCESS)
   {  // create adapter using both interrupt and I/O space resources
      pResourceList->NumResource = 2;
      pResourceList->hResource[0] = girqResource;
      pResourceList->hResource[1] = gioResource;

      gAdapterStruct.HostBusType = AS_HOSTBUS_PCI;
      AdjAdaptNum.pNextAdj       = NULL;
      AdjAdaptNum.AdjLength      = sizeof(ADJUNCT);
      AdjAdaptNum.AdjType        = ADJ_ADAPTER_NUMBER;
      AdjAdaptNum.Adapter_Number = 0;
      gAdapterStruct.pAdjunctList = &AdjAdaptNum;

      rc=RMCreateAdapter(ghDriver, &ghAdapter,  &gAdapterStruct,
                         NULL, pResourceList);
   }

   if (rc!=RMRC_SUCCESS && !ghDriver)  // if failed release all the resources
      RMDestroyDriver( ghDriver );

   return (rc==RMRC_SUCCESS);
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  CheckResourceUsage                               */
/*                                                                    */
/* DESCRIPTIVE NAME:  Check host resource usage.                      */
/*                                                                    */
/* FUNCTION:  The function of this routine is to check USB host       */
/*            resource (base address area) availability.              */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Initialization time                                       */
/*                                                                    */
/* ENTRY POINT:  CheckResourceUsage                                   */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  none                                                       */
/*                                                                    */
/* EXIT-NORMAL: N/A                                                   */
/*                                                                    */
/* EXIT-ERROR:  N/A                                                   */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  none                                         */
/*                                                                    */
/* EXTERNAL REFERENCES:  RMCreateDriver                               */
/*                       RMAllocResource                              */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
static BOOL BusResourcesUsed(void)
{
   APIRET    rc=RMRC_SUCCESS;
   RESOURCESTRUCT Resource;
   UCHAR       ResourceBuf[ 12 ];
   PAHRESOURCE pResourceList = (PAHRESOURCE)ResourceBuf;
   HDRIVER     hDriver=NULL;
   BOOL        resourcesUsed=TRUE;
   BOOL        rcConfig=FALSE;
   ULONG       IOBase;

   // get serial bus resource values

   if (!rc)
      rc = ReadPCIConfigSpace( gBusNum, gDevFunc, // read Host controller's IO base address
                               (UCHAR) PCIREG_USBBA,
                               (PULONG) &IOBase, sizeof(IOBase) );
   if (!rc)
   {
      IOBase&= 0x0000ffe0;
      gusbIOBase=(USHORT)IOBase;
   }
   else   // failed to retrieve resource values (IRQ, IRQ pin or I/O base address)
      return (resourcesUsed);

   // check if used (try to allocate, if failed - resources already in use)
   rc=RMCreateDriver( &gDriverStruct, &hDriver);

   if (rc==RMRC_SUCCESS)
   {  // create I/O space resource handle
      Resource.ResourceType              = RS_TYPE_IO;
      Resource.IOResource.BaseIOPort     = gusbIOBase;
      Resource.IOResource.NumIOPorts     = USB_PORT_COUNT;
      Resource.IOResource.IOFlags        = RS_IO_EXCLUSIVE;
      Resource.IOResource.IOAddressLines = 16;
      rc=RMAllocResource( hDriver, &gioResource, &Resource);
      resourcesUsed= rc!=RMRC_SUCCESS;
   }

   if(gioResource)
      RMDeallocResource(hDriver, gioResource);
   gioResource=NULL;
   if (hDriver)
      RMDestroyDriver(hDriver);

   return (resourcesUsed);
}

