/* SCCSID = "src/dev/usb/HID/HIDIDC.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:  HIDIDC.C                                              */
/*                                                                            */
/*   DESCRIPTIVE NAME:  HID Class device driver inter-device driver           */
/*                      communication routines.                               */
/*                                                                            */
/*   FUNCTION: These routines handle the PDD-PDD IDC for the                  */
/*             HID Class device driver.                                       */
/*                                                                            */
/*   NOTES:                                                                   */
/*      DEPENDENCIES: None                                                    */
/*      RESTRICTIONS: None                                                    */
/*                                                                            */
/*   ENTRY POINTS:                                                            */
/*             HIDidc       PDD - PDD IDC worker switch                       */
/*             HIDDetachDevice                                                */
/*             HIDCheckForService                                             */
/*             HIDRegisterClient                                              */
/*             HIDAcceptIO                                                    */
/*             HIDProcessIRQ                                                  */
/*             HIDClearStalled                                                */
/*                                                                            */
/*   EXTERNAL REFERENCES:                                                     */
/*                                                                            */
/* Change Log                                                                 */
/*                                                                            */
/*  Mark    yy/mm/dd  Programmer      Comment                                 */
/*  ----    --------  ----------      -------                                 */
/*          98/01/16  MB              Original developer.                     */
/*          98/09/23  MB              modified HIDCheckForService to refuse   */
/*                                    service if configuration is already     */
/*                                    set by other driver                     */
/**************************** END OF SPECIFICATIONS ***************************/

#include "hid.h"

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  HIDidc                                           */
/*                                                                    */
/* DESCRIPTIVE NAME:  PDD-PDD IDC entry point and request router      */
/*                                                                    */
/* FUNCTION:  This routine is the PDD-PDD IDC entry point and         */
/*            request router..  IDC function requests are routed      */
/*            to the appropriate worker routine.  The address of      */
/*            this routine is returned to other device drivers via    */
/*            the DevHelp AttachDD call.                              */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  HIDidc                                              */
/*    LINKAGE  :  CALL FAR                                            */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP_GENIOCTL                                  */
/*                                                                    */
/* EXIT-NORMAL:  n/a                                                  */
/*                                                                    */
/* EXIT-ERROR:  n/a                                                   */
/*                                                                    */
/* EFFECTS:  sets error code in pRP_GENIOCTL->rph.Status              */
/*           USB_IDC_RC_PARMERR - 1) request command code is not      */
/*                                CMDGenIOCTL; 2) parameter packet    */
/*                                address is NULL;                    */
/*           USB_IDC_RC_WRONGFUNC - wrong function requested          */
/*           USB_IDC_RC_WRONGCAT - wrong request category             */
/*                                                                    */
/* INTERNAL REFERENCES:  HIDProcessIRQ                                */
/*    ROUTINES:          HIDDetachDevice                              */
/*                       HIDCheckForService                           */
/*                       HIDRegisterClient                            */
/*                                                                    */
/* EXTERNAL REFERENCES:  USBCallIDC                                   */
/*    ROUTINES:                                                       */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
void FAR HIDidc( PRP_GENIOCTL pRP_GENIOCTL )
{
   USHORT   status;

   if (!pRP_GENIOCTL)
      return;

#ifdef   DEBUG
   dsPrint3(DBG_HLVLFLOW, "HID : HIDidc started: Category=%x, Function=%x, Status=%x\r\n",
            pRP_GENIOCTL->Category,pRP_GENIOCTL->Function,pRP_GENIOCTL->rph.Status);
#endif

   status=pRP_GENIOCTL->rph.Status;
   pRP_GENIOCTL->rph.Status=USB_IDC_RC_OK;
   if (pRP_GENIOCTL->rph.Cmd!=CMDGenIOCTL || !pRP_GENIOCTL->ParmPacket)
      pRP_GENIOCTL->rph.Status=USB_IDC_RC_PARMERR;

   if (pRP_GENIOCTL->rph.Status==USB_IDC_RC_OK)
      switch (pRP_GENIOCTL->Category)
      {
      case USB_IDC_CATEGORY_CLASS:
         switch (pRP_GENIOCTL->Function)
         {
         case USB_IDC_FUNCTION_DETDEV:
            HIDDetachDevice( pRP_GENIOCTL );
            break;
         case USB_IDC_FUNCTION_CHKSERV:
            HIDCheckForService( pRP_GENIOCTL );
            break;
         case USB_IDC_FUNCTION_REGISTER:
            HIDRegisterClient( pRP_GENIOCTL );
            break;
         case USB_IDC_FUNCTION_ACCIO:
            HIDAcceptIO( pRP_GENIOCTL );
            break;
         case USB_IDC_FUNCTION_PRCIRQ:
            pRP_GENIOCTL->rph.Status=status;
            HIDProcessIRQ( pRP_GENIOCTL );
            break;
         case USB_IDC_FUNCTION_CLRSTALL:
            HIDClearStalled( pRP_GENIOCTL );
            break;
         default:
            pRP_GENIOCTL->rph.Status=USB_IDC_RC_WRONGFUNC;
            break;
         }
         break;
      default:
         pRP_GENIOCTL->rph.Status=USB_IDC_RC_WRONGCAT;
         break;
      }
   pRP_GENIOCTL->rph.Status|=STATUS_DONE;   

#ifdef   DEBUG
   dsPrint3(DBG_HLVLFLOW, "HID : HIDidc finished: Category=%x, Function=%x, Status=%x\r\n",
            pRP_GENIOCTL->Category,pRP_GENIOCTL->Function,pRP_GENIOCTL->rph.Status);
#endif
}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  HIDAcceptIO                                      */
/*                                                                    */
/* DESCRIPTIVE NAME:  HID Accept I/O request routine                  */
/*                                                                    */
/* FUNCTION:  This routine passes all internal HID Class driver       */
/*            I/O requests to USBD driver.                            */
/*                                                                    */
/* NOTES:  HIDAcceptIO translates HID v.1.0 setup packets to HID      */
/*         preDraft3 packets when required (changes packet            */
/*         destination from interface to endpoint and interface index */
/*         to endpoint number).                                        */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  HIDAcceptIO                                         */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP_GENIOCTL                                  */
/*                                                                    */
/* EXIT-NORMAL:  n/a                                                  */
/*                                                                    */
/* EXIT-ERROR:  n/a                                                   */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:  USBCallIDC                                   */
/*    ROUTINES:                                                       */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
void HIDAcceptIO( PRP_GENIOCTL pRP_GENIOCTL )
{
   UCHAR       savedCategory;
   USBRB FAR   *ioRB;
   USHORT      deviceIndex;

   ioRB=(USBRB FAR *)pRP_GENIOCTL->ParmPacket;

   if (ioRB->flags&USRB_FLAGS_TTYPE_SETUP)
   {
      // find active device data row based on device address
      for (deviceIndex=0; deviceIndex<gNoOfActiveDevices; deviceIndex++)
      {
         if (!gActiveDevices[deviceIndex].pDeviceInfo)
            continue;
         if (gActiveDevices[deviceIndex].pDeviceInfo->ctrlID!=ioRB->controllerId)
            continue;
         if (gActiveDevices[deviceIndex].pDeviceInfo->deviceAddress==ioRB->deviceAddress)
            break;
      }
      // update class setup packet for predraft3 devices
      if (deviceIndex<gNoOfActiveDevices && (gActiveDevices[deviceIndex].versionFlags&HID_PREDRAFT3_DEVICE))
      {
         SetupPacket FAR   *setupPacket;

         setupPacket=(SetupPacket FAR *)ioRB->buffer1;
         if ((setupPacket->bmRequestType&REQTYPE_RECIPIENT_MASK)==REQTYPE_RECIPIENT_INTERFACE)
         {  // change destination from interface to endpoint
            USHORT   interface;
            setupPacket->bmRequestType&=~REQTYPE_RECIPIENT_MASK;
            setupPacket->bmRequestType|=REQTYPE_RECIPIENT_ENDPOINT;
            interface=setupPacket->wIndex;
            setupPacket->wIndex= (USHORT)GetInterruptPipeAddr (gActiveDevices[deviceIndex].pDeviceInfo->configurationData, 
                                                               gActiveDevices[deviceIndex].pDeviceInfo->descriptor.bNumConfigurations, 
                                                               gActiveDevices[deviceIndex].pDeviceInfo->bConfigurationValue,
                                                               (UCHAR)interface);
#ifdef   DEBUG
            dsPrint3(DBG_DETAILED, "HID : HIDAcceptIO: changed (draft3) for devaddr=%d, intf=%d, endpt=%d\r\n",
                     gActiveDevices[deviceIndex].pDeviceInfo->deviceAddress, interface, setupPacket->wIndex);
#endif
         }
      }
   }

   savedCategory=pRP_GENIOCTL->Category;           // save category value
   pRP_GENIOCTL->Category=USB_IDC_CATEGORY_USBD;   // set USBD as IDC call target
   USBCallIDC( gpUSBDIDC, gdsUSBIDC, pRP_GENIOCTL );
   pRP_GENIOCTL->Category=savedCategory;           // restore category value
}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  HIDDetachDevice                                  */
/*                                                                    */
/* DESCRIPTIVE NAME:  Device detach worker routine                    */
/*                                                                    */
/* FUNCTION:  This routine is called when USBD driver detects device  */
/*            detach condition. Each registered client called to      */
/*            process detach, local device list entry released.       */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  HIDDetachDevice                                     */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP_GENIOCTL                                  */
/*                                                                    */
/* EXIT-NORMAL:  n/a                                                  */
/*                                                                    */
/* EXIT-ERROR:  n/a                                                   */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  FreeReportItems                              */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:  USBCallIDC                                   */
/*    ROUTINES:                                                       */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
void HIDDetachDevice( PRP_GENIOCTL pRP_GENIOCTL )
{
   USBDetach FAR  *detachData;
   USHORT         deviceIndex, clientIndex;
   UCHAR          category;

   category=pRP_GENIOCTL->Category; // save category value

   // inform clients on device detach event
   for (clientIndex=0; clientIndex<gNoOfRegisteredClients; clientIndex++)
   {
      detachData=(USBDetach FAR *)pRP_GENIOCTL->ParmPacket;
#ifdef   DEBUG
      dsPrint2(DBG_DETAILED, "HID : HIDDetachDevice calling client driver %d, a=%d\r\n",
               clientIndex,detachData->deviceAddress);
#endif
      pRP_GENIOCTL->Category=USB_IDC_CATEGORY_CLIENT;
      pRP_GENIOCTL->Function=USB_IDC_FUNCTION_DETDEV;
      USBCallIDC( gClientDrivers[clientIndex].clientIDCAddr,
                  gClientDrivers[clientIndex].clientDS, pRP_GENIOCTL );
   }
   pRP_GENIOCTL->Category=category; // restore category value

   // delete device data
   for (deviceIndex=0; deviceIndex<gNoOfActiveDevices; deviceIndex++)
   {
      if (!gActiveDevices[deviceIndex].pDeviceInfo)
         continue;   // empty entry
      if (gActiveDevices[deviceIndex].pDeviceInfo->ctrlID!=detachData->controllerId ||
          gActiveDevices[deviceIndex].pDeviceInfo->deviceAddress!=detachData->deviceAddress)
         continue;

      FreeReportItems ( gActiveDevices[deviceIndex].reportItemIndex );
      gActiveDevices[deviceIndex].reportItemIndex=LAST_INDEX;
      gActiveDevices[deviceIndex].pDeviceInfo=NULL;
   }

   // decrease gNoOfActiveDevices if possible
   if (gNoOfActiveDevices>0)
      for (deviceIndex=gNoOfActiveDevices-1; ; deviceIndex--)
      {
         if (!gActiveDevices[deviceIndex].pDeviceInfo)
            gNoOfActiveDevices--;
         else
            break;
         if (!deviceIndex)
            break;
      }
}


/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  HIDCheckForService                               */
/*                                                                    */
/* DESCRIPTIVE NAME:  Check for service worker routine                */
/*                                                                    */
/* FUNCTION:  This routine is called to check device descriptor data  */
/*            HID class conformance.                                  */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  HIDCheckForService                                  */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP_GENIOCTL                                  */
/*                                                                    */
/* EXIT-NORMAL:  n/a                                                  */
/*                                                                    */
/* EXIT-ERROR:  n/a                                                   */
/*                                                                    */
/* EFFECTS:  sets return code in  pRP_GENIOCTL->rph.Status            */
/*           USB_IDC_RC_SERVREJCTD - device can't be service by       */
/*                                   driver - 1) device class,        */
/*                                   subclass and protocol in device  */
/*                                   descriptor is not 0; 2) there    */
/*                                   are no HID descriptors or its    */
/*                                   size exceeds                     */
/*                                   HID_MAX_REPORT_LENGTH bytes.     */
/*           USB_IDC_RC_EXCEEDSMAX - no space in device table         */
/*                                                                    */
/* INTERNAL REFERENCES:  none                                         */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:  GetHIDReportLength                           */
/*    ROUTINES:          IsDraft3Compl                                */
/*                       setmem                                       */
/*                       USBCallIDC                                   */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
void HIDCheckForService( PRP_GENIOCTL pRP_GENIOCTL )
{
   USBCDServe FAR    *serviceData;
   UCHAR             configIndex;
   UCHAR FAR         *nextBytePtr;
   DeviceConfiguration FAR    *devConf;
   USHORT            deviceIndex;
   USBSetConf        setConfiguration;
   RP_GENIOCTL       rp_USBReq;
   UCHAR             bNumConfigurations;
   UCHAR             interfaceIndex;
   USHORT            hidReportLength=0;

   serviceData=(USBCDServe FAR *)pRP_GENIOCTL->ParmPacket;

   // check device class, subclass and protocol values - HID devices sets 0's in all these fields
   if (serviceData->pDeviceInfo->descriptor.bDeviceClass!=0 ||
       serviceData->pDeviceInfo->descriptor.bDeviceSubClass!=0 ||
       serviceData->pDeviceInfo->descriptor.bDeviceProtocol!=0)
   {   //   device is not HID class device - can't be served
      pRP_GENIOCTL->rph.Status=USB_IDC_RC_SERVREJCTD;
#ifdef   DEBUG
      dsPrint3(DBG_CRITICAL, "HID : HIDCheckForService: can not serve. Class=%d,SubCls=%d,Protocol=%d\r\n",
               serviceData->pDeviceInfo->descriptor.bDeviceClass,
               serviceData->pDeviceInfo->descriptor.bDeviceSubClass,
               serviceData->pDeviceInfo->descriptor.bDeviceProtocol);
#endif
      return;
   }
   // check all device descriptors to find HID descriptors
   bNumConfigurations=serviceData->pDeviceInfo->descriptor.bNumConfigurations;
   devConf=(DeviceConfiguration FAR *)serviceData->pDeviceInfo->configurationData;
   for (configIndex=0; configIndex<bNumConfigurations; configIndex++)
   {
      nextBytePtr=(UCHAR FAR *)devConf;
      nextBytePtr=nextBytePtr+devConf->wTotalLength;
      for (interfaceIndex=0; interfaceIndex<devConf->bNumInterfaces && !hidReportLength; interfaceIndex++)
      {
         hidReportLength=GetHIDReportLength(serviceData->pDeviceInfo->configurationData, 
                                            bNumConfigurations, devConf->bConfigurationValue, interfaceIndex);
      }
      if (hidReportLength && hidReportLength<=HID_MAX_REPORT_LENGTH)
         break;
      // advance pointer to next configuration array
      devConf=(DeviceConfiguration FAR *)nextBytePtr;
   }
   if (!hidReportLength || hidReportLength>HID_MAX_REPORT_LENGTH)
   {  //   no HID class descriptor found - device is not HID class device - can't be served
      // device is also ignored if report descriptor size exceeds HID_MAX_REPORT_LENGTH
      pRP_GENIOCTL->rph.Status=USB_IDC_RC_SERVREJCTD;
#ifdef   DEBUG
      dsPrint2(DBG_CRITICAL, "HID : HIDCheckForService: can not serve devaddr %d. Report length=%d\r\n",
               serviceData->pDeviceInfo->deviceAddress, hidReportLength);
#endif
      return;
   }

   if (serviceData->pDeviceInfo->bConfigurationValue &&  // 23/09/98 MB
       serviceData->pDeviceInfo->bConfigurationValue!=devConf->bConfigurationValue)
   {  // configuration has already been set to another than
      // required value
      pRP_GENIOCTL->rph.Status=USB_IDC_RC_SERVREJCTD;
#ifdef   DEBUG
      dsPrint2(DBG_CRITICAL, "HID : HIDCheckForService: can not serve devaddr %d. Configuration set=%d\r\n",
               serviceData->pDeviceInfo->deviceAddress, serviceData->pDeviceInfo->bConfigurationValue);
#endif
      return;
   }

   // device belongs to HID class - allocate new servicable device entry
   for (deviceIndex=0; deviceIndex<gNoOfActiveDevices; deviceIndex++)
   {
      if (!gActiveDevices[deviceIndex].pDeviceInfo)
         break;
   }
   if (deviceIndex+1>=gMaxDevices)
   {  // no space in Hub data entry table - set error return code
      pRP_GENIOCTL->rph.Status=USB_IDC_RC_EXCEEDSMAX;
#ifdef   DEBUG
      dsPrint(DBG_CRITICAL, "HID : HIDCheckForService: Can not allocate device entry\r\n");
#endif
      return;
   }
   if (deviceIndex>=gNoOfActiveDevices)
      gNoOfActiveDevices=deviceIndex+1;

   gActiveDevices[deviceIndex].pDeviceInfo=serviceData->pDeviceInfo;   // far pointer to device data
   gActiveDevices[deviceIndex].devConf=devConf;       // far pointer to device cinfiguration data
   gActiveDevices[deviceIndex].reportItemIndex=LAST_INDEX;   // no report items for that device
   gActiveDevices[deviceIndex].protocolSetIndex=0;       // interface index to last protocol set request
   gActiveDevices[deviceIndex].versionFlags=0;
   if (IsDraft3Compl(serviceData->pDeviceInfo->configurationData, bNumConfigurations))
      gActiveDevices[deviceIndex].versionFlags|=HID_PREDRAFT3_DEVICE;

   if(serviceData->pDeviceInfo->bConfigurationValue!=devConf->bConfigurationValue)
   {
      // mark configuration as used by driver. All other drivers can't change this value
      serviceData->pDeviceInfo->bConfigurationValue=devConf->bConfigurationValue;
   
      // fill in control blocks to set USB device configuration to HID matching configuration
      setConfiguration.controllerId=serviceData->pDeviceInfo->ctrlID;        // controller ID, not used, should be set to 0
      setConfiguration.deviceAddress=serviceData->pDeviceInfo->deviceAddress;       // USB device address
      setConfiguration.classDriverDS=GetDS();   //  class driver data segment value - used to identify driver;
      setConfiguration.configurationValue=devConf->bConfigurationValue;  // desired configuration value (type depends on call function)
      setConfiguration.irqSwitchValue=HID_IRQ_STATUS_SETCONF;      // value used in class driver IRQ processor worker switch
      setConfiguration.category=USB_IDC_CATEGORY_CLASS;            // IRQ processor category
      setConfiguration.setConfiguration=&gActiveDevices[deviceIndex].stdPacket;
   
   #ifdef   DEBUG
      dsPrint3(DBG_DETAILED, "HID : HIDCheckForService: a=%d, config=%d, vFlags=%x\r\n",
               gActiveDevices[deviceIndex].pDeviceInfo->deviceAddress,
               devConf->bConfigurationValue, gActiveDevices[deviceIndex].versionFlags);
   #endif
   
      setmem((PSZ)&rp_USBReq, 0, sizeof(rp_USBReq));
      rp_USBReq.rph.Cmd=CMDGenIOCTL;   // IOCTL
      rp_USBReq.Category=USB_IDC_CATEGORY_USBD;
      rp_USBReq.Function=USB_IDC_FUNCTION_SETCONF;
      rp_USBReq.ParmPacket=(PVOID)&setConfiguration;
   
      USBCallIDC( gpUSBDIDC, gdsUSBIDC, (PRP_GENIOCTL)&rp_USBReq );
   }
   else
   {   //   continue as if configuration already set
      USBRB        hcdReqBlock;

      setmem((PSZ)&hcdReqBlock, 0, sizeof(hcdReqBlock));

      hcdReqBlock.controllerId=serviceData->pDeviceInfo->ctrlID;
      hcdReqBlock.deviceAddress=serviceData->pDeviceInfo->deviceAddress;
      
      setmem((PSZ)&rp_USBReq, 0, sizeof(rp_USBReq));
      rp_USBReq.rph.Cmd=CMDGenIOCTL;   // IOCTL
      rp_USBReq.Category=USB_IDC_CATEGORY_USBD;
      rp_USBReq.Function=USB_IDC_FUNCTION_SETCONF;
      rp_USBReq.ParmPacket=(PVOID)&hcdReqBlock;

      ConfigurationSet( (PRP_GENIOCTL)&rp_USBReq );
   }
}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  HIDRegisterClient                                */
/*                                                                    */
/* DESCRIPTIVE NAME:  Register Client driver worker routine           */
/*                                                                    */
/* FUNCTION:  This routine accepts registration data from Client      */
/*            drivers and calls client driver for all known devices.  */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  HIDRegisterClient                                   */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP_GENIOCTL                                  */
/*                                                                    */
/* EXIT-NORMAL:  n/a                                                  */
/*                                                                    */
/* EXIT-ERROR:  n/a                                                   */
/*                                                                    */
/* EFFECTS:  sets error code in pRP_GENIOCTL->rph.Status              */
/*           USB_IDC_RC_EXCEEDSMAX - no of clients exceeds maximum    */
/*                                                                    */
/* INTERNAL REFERENCES:  none                                         */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:  setmem                                       */
/*    ROUTINES:          USBCallIDC                                   */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
void HIDRegisterClient( PRP_GENIOCTL pRP_GENIOCTL )
{
   USBDClass FAR  *regData;
   RP_GENIOCTL rp_USBReq;
   USHORT      deviceIndex;
   USHORT      clientIndex;
   USBHIDServe serviceData;   

   if (gNoOfRegisteredClients>=gMaxClients-1)
   {  // no space to register client driver
      pRP_GENIOCTL->rph.Status=USB_IDC_RC_EXCEEDSMAX;
      return;
   }
   regData=(USBDClass FAR *)pRP_GENIOCTL->ParmPacket;

   gClientDrivers[gNoOfRegisteredClients].clientIDCAddr=regData->usbIDC;
   gClientDrivers[gNoOfRegisteredClients].clientDS=regData->usbDS;
   clientIndex=gNoOfRegisteredClients;

   gNoOfRegisteredClients++;

   // call client driver to process known device information
   serviceData.itemData=gReportItemData;
   serviceData.itemUsage=gItemUsage;
   serviceData.itemDesignator=gItemDesignator;
   serviceData.itemString=gItemString;

   for (deviceIndex=0; deviceIndex<gNoOfActiveDevices; deviceIndex++)
   {
      serviceData.pDeviceInfo=gActiveDevices[deviceIndex].pDeviceInfo;   // far pointer to device data
      setmem((PSZ)&rp_USBReq, 0, sizeof(rp_USBReq));
      rp_USBReq.rph.Cmd=CMDGenIOCTL;   // IOCTL
      rp_USBReq.Category=USB_IDC_CATEGORY_CLIENT;
      rp_USBReq.Function=USB_IDC_FUNCTION_CHKSERV;
      rp_USBReq.ParmPacket=(PVOID)&serviceData;

      serviceData.devConf=gActiveDevices[deviceIndex].devConf;       // far pointer to device configuration data
      serviceData.reportItemIndex=gActiveDevices[deviceIndex].reportItemIndex;
      serviceData.versionFlags=gActiveDevices[deviceIndex].versionFlags;

      USBCallIDC( gClientDrivers[clientIndex].clientIDCAddr,
                  gClientDrivers[clientIndex].clientDS, (RP_GENIOCTL FAR *)&rp_USBReq );
   }

}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  HIDClearStalled                                  */
/*                                                                    */
/* DESCRIPTIVE NAME:  Clears stalled communication pipe               */
/*                                                                    */
/* FUNCTION:  This routine calls USBD driver to clear stalled pipe.   */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  HIDClearStalled                                     */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  RP_GENIOCTL FAR *pRP_GENIOCTL                              */
/*                                                                    */
/* EXIT-NORMAL:  none                                                 */
/*                                                                    */
/* EXIT-ERROR:  none                                                  */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  none                                         */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:  setmem                                       */
/*    ROUTINES:          USBCallIDC                                   */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
void HIDClearStalled( RP_GENIOCTL FAR *pRP_GENIOCTL )
{
   USBRB FAR            *processedRB;
   RP_GENIOCTL          rp_USBReq;
   USBClearStalled      clearRB;
   USHORT               deviceIndex;

   processedRB=(USBRB FAR *)pRP_GENIOCTL->ParmPacket;

#ifdef   DEBUG
   dsPrint3(DBG_IRQFLOW, "HID : HIDClearStalled: clearing ctrlid=%d,address=%d,endpoint=%d\r\n",
            processedRB->controllerId, processedRB->deviceAddress, processedRB->endPointId);
#endif

   clearRB.controllerId=processedRB->controllerId;        // controller ID, not used, should be set to 0
   clearRB.deviceAddress=processedRB->deviceAddress;       // USB device address
   clearRB.endPointId=processedRB->endPointId;          // stalled endpoint ID
   if (processedRB->category==USB_IDC_CATEGORY_CLASS)
   {
      clearRB.clientIDCAddr=NULL;       // no irq notification for this request
      clearRB.clientDS=0;            //  no irq notification for this request
   }
   else
   {
      clearRB.clientIDCAddr=processedRB->usbIDC;       // no irq notification for this request
      clearRB.clientDS=processedRB->usbDS;            //  no irq notification for this request
   }
   clearRB.irqSwitchValue=processedRB->requestData1;      //  no irq notification for this request
   clearRB.requestData2=processedRB->requestData2;      //  no irq notification for this request
   clearRB.requestData3=processedRB->requestData3;      //  no irq notification for this request
   clearRB.category=processedRB->category;            // IRQ processor category
   clearRB.clearStalled=NULL;       // clear stalled pipe request packet buffer

   // find active device data row based on device address
   for (deviceIndex=0; deviceIndex<gNoOfActiveDevices; deviceIndex++)
   {
      if (!gActiveDevices[deviceIndex].pDeviceInfo)
         continue;
      if (gActiveDevices[deviceIndex].pDeviceInfo->ctrlID!=processedRB->controllerId)
         continue;
      if (gActiveDevices[deviceIndex].pDeviceInfo->deviceAddress==processedRB->deviceAddress)
      {
         clearRB.clearStalled=(SetupPacket FAR *)&gActiveDevices[deviceIndex].cstPacket;
         break;
      }
   }

   if (!clearRB.clearStalled)  // device not exists
      return;
#ifdef   DEBUG
   dsPrint3(DBG_DETAILED, "HID : HIDClearStalled: idcAddr=%lx,ds=%x,category=%x\r\n",
            (LONG)clearRB.clientIDCAddr, clearRB.clientDS, processedRB->category);
   dsPrint4(DBG_DETAILED, "HID : HIDClearStalled: r1=%lx,r2=%lx,r3=%lx, sAddr=%lx\r\n",
            clearRB.irqSwitchValue, clearRB.requestData2, clearRB.requestData3,(LONG)clearRB.clearStalled);
#endif

   setmem((PSZ)&rp_USBReq, 0, sizeof(rp_USBReq));
   rp_USBReq.rph.Cmd=CMDGenIOCTL;   // IOCTL
   rp_USBReq.Category=USB_IDC_CATEGORY_USBD;
   rp_USBReq.Function=USB_IDC_FUNCTION_CLRSTALL;
   rp_USBReq.ParmPacket=(PVOID)&clearRB;

   USBCallIDC( gpUSBDIDC, gdsUSBIDC, (RP_GENIOCTL FAR *)&rp_USBReq );

   if (rp_USBReq.rph.Status==USB_IDC_RC_OK)
      processedRB->status&=~USRB_STATUS_STALLED;
}

