/* SCCSID = "src/dev/usb/HID/HIDIRQ.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:  HIDIRQ.C                                              */
/*                                                                            */
/*   DESCRIPTIVE NAME:  HID Class device driver interrupt processing          */
/*                      extension routines.                                   */
/*                                                                            */
/*   FUNCTION: These routines handle the IRQ IDC calls for the                */
/*             HID Class device driver.                                       */
/*                                                                            */
/*   NOTES:                                                                   */
/*      DEPENDENCIES: None                                                    */
/*      RESTRICTIONS: None                                                    */
/*                                                                            */
/*   ENTRY POINTS:                                                            */
/*             HIDProcessIRQ - IRQ processing switch routine                  */
/*      ConfigurationSet                                                      */
/*      AskClientsToServe                                                     */
/*      SetProtocol                                                           */
/*      ProtocolSet                                                           */
/*                                                                            */
/*   EXTERNAL REFERENCES:                                                     */
/*                                                                            */
/* Change Log                                                                 */
/*                                                                            */
/*  Mark    yy/mm/dd  Programmer      Comment                                 */
/*  ----    --------  ----------      -------                                 */
/*          98/01/16  MB              Original developer.                     */
/*                                                                            */
/**************************** END OF SPECIFICATIONS ***************************/

#include "hid.h"


/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  HIDProcessIRQ                                    */
/*                                                                    */
/* DESCRIPTIVE NAME:  IRQ procesing extension routine                 */
/*                                                                    */
/* FUNCTION:  This routine processes all internal HID Class           */
/*            driver I/O request IRQ extension calls by calling       */
/*            appropriate worker routines.                            */
/*                                                                    */
/* NOTES: This routine issues I/O request to clear stalled            */
/*        endpoints before calling worker routine.                    */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  HIDProcessIRQ                                       */
/*    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              */
/*                                                                    */
/* INTERNAL REFERENCES:  ConfigurationSet                             */
/*    ROUTINES:          AskClientsToServe                            */
/*                       SetProtocol                                  */
/*                       ProtocolSet                                  */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*    ROUTINES:                                                       */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
void HIDProcessIRQ( PRP_GENIOCTL pRP_GENIOCTL )
{
   USBRB FAR    *processedRB;

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

#ifdef   DEBUG
   dsPrint2(DBG_HLVLFLOW, "HID : HIDProcessIRQ Switch %d, Status %x\r\n", processedRB->requestData1, processedRB->status);
#endif

   if (processedRB->status&USRB_STATUS_STALLED)
      HIDClearStalled( pRP_GENIOCTL );

   switch (processedRB->requestData1)
   {
   case HID_IRQ_STATUS_SETCONF:
      ConfigurationSet( pRP_GENIOCTL );
      break;
   case HID_IRQ_STATUS_SERVCLIENT:
      AskClientsToServe( pRP_GENIOCTL );
      break;
   case HID_IRQ_STATUS_SETPROTOCOL:
      SetProtocol( pRP_GENIOCTL );
      break;
   case HID_IRQ_STATUS_REPRETRIEVED:
      ProtocolSet( pRP_GENIOCTL );
      break;
   default:
      break;
   }
}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  ConfigurationSet                                 */
/*                                                                    */
/* DESCRIPTIVE NAME:  Configuration set worker routine                */
/*                                                                    */
/* FUNCTION:  This routine is called when "Set Configuration" I/O     */
/*            issued after device is accepted for service is          */
/*            completed. The routine finds out device's data row      */
/*            in active device array and starts HID report data       */
/*            retrieving for all the interfaces.                      */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  ConfigurationSet                                    */
/*    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_ALLOCERR - device not found in device list    */
/*                                                                    */
/* INTERNAL REFERENCES:  ProtocolSet                                  */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:  none                                         */
/*    ROUTINES:                                                       */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
void ConfigurationSet( PRP_GENIOCTL pRP_GENIOCTL )
{
   USBRB FAR    *processedRB;
   USHORT       deviceIndex;

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

   if (pRP_GENIOCTL->rph.Status!=USB_IDC_RC_OK)
   {  // stop processing if failed to set configuration

#ifdef   DEBUG
      dsPrint1(DBG_CRITICAL, "HID : ConfigurationSet failed. Status=%x\r\n", pRP_GENIOCTL->rph.Status);
#endif
      return;
   }
#ifdef   DEBUG
   dsPrint2(DBG_IRQFLOW, "HID : ConfigurationSet Status=%x, devaddr=%d\r\n", pRP_GENIOCTL->rph.Status, processedRB->deviceAddress);
#endif
   // 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)
         break;
   }
   if (deviceIndex>=gNoOfActiveDevices)
   {  // entry not found - set error return code
#ifdef   DEBUG
      dsPrint2(DBG_CRITICAL, "HID : ConfigurationSet failed to locate device ctrlidd=%d,addr=%d\r\n",
               processedRB->controllerId, processedRB->deviceAddress);
#endif
      pRP_GENIOCTL->rph.Status=USB_IDC_RC_ALLOCERR;      
      return;
   }

   // start report data retrieving
   processedRB->requestData2=MAKEULONG(deviceIndex,0xffff);
   ProtocolSet( pRP_GENIOCTL );
}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  ProtocolSet                                      */
/*                                                                    */
/* DESCRIPTIVE NAME:  Transfer protocol set                           */
/*                                                                    */
/* FUNCTION:  This routine is called to start/continue HID device     */
/*            initialization. This routine processes all the device   */
/*            interfaces by initiating report read process and        */
/*            ask all known client drivers to accept/refuse device    */
/*            for service                                             */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  ProtocolSet                                         */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP_GENIOCTL                                  */
/*                                                                    */
/* EXIT-NORMAL:  n/a                                                  */
/*                                                                    */
/* EXIT-ERROR:   n/a                                                  */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  GetHIDReport                                 */
/*    ROUTINES:          AskClientsToServe                            */
/*                                                                    */
/* EXTERNAL REFERENCES:  GetHIDReportLength                           */
/*    ROUTINES:                                                       */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
void ProtocolSet( PRP_GENIOCTL pRP_GENIOCTL )
{
   USBRB FAR    *processedRB;
   USHORT       deviceIndex;
   UCHAR        indexToInterface;
   USHORT       hidReportLength;

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

   // extract device&interface indexes from request block
   deviceIndex=LOUSHORT(processedRB->requestData2);
   indexToInterface=(UCHAR)(HIUSHORT(processedRB->requestData2)+1);

#ifdef   DEBUG
   if (pRP_GENIOCTL->rph.Status!=USB_IDC_RC_OK)
   {  // stop processing if failed to set configuration
      dsPrint1(DBG_CRITICAL, "HID : ProtocolSet failed. Status=%x\r\n", pRP_GENIOCTL->rph.Status);
   }
#endif

   // find out HID interface index
   for (;indexToInterface<gActiveDevices[deviceIndex].devConf->bNumInterfaces;indexToInterface++)
   {
      hidReportLength=GetHIDReportLength(gActiveDevices[deviceIndex].pDeviceInfo->configurationData, 
                                         gActiveDevices[deviceIndex].pDeviceInfo->descriptor.bNumConfigurations, 
                                         gActiveDevices[deviceIndex].pDeviceInfo->bConfigurationValue, indexToInterface);
      if (hidReportLength)
         break;
   }

   gActiveDevices[deviceIndex].protocolSetIndex=indexToInterface;
   if (gActiveDevices[deviceIndex].protocolSetIndex<gActiveDevices[deviceIndex].devConf->bNumInterfaces)
      // issue request to read in report descriptor for current interface
      GetHIDReport( pRP_GENIOCTL, deviceIndex, indexToInterface );
   else
      AskClientsToServe( pRP_GENIOCTL );  // call all the registered clients
}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  GetHIDReport                                     */
/*                                                                    */
/* DESCRIPTIVE NAME:  Get HID report data routine                     */
/*                                                                    */
/* FUNCTION:  This routine issues I/O request to read in HID report   */
/*            data for specific interface.                            */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  GetHIDReport                                        */
/*    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              */
/*                                                                    */
/* INTERNAL REFERENCES:  HIDAcceptIO                                  */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:  setmem                                       */
/*    ROUTINES:          GetHIDReportLength                           */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
void GetHIDReport( PRP_GENIOCTL pRP_GENIOCTL, USHORT deviceIndex, UCHAR interfaceIndex )
{
   USBRB FAR    *processedRB;
   USBRB        hcdReqBlock;
   RP_GENIOCTL  rp_USBReq;

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

   if (pRP_GENIOCTL->rph.Status!=USB_IDC_RC_OK)
   {  // stop processing if failed to set configuration

#ifdef   DEBUG
      dsPrint1(DBG_CRITICAL, "HID : ConfigurationSet failed. Status=%x\r\n", pRP_GENIOCTL->rph.Status);
#endif
      return;
   }

   setmem(gActiveDevices[deviceIndex].reportData,0,sizeof(gActiveDevices[deviceIndex].reportData));

   hcdReqBlock.controllerId=gActiveDevices[deviceIndex].pDeviceInfo->ctrlID;
   hcdReqBlock.deviceAddress=gActiveDevices[deviceIndex].pDeviceInfo->deviceAddress; // use default address to set address for unconfigured devices
   hcdReqBlock.endPointId=USB_DEFAULT_CTRL_ENDPT;    // default control endpoint
   hcdReqBlock.status=0;        // not used
   hcdReqBlock.flags=USRB_FLAGS_TTYPE_SETUP;
   hcdReqBlock.buffer1=(PUCHAR)&gActiveDevices[deviceIndex].stdPacket;       // pointer to get descriptor packet
   gActiveDevices[deviceIndex].stdPacket.bmRequestType=REQTYPE_XFERDIR_DEVTOHOST|REQTYPE_RECIPIENT_INTERFACE;    // Characteristics of request
   gActiveDevices[deviceIndex].stdPacket.bRequest=REQ_GET_DESCRIPTOR;         // get HID descriptor
   gActiveDevices[deviceIndex].stdPacket.wValue=MAKEUSHORT(0,HID_CLASS_DESCRIPTORS_REPORT);  // report index (always 0 for HID) and descriptor ID
   gActiveDevices[deviceIndex].stdPacket.wIndex=interfaceIndex;    // HID interface index
   gActiveDevices[deviceIndex].stdPacket.wLength=  // get report descriptor length from configuration data
                                                   GetHIDReportLength(gActiveDevices[deviceIndex].pDeviceInfo->configurationData, 
                                                                      gActiveDevices[deviceIndex].pDeviceInfo->descriptor.bNumConfigurations, 
                                                                      gActiveDevices[deviceIndex].pDeviceInfo->bConfigurationValue, interfaceIndex);
   hcdReqBlock.buffer1Length=sizeof(gActiveDevices[deviceIndex].stdPacket); // setup packet size
   hcdReqBlock.buffer2=(PUCHAR)&gActiveDevices[deviceIndex].reportData;     // no additonal data to be sent to/from host
   hcdReqBlock.buffer2Length=gActiveDevices[deviceIndex].stdPacket.wLength;  // to complete this request
   hcdReqBlock.serviceTime=USB_DEFAULT_SRV_INTV;   // use default service frequency to get report descriptor
   hcdReqBlock.maxPacketSize=USB_DEFAULT_PKT_SIZE; // use default packet size to get report descriptor
   hcdReqBlock.maxErrorCount=USB_MAX_ERROR_COUNT;  // use maximum error retry count to get report descriptor
   hcdReqBlock.usbIDC=(PUSBIDCEntry)HIDidc;        // set HID IDC routine to finish IRQ processing
   hcdReqBlock.usbDS=GetDS(); // set data segment value
   hcdReqBlock.category=USB_IDC_CATEGORY_CLASS;          // set CLASS layer as IRQ processor
   hcdReqBlock.requestData1=HID_IRQ_STATUS_SETPROTOCOL;  // USBD I/O call type ID - set protocol
   hcdReqBlock.requestData2=MAKEULONG(deviceIndex,interfaceIndex);   // save device and interface indexes
   hcdReqBlock.requestData3=0;                        // not used

   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_ACCIO;
   rp_USBReq.ParmPacket=(PVOID)&hcdReqBlock;

   HIDAcceptIO( (RP_GENIOCTL FAR *)&rp_USBReq );
}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  SetProtocol                                      */
/*                                                                    */
/* DESCRIPTIVE NAME:  Set HID protocol routine                        */
/*                                                                    */
/* FUNCTION:  This routine initiates set protocol I/O request.        */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  SetProtocol                                         */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP_GENIOCTL                                  */
/*                                                                    */
/* EXIT-NORMAL:  n/a                                                  */
/*                                                                    */
/* EXIT-ERROR:   n/a                                                  */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  ProtocolSet                                  */
/*    ROUTINES:          HIDAcceptIO                                  */
/*                       HIDProcessReport                             */
/*                                                                    */
/* EXTERNAL REFERENCES:  GetInterfaceDPtr                             */
/*    ROUTINES:                                                       */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
void SetProtocol( PRP_GENIOCTL pRP_GENIOCTL )
{
   USBRB FAR    *processedRB;
   USBRB        hcdReqBlock;
   RP_GENIOCTL  rp_USBReq;
   USHORT       deviceIndex;
   UCHAR        indexToInterface;
   DeviceInterface FAR *interfaceDesc;


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

   deviceIndex=LOUSHORT(processedRB->requestData2);
   indexToInterface=(UCHAR)HIUSHORT(processedRB->requestData2);

   interfaceDesc=GetInterfaceDPtr(gActiveDevices[deviceIndex].pDeviceInfo->configurationData, 
                                  gActiveDevices[deviceIndex].pDeviceInfo->descriptor.bNumConfigurations, 
                                  gActiveDevices[deviceIndex].pDeviceInfo->bConfigurationValue, indexToInterface);

   // process received report data
   gActiveDevices[deviceIndex].reportItemIndex=HIDProcessReport(gActiveDevices[deviceIndex].reportItemIndex,
                                                                indexToInterface, gActiveDevices[deviceIndex].reportData, processedRB->buffer2Length);

#ifdef   DEBUG
   dsPrint4(DBG_DETAILED, "HID : SetProtocol idesc=%lx, numc=%d,conf=%d,intf=%d\r\n",
            (ULONG)interfaceDesc,gActiveDevices[deviceIndex].pDeviceInfo->descriptor.bNumConfigurations,
            gActiveDevices[deviceIndex].pDeviceInfo->bConfigurationValue,
            indexToInterface);
   if (interfaceDesc)
      dsPrint1(DBG_DETAILED, "HID : SetProtocol subclss=%d\r\n",
               interfaceDesc->bInterfaceSubClass);
#endif

   // bypass set protocol for non-boot class devices
   if (!interfaceDesc || interfaceDesc->bInterfaceSubClass!=DEV_SUBCLASS_HIDBOOTSUBCLASS)
   {  // 
      ProtocolSet( pRP_GENIOCTL );
      return;
   }

   hcdReqBlock.controllerId=processedRB->controllerId;
   hcdReqBlock.deviceAddress=processedRB->deviceAddress;
   hcdReqBlock.endPointId=USB_DEFAULT_CTRL_ENDPT;    // default control endpoint
   hcdReqBlock.status=0;        // not used
   hcdReqBlock.flags=USRB_FLAGS_TTYPE_SETUP;
   hcdReqBlock.buffer1=(PUCHAR)&gActiveDevices[deviceIndex].stdPacket;       // pointer to set device address setup packet
   gActiveDevices[deviceIndex].stdPacket.bmRequestType=REQTYPE_TYPE_CLASS|REQTYPE_RECIPIENT_INTERFACE;    // Characteristics of request
   gActiveDevices[deviceIndex].stdPacket.bRequest=HID_REQUEST_SET_PROTOCOL;   // HID class set protocol request
   gActiveDevices[deviceIndex].stdPacket.wValue=HID_PROTOCOL_TYPE_REPORT;     // required HID protocol type
   gActiveDevices[deviceIndex].stdPacket.wIndex=indexToInterface;             // interface to be modified
   gActiveDevices[deviceIndex].stdPacket.wLength=0;          // not used
   hcdReqBlock.buffer1Length=sizeof(gActiveDevices[deviceIndex].stdPacket); // setup packet size
   hcdReqBlock.buffer2=NULL;     // no additonal data to be sent to/from host
   hcdReqBlock.buffer2Length=0;  // to complete this request
   hcdReqBlock.serviceTime=USB_DEFAULT_SRV_INTV;   // use default service frequency to get report descriptor
   hcdReqBlock.maxPacketSize=USB_DEFAULT_PKT_SIZE; // use default packet size to get report descriptor
   hcdReqBlock.maxErrorCount=USB_MAX_ERROR_COUNT;  // use maximum error retry count to get report descriptor
   hcdReqBlock.usbIDC=(PUSBIDCEntry)HIDidc;        // set HID IDC routine to finish IRQ processing
   hcdReqBlock.usbDS=GetDS(); // set data segment value
   hcdReqBlock.category=USB_IDC_CATEGORY_CLASS;        // set CLASS layer as IRQ processor
   hcdReqBlock.requestData1=HID_IRQ_STATUS_REPRETRIEVED;  // HID I/O call type ID - report retrieved
   hcdReqBlock.requestData2=MAKEULONG(deviceIndex,indexToInterface); // save device and interface indexes
   hcdReqBlock.requestData3=0;                        // not used

   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_ACCIO;
   rp_USBReq.ParmPacket=(PVOID)&hcdReqBlock;

   HIDAcceptIO( (RP_GENIOCTL FAR *)&rp_USBReq );

#ifdef   DEBUG
   dsPrint2(DBG_IRQFLOW, "HID : SetProtocol ended. Status=%x, Interface=%d\r\n", pRP_GENIOCTL->rph.Status, indexToInterface);
#endif

}

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  AskClientsToServe                                */
/*                                                                    */
/* DESCRIPTIVE NAME:  Ask clients to serve worker routine             */
/*                                                                    */
/* FUNCTION:  This routine calls all the registered client drivers    */
/*            to check current device serviceability.                 */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  AskClientsToServe                                   */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP_GENIOCTL                                  */
/*                                                                    */
/* EXIT-NORMAL:  n/a                                                  */
/*                                                                    */
/* EXIT-ERROR:   n/a                                                  */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  none                                         */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:  USBCallIDC                                   */
/*    ROUTINES:          setmem                                       */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
void AskClientsToServe( PRP_GENIOCTL pRP_GENIOCTL )
{
   USBRB FAR   *processedRB;
   RP_GENIOCTL rp_USBReq;
   USHORT      deviceIndex;
   USHORT      clientIndex;
   USBHIDServe serviceData;

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

   deviceIndex=LOUSHORT(processedRB->requestData2);

#ifdef   DEBUG
   if (pRP_GENIOCTL->rph.Status!=USB_IDC_RC_OK)
   {  // stop processing if failed to set configuration

      dsPrint2(DBG_CRITICAL, "HID : AskClientsToServe failed. Status=%x,devIndex=%d\r\n",
               pRP_GENIOCTL->rph.Status,deviceIndex);
   }
#endif

   if (!gActiveDevices[deviceIndex].pDeviceInfo) // device already detached
      return;

#ifdef   DEBUG
   {
      USHORT   itemIndex;

      for (itemIndex=gActiveDevices[deviceIndex].reportItemIndex;
          itemIndex!=LAST_INDEX; itemIndex=gReportItemData[itemIndex].indexToNextItem)
      {
         dsPrint4(DBG_SPECIFIC, "HID : ReportItems: index=%d,interface=%d, maintype=%d, collind=%d\r\n",
                  itemIndex, gReportItemData[itemIndex].interface, 
                  gReportItemData[itemIndex].mainType,
                  gReportItemData[itemIndex].parColIndex);
         dsPrint4(DBG_SPECIFIC, "HID : ReportItems: reportId=%d,repSize=%d, repCount=%d, usagePage=%x\r\n",
                  gReportItemData[itemIndex].itemFeatures.reportID, 
                  gReportItemData[itemIndex].itemFeatures.reportSize,
                  gReportItemData[itemIndex].itemFeatures.reportCount,
                  gReportItemData[itemIndex].itemFeatures.usagePage);
         dsPrint4(DBG_SPECIFIC, "HID : ReportItems: logmin=%x,logmax=%x, phymin=%x, phymax=%x\r\n",
                  gReportItemData[itemIndex].itemFeatures.logMin, 
                  gReportItemData[itemIndex].itemFeatures.logMax,
                  gReportItemData[itemIndex].itemFeatures.phyMin,
                  gReportItemData[itemIndex].itemFeatures.phyMax);
         dsPrint3(DBG_SPECIFIC, "HID : ReportItems: unit=%lx,unitExponent=%x, usageMin=%d\r\n",
                  gReportItemData[itemIndex].itemFeatures.unit, 
                  gReportItemData[itemIndex].itemFeatures.unitExponent,
                  gReportItemData[itemIndex].localFeatures.usageMin);
         dsPrint3(DBG_SPECIFIC, "HID : ReportItems: usageMax=%d, dMin=%d, dMax=%d\r\n",
                  gReportItemData[itemIndex].localFeatures.usageMax, 
                  gReportItemData[itemIndex].localFeatures.designatorMin,
                  gReportItemData[itemIndex].localFeatures.designatorMax);
         dsPrint2(DBG_SPECIFIC, "HID : ReportItems: stringMin=%x, stringMax=%d\r\n",
                  gReportItemData[itemIndex].localFeatures.stringMin,
                  gReportItemData[itemIndex].localFeatures.stringMax);
      }
   }
#endif

   // fill in service data structure
   serviceData.pDeviceInfo=gActiveDevices[deviceIndex].pDeviceInfo;   // far pointer to device data
   serviceData.devConf=gActiveDevices[deviceIndex].devConf;       // far pointer to device configuartion data
   serviceData.itemData=gReportItemData;
   serviceData.itemUsage=gItemUsage;
   serviceData.itemDesignator=gItemDesignator;
   serviceData.itemString=gItemString;
   serviceData.reportItemIndex=gActiveDevices[deviceIndex].reportItemIndex;
   serviceData.versionFlags=gActiveDevices[deviceIndex].versionFlags;

   // call all the registered client drivers
   for (clientIndex=0; clientIndex<gNoOfRegisteredClients; clientIndex++)
   {
      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;

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

#ifdef   DEBUG
   dsPrint1(DBG_IRQFLOW, "HID : AskClientsToServe  Status=%x\r\n", pRP_GENIOCTL->rph.Status);
#endif
}

