/* SCCSID = "src/dev/usb/USBMOUSE/MOUIDC.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:  MOUIDC.C                                              */
/*                                                                            */
/*   DESCRIPTIVE NAME:  USB Mouse Device Driver inter-device driver           */
/*                      communication routines.                               */
/*                                                                            */
/*   FUNCTION: These routines handle the PDD-PDD IDC for the                  */
/*             USB Mouse DD                                                   */
/*                                                                            */
/*   NOTES:                                                                   */
/*      DEPENDENCIES: None                                                    */
/*      RESTRICTIONS: None                                                    */
/*                                                                            */
/*   ENTRY POINTS:                                                            */
/*                   USBMOUSE  PDD - PDD   IDC Entry Point                    */
/*                                                                            */
/*   EXTERNAL REFERENCES:                                                     */
/*                                                                            */
/* Change Log                                                                 */
/*                                                                            */
/*  Mark    yy/mm/dd  Programmer         Comment                              */
/*  ----    --------  ----------         -------                              */
/*          98/02/01  Vjacheslav Chibis                                       */
/*                                                                            */
/**************************** END OF SPECIFICATIONS ***************************/

#include "mouse.h" /* USB mouse driver master header */

/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  USBMOUSEidc                                     */
/*                                                                    */
/* 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 :  USBMOUSEidc                                         */
/*    LINKAGE  :  CALL FAR                                            */
/*                                                                    */
/* INPUT:     PRP_GENIOCTL pRP_GENIOCTL                               */
/*                                                                    */
/* EXIT-NORMAL:  None                                                 */
/*                                                                    */
/* EXIT-ERROR:  None                                                  */
/*                                                                    */
/* EFFECTS:  None                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:   SetActiveDevice                             */
/*                        SetIdleTime                                 */
/*                        ResetActiveDevice                           */
/*                        CheckService                                */
/*                        CalculateItems                              */
/*                        USBMOUSEProcessIRQ                          */
/*    ROUTINES:                                                       */
/*                                                                    */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */     
/*                                                                    */    
/*    ROUTINES:          ReadInterruptPipe                            */
/*                       SetIdleTime                                  */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/

void FAR USBMOUSEidc( PRP_GENIOCTL pRP_GENIOCTL )
{

   USHORT   st_saved;      /* to remember old status  */
   RP_GENIOCTL pRP;        /* request packet          */
   USBRB    hcdReqBlock;   /* request packet          */
   USHORT   deviceIndex;   /* new device #            */
   UCHAR    interface;     /* interface #             */
   UCHAR    reportID;      /* report #                */



   if( !pRP_GENIOCTL )  /* check for invalid request packet */
      return;

   st_saved=pRP_GENIOCTL->rph.Status; /* we will need it then */

   pRP_GENIOCTL->rph.Status=USB_IDC_RC_OK;  /* set the default status */

   if( pRP_GENIOCTL->rph.Cmd!=CMDGenIOCTL || !pRP_GENIOCTL->ParmPacket )
      pRP_GENIOCTL->rph.Status=USB_IDC_RC_PARMERR;  /* check for invalid IDC call parameters */

   /*
 #ifdef DEBUG
   dsPrint1(DBG_HLVLFLOW, "USBMOUSE :  call : Category=%x \r\n", pRP_GENIOCTL->Category);
 #endif
 */


   if( pRP_GENIOCTL->rph.Status==USB_IDC_RC_OK ) /* if request packet`s parameters ok */
   {

      switch( pRP_GENIOCTL->Category )
      {
         case USB_IDC_CATEGORY_CLIENT:   /* IDC USB client category */
            {
               switch( pRP_GENIOCTL->Function )
               {
                  case USB_IDC_FUNCTION_CHKSERV:  // determination whether a Client Driver can serve a specified device
                     if( CheckService(pRP_GENIOCTL, (UCHAR FAR *)&interface, (UCHAR FAR *)&reportID)==STATUS_DONE )
                     {

                        /* get index for new attached device */
                        deviceIndex=SetActiveDevice(pRP_GENIOCTL, interface, reportID);

                        /* check for appropriate device, if specified */
                        if( deviceIndex==STECODE )
                        {
                           pRP_GENIOCTL->rph.Status=STATUS_DONE|USB_IDC_SERVREJCTD;
#ifdef DEBUG
                           dsPrint(DBG_SPECIFIC, "USBMOUSE : item type mismatch\r\n");
#endif

                           break;
                        }

                        if( (gMouseNo!=FULL_BYTE)&&(deviceIndex!=gMouseNo) )
                        {
#ifdef DEBUG
                           dsPrint2(DBG_SPECIFIC, "USBMOUSE : deviceIndex mismatch! gMouseNo=%d deviceIndex=%d \r\n", gMouseNo, deviceIndex);
#endif
                           //    break;
                        }




                        /* calculate items for new attached device */
                        CalculateItems(deviceIndex);

                        if( gUseIdleTime )           /* if we need it then sets idle time for the device */
                           SetIdleTime(deviceIndex);
                        else
                        {
                           pRP.rph.Status=STATUS_DONE; /* status */
                           /* controller identificator */
                           hcdReqBlock.controllerId=gActiveMice[deviceIndex].pDeviceInfo->ctrlID;
                           /* device address */
                           hcdReqBlock.deviceAddress=gActiveMice[deviceIndex].pDeviceInfo->deviceAddress;

                           hcdReqBlock.requestData2=MAKEULONG(deviceIndex,0); /* save our device # */

                           pRP.ParmPacket=(PVOID)&hcdReqBlock; /* save parampacket`s address */


                           ReadInterruptPipe((RP_GENIOCTL FAR *)&pRP); /* request to get event data from device */
                        }
                     }
                     break;
                  case USB_IDC_FUNCTION_PRCIRQ:   /* process IRQ at Client driver level */
                     pRP_GENIOCTL->rph.Status=st_saved; /* and now we need our save status */
                     USBMOUSEProcessIRQ(pRP_GENIOCTL);/* process IRQ routine */
                     break;
                  case USB_IDC_FUNCTION_DETDEV: /* detach active USB mouse */

                     /* set the appropriate status for deleting detached device from active device list*/
                     pRP_GENIOCTL->rph.Status=ResetActiveDevice(pRP_GENIOCTL)?STERR|STATUS_DONE:STATUS_DONE;

#ifdef DEBUG
                     if( pRP_GENIOCTL->rph.Status!=STATUS_DONE )
                        dsPrint(DBG_DETAILED, "USBMOUSE : ResetActiveDevice FAILED \r\n");
#endif


                     break;

                  default: pRP_GENIOCTL->rph.Status=USB_IDC_RC_WRONGFUNC; /* invalid IDC function */
                     break;
               }
            }
         default:
            pRP_GENIOCTL->rph.Status=USB_IDC_RC_WRONGCAT; /* invalid IDC category */
            break;
      }
   }

   /*
  #ifdef   DEBUG
    dsPrint3(DBG_HLVLFLOW,"USBMOUSE IDC call: Category=%x, Function=%x, Status=%x \r\n",
            pRP_GENIOCTL->Category, pRP_GENIOCTL->Function, pRP_GENIOCTL->rph.Status);
  #endif
  */

}  


/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  USBMOUSEProcessIRQ                               */
/*                                                                    */
/* DESCRIPTIVE NAME:  IRQ procesing extension routine                 */
/*                                                                    */
/* FUNCTION:  This function process IRQ IDC call to USB mouse DD      */
/*                                                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  USBMOUSEProcessIRQ                                  */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  PRP_GENIOCTL pRP_GENIOCTL                                  */
/*                                                                    */
/* EXIT-NORMAL:  N/a                                                  */
/*                                                                    */
/* EXIT-ERROR:  N/a                                                   */
/*                                                                    */
/* EFFECTS:  None                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */  
/*                                                                    */
/*    ROUTINES:          ClearStalled                                 */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/*    ROUTINES:          ReadInterruptPipe                            */
/*                       SendLegacyIRQ                                */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
void USBMOUSEProcessIRQ( PRP_GENIOCTL pRP_GENIOCTL )
{
   USBRB FAR    *processedRB;
   UCHAR oldCat;

#ifdef DEBUG
   USHORT i;
#endif


   if( !pRP_GENIOCTL ) /* mandatory data */
      return;

   /* get pointer to parameter`s packet */
   processedRB=(USBRB FAR *)pRP_GENIOCTL->ParmPacket;


   /* if it was an error reading device data */
   if( processedRB->status&USRB_STATUS_STALLED )
   {
      #ifdef DEBUG
      dsPrint1(DBG_CRITICAL, "USBMOUSE : USBMOUESProcessIRQ : USRB_STATUS_STALLED! adress=%d\r\n", 
      gActiveMice[processedRB->requestData2].pDeviceInfo->deviceAddress);
      #endif



      if( processedRB->requestData1!=CLIENT_IRQ_CLRSTALL ) /* send clear stalled request once only */
      {
         oldCat=pRP_GENIOCTL->Category;
         ClearStalled(pRP_GENIOCTL);
         pRP_GENIOCTL->Category=oldCat;
      }
      return;
   }

   else
      if( processedRB->requestData1==CLIENT_IRQ_CLRSTALL ) /* Clear stalled processed */
   {
#ifdef DEBUG
      dsPrint(DBG_IRQFLOW, "USBMOUSE : USBMOUSEPRocessIRQ :  CLEAR_STALLED OK!\r\n");
#endif

      ReadInterruptPipe(pRP_GENIOCTL); /* request to get event data from the device */
      return;
   }




#ifdef DEBUG
   dsPrint(DBG_IRQFLOW,"USBMOUSE : USBMOUSEProcessIRQ : USBMOUSEProcessIRQ\r\n");
   dsPrint2(DBG_IRQFLOW,"USBMOUSE : requestData1=%x, requestData2=%x\r\n",
   processedRB->requestData1,
   processedRB->requestData2);
#endif

   switch( processedRB->requestData1 )
   {
      case CLIENT_IRQ_SETIDLE:      //Set Idle Time request processed ok

#ifdef DEBUG
         dsPrint1(DBG_IRQFLOW,"USBMOUSE : USBMOUSEProcessIRQ : SETIDLE deviceIndex=%d \r\n", (USHORT)processedRB->requestData2);
#endif
         pRP_GENIOCTL->rph.Status=STATUS_DONE;    //always ok

         ReadInterruptPipe(pRP_GENIOCTL);   //sends ReadPipe request 
         break;//CLIENT_IRQ_SETIDLE

      case CLIENT_IRQ_READPIPE:    //we`ve got an Interrupt Pipe data
#ifdef DEBUG
         dsPrint1(DBG_IRQFLOW,"USBMOUSE : USBMOUSEProcessIRQ : READPIPE  deviceIndex=%d \r\n", (USHORT)processedRB->requestData2);
#endif
         if( pRP_GENIOCTL->rph.Status== USB_IDC_RC_OK ) //if was not an error reading interrupt pipe
         {
            ReadInterruptPipe(pRP_GENIOCTL);  //sends ReadPipe request
            if( ( (USHORT)processedRB->requestData2!=gMouseNo ) && (gMouseNo!=FULL_BYTE) )
               break; // if we are in single device mode and device No. do not match required No in config.sys
            else
               SendLegacyIRQ(pRP_GENIOCTL);      //processes USB mouse event(s)




         }
         break; /* CLIENT_IRQ_READPIPE */
      case CLIENT_IRQ_GETREPORT:
         /* received status data from device */
#ifdef DEBUG
         dsPrint(DBG_SPECIFIC,"USBMOUSE : GetReport successfull\r\n");
         for( i=0;i<3;i++ )
            dsPrint2(DBG_DETAILED,"USBMOUSE:  getReport result intbuffer[%d]=%x\r\n", 
            i,
            gActiveMice[0].IntBuffer[i]
            );
         dsPrint(DBG_SPECIFIC,"USBMOUSE : Report OK\r\n");
#endif
         break; /* CLIENT_IRQ_GETREPORT */

      default :   
#ifdef DEBUG
         dsPrint2(DBG_CRITICAL,"USBMOUSE : USBMOUSEProcessIRQ : UNKNOWN IRQ  type=%d deviceIndex=%d \r\n", 
         (USHORT)processedRB->requestData1,
         (USHORT)processedRB->requestData2);
#endif
         ;
   }

   return;
}



/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  LMOUCallIDC                                      */
/*                                                                    */
/* DESCRIPTIVE NAME: Legacy mouse IDC call                            */
/*                                                                    */
/* FUNCTION:   Process IDC call to  Legacy Mouse Driver               */
/*                                                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT:                                                           */
/*                                                                    */
/* ENTRY POINT :  LMOUCallIDC                                         */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:    PUSBIDCEntry idcEntry                                    */
/*           USHORT callingDS                                         */
/*           RP_GENIOCTL FAR *pRP                                     */
/*                                                                    */
/* EXIT-NORMAL:  n/a                                                  */
/*                                                                    */
/* EXIT-ERROR:   n/a                                                  */
/*                                                                    */
/* EFFECTS:  None                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  none                                         */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*    ROUTINES:                                                       */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/


#pragma alloc_text( RMCode, LMOUcallIDC )

#pragma optimize("eglt", off)

void FAR LMOUcallIDC( PUSBIDCEntry idcEntry, USHORT callingDS, RP_GENIOCTL FAR *pRP )
{

   if( idcEntry && callingDS &&pRP )
   {
      _asm
      {
         push ds
         push ax

         push callingDS
         pop  ds
         mov  ax, 150h     /* USB LMouse Function */
         push  WORD PTR pRP+2
         push  WORD PTR pRP

         call  idcEntry    /* call legacy mouse DD IDC routine */ 

         add   sp,4

         pop  ax      
         pop  ds

      }
   }
   return;
}
   #pragma optimize("", on)
/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  CheckParCol                                      */
/*                                                                    */
/* DESCRIPTIVE NAME: Check parent collection                          */
/*                                                                    */
/* FUNCTION: Check parent collection and search usages                */
/*                                                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT:                                                           */
/*                                                                    */
/* ENTRY POINT :  CheckParCol                                         */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:   ReportItemData FAR *pItemData                             */
/*          USHORT index                                              */
/*                                                                    */
/* EXIT-NORMAL: always                                                */
/*                                                                    */
/* EXIT-ERROR:                                                        */
/*                                                                    */
/* EFFECTS:  None                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  none                                         */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*    ROUTINES:                                                       */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/

USHORT CheckParCol(ReportItemData FAR *pItemData, USHORT index)
{
   ReportItemData FAR *pParCol;


   while( index!=LAST_INDEX )
   {
      pParCol=pItemData+index;

      #ifdef DEBUG
      dsPrint4(DBG_SPECIFIC,"USBMOUSE : CheckParCol : mainType=%d usagePage=%d usageMin=%d usageMax=%d\r\n",
      pParCol->mainType,
      pParCol->itemFeatures.usagePage,
      pParCol->localFeatures.usageMin,
      pParCol->localFeatures.usageMax
      );
      #endif

      if( pParCol->mainType==HID_REPORT_TAGS_MAIN_COLL&&
      pParCol->itemFeatures.usagePage==HID_USAGE_PAGE_GDESKTOP&& /* generic desktop */

      (pParCol->localFeatures.usageMin==HID_GDESKTOP_USAGE_MOUSE||
      pParCol->localFeatures.usageMin==HID_GDESKTOP_USAGE_POINTER)&&

      (pParCol->localFeatures.usageMax==HID_GDESKTOP_USAGE_MOUSE||
      pParCol->localFeatures.usageMin==HID_GDESKTOP_USAGE_POINTER)
      ) break;
      index=pParCol->indexToNextItem;
   }
#ifdef DEBUG
   dsPrint1(DBG_SPECIFIC,"USBMOUSE : CheckParCol : index=%x\r\n", index);
#endif
   return(index);
}
/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  CheckUsage                                       */
/*                                                                    */
/* DESCRIPTIVE NAME:  Check usage                                     */
/*                                                                    */
/* FUNCTION:  Search usages we need to serve a mouse                  */
/*                                                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT:                                                           */
/*                                                                    */
/* ENTRY POINT :  CheckUsage                                          */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:                                                             */
/*                                                                    */
/* EXIT-NORMAL:  always                                               */
/*                                                                    */
/* EXIT-ERROR:                                                        */
/*                                                                    */
/* EFFECTS:  None                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  none                                         */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*    ROUTINES:                                                       */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/

USHORT CheckUsage(LocalFeatures localFeatures, ItemUsage FAR *pUsageData, USHORT IndexToUsageList)
{
   USHORT status;
   ItemUsage FAR *pUData;

   status=0;

   if( (localFeatures.usageMin==HID_GDESKTOP_USAGE_X)&& /* X coordinate */
   (localFeatures.usageMax==HID_GDESKTOP_USAGE_X) )
      status|=AXE_X;
   else
      if( (localFeatures.usageMin==HID_GDESKTOP_USAGE_Y)&& /* Y coordinate */
   (localFeatures.usageMax==HID_GDESKTOP_USAGE_Y) )
      status|=AXE_Y;
   else
      if( (localFeatures.usageMin==HID_GDESKTOP_USAGE_X)&&
   (localFeatures.usageMax==HID_GDESKTOP_USAGE_Y) )
      status|=AXE_X|AXE_Y;

#ifdef DEBUG 
   dsPrint2(DBG_SPECIFIC,"USBMOUSE : CheckUsage : localFeatures.usageMin=%d, localFeatures.usageMax=%d\r\n", 
   localFeatures.usageMin,
   localFeatures.usageMax
   );
   dsPrint1(DBG_SPECIFIC,"USBMOUSE : CheckUsage started. Status=%d\r\n", status);
#endif 


   while( IndexToUsageList!=LAST_INDEX )
   {
      pUData=pUsageData+IndexToUsageList;

#ifdef DEBUG
      dsPrint3(DBG_SPECIFIC,"USBMOUSE :  IndexToUsageList=%d usagemin=%d usageMax=%d\r\n",
      IndexToUsageList, 
      pUData->usageMin,
      pUData->usageMax
      );
#endif
      if( (pUData->usageMin==HID_GDESKTOP_USAGE_X)&&   /* X coordinate */
      (pUData->usageMax==HID_GDESKTOP_USAGE_X) )
         status|=AXE_X;
      else
         if( (pUData->usageMin==HID_GDESKTOP_USAGE_Y)&&   /* Y coorsinate */
      (pUData->usageMax==HID_GDESKTOP_USAGE_Y) )
         status|=AXE_Y;
      else
         if( (pUData->usageMin==HID_GDESKTOP_USAGE_X)&&
      (pUData->usageMax==HID_GDESKTOP_USAGE_Y) )
         status|=AXE_Y|AXE_X;

      IndexToUsageList=pUData->indexToNextUsageData;
   }

#ifdef DEBUG
   dsPrint1(DBG_DETAILED,"USBMOUSE : CheckUsage end. Status=%d\r\n", status);
#endif

   return(status);
}
/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  CheckService                                     */
/*                                                                    */
/* DESCRIPTIVE NAME:  Check device service                            */
/*                                                                    */
/* FUNCTION:   Checks if it can serve the specified device            */
/*                                                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT:                                                           */
/*                                                                    */
/* ENTRY POINT :  CheckService                                        */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:     PRP_GENIOCTL pRP_GENIOCTL                               */
/*            UCHAR FAR *pInterface                                   */
/*            UCHAR FAR *pReportID                                    */
/*                                                                    */
/* EXIT-NORMAL:   STATUS_DONE                                         */
/*                                                                    */
/* EXIT-ERROR:    STATUS_DONE|USB_IDC_SERVREJCTD                      */
/*                                                                    */
/* EFFECTS:  pRP_GENIOCTL->rph.Status                                 */
/*                                                                    */
/* INTERNAL REFERENCES:  NONE                                         */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*    ROUTINES:         GetReportLength                               */
/*                      CheckUsage                                    */
/*                      CheckParCol                                   */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/

USHORT CheckService(PRP_GENIOCTL pRP_GENIOCTL, UCHAR FAR *pInterface, UCHAR FAR *pReportID)
{

   typedef struct _list
   {
      UCHAR type;
      UCHAR reportID;
      UCHAR interface;
   }   List;

#define MAXLIST 0x2F
   List CheckList[MAXLIST]; /* list to save usage data */

   USBHIDServe FAR *ServDevData;

   USHORT reportIndex;
   USHORT count;

   USHORT index_1;
   USHORT index_2;


   ServDevData=(USBHIDServe FAR *)pRP_GENIOCTL->ParmPacket;


#ifdef DEBUG
   dsPrint1(DBG_SPECIFIC,"USBMOUSE : CheckService : itemData=%x\r\n", (ULONG)ServDevData->itemData);
#endif

   pRP_GENIOCTL->rph.Status=STATUS_DONE|USB_IDC_SERVREJCTD; /* set head value */

   reportIndex=ServDevData->reportItemIndex;

   /**********************/
   /* set head values    */
   /**********************/
   *pInterface=0; 
   *pReportID=0;
   count=0;



   while( reportIndex!=LAST_INDEX ) /* while we have report data */
   {
#ifdef DEBUG
      dsPrint2(DBG_SPECIFIC,"USBMOUSE : itemType=%x itemFlags=%x\r\n", ServDevData->itemData[reportIndex].mainType, ServDevData->itemData[reportIndex].itemFlags);

      dsPrint2(DBG_SPECIFIC,"USBMOUSE : reportIndex=%x reportCount=%x\r\n",
      reportIndex,
      ServDevData->itemData[reportIndex].itemFeatures.reportCount
      );

      dsPrint4(DBG_SPECIFIC,"USBMOUSE : usagePage=%d usageMin=%d usageMax=%d mainType=%d \r\n",
      ServDevData->itemData[reportIndex].itemFeatures.usagePage,
      ServDevData->itemData[reportIndex].localFeatures.usageMin,
      ServDevData->itemData[reportIndex].localFeatures.usageMax,
      ServDevData->itemData[reportIndex].mainType);

      dsPrint1(DBG_SPECIFIC, "USBMOUSE : interface=%d\r\n", ServDevData->itemData[reportIndex].interface);
      dsPrint3(DBG_SPECIFIC, "USBMOUSE : reportID=%d reportSize=%d reportCount=%d\r\n",
      ServDevData->itemData[reportIndex].itemFeatures.reportID, 
      ServDevData->itemData[reportIndex].itemFeatures.reportSize,
      ServDevData->itemData[reportIndex].itemFeatures.reportCount
      );

#endif
      /********************/     
      /* check for button */
      /********************/     
      if( ServDevData->itemData[reportIndex].mainType==HID_REPORT_TAGS_MAIN_INPUT&&
      ServDevData->itemData[reportIndex].itemFeatures.usagePage==HID_USAGE_PAGE_BUTTON&&
      ServDevData->itemData[reportIndex].localFeatures.usageMin==1 )
      {
#ifdef DEBUG
         dsPrint(DBG_SPECIFIC,"USBMOUSE : INPUT&BUTTON&usagemin=1\r\n");
         dsPrint3(DBG_SPECIFIC,"USBMOUSE :  reportID=%d reportSize=%d reportCount=%d\r\n",
         ServDevData->itemData[reportIndex].itemFeatures.reportID, 
         ServDevData->itemData[reportIndex].itemFeatures.reportSize,
         ServDevData->itemData[reportIndex].itemFeatures.reportCount
         );

#endif
         if( CheckParCol(ServDevData->itemData, ServDevData->itemData[reportIndex].parColIndex)!=-1 )
         {
            /***********************/
            /* fill out check list */
            /***********************/
            CheckList[count].type=HID_USAGE_PAGE_BUTTON;
            CheckList[count].interface=ServDevData->itemData[reportIndex].interface;
            CheckList[count].reportID=ServDevData->itemData[reportIndex].itemFeatures.reportID;
            count++; /* one more item found */

         }


      }
      /***********************/
      /* check for main type */
      /***********************/
      if( ServDevData->itemData[reportIndex].mainType==HID_REPORT_TAGS_MAIN_INPUT&&
      ServDevData->itemData[reportIndex].itemFeatures.usagePage==HID_USAGE_PAGE_GDESKTOP&&
      CheckUsage(ServDevData->itemData[reportIndex].localFeatures, ServDevData->itemUsage, ServDevData->itemData[reportIndex].localFeatures.indexToUsageList)==AXE_X|AXE_Y )
      {
#ifdef DEBUG
         dsPrint(DBG_SPECIFIC,"USBMOUSE : INPUT&GDESKTOP&usageMin=0x30&usageMax==0x31\r\n");
         dsPrint3(DBG_SPECIFIC,"USBMOUSE :  reportID=%d reportSize=%d reportCount=%d\r\n",
         ServDevData->itemData[reportIndex].itemFeatures.reportID, 
         ServDevData->itemData[reportIndex].itemFeatures.reportSize,
         ServDevData->itemData[reportIndex].itemFeatures.reportCount
         );


#endif

         if( CheckParCol(ServDevData->itemData, ServDevData->itemData[reportIndex].parColIndex)!=-1 )
         {
            /***********************/
            /* fill out check list */
            /***********************/
            CheckList[count].type=HID_USAGE_PAGE_GDESKTOP;
            CheckList[count].interface=ServDevData->itemData[reportIndex].interface;
            CheckList[count].reportID=ServDevData->itemData[reportIndex].itemFeatures.reportID;
            count++; /* one more item found */

         }

      }

      reportIndex=ServDevData->itemData[reportIndex].indexToNextItem;/* get index to the next report */

   }

   /********************************************************************/
   /* check if all found items have the same report ID and Interface # */
   /********************************************************************/
   if( count )
      for( index_1=0; index_1<=count; index_1++ )
         for( index_2=index_1+1; index_2<=count; index_2++ )
         {
            if( (CheckList[index_1].type!=CheckList[index_2].type)&&
            (CheckList[index_1].interface==CheckList[index_2].interface)&&
            (CheckList[index_1].reportID==CheckList[index_2].reportID)
            )
            {
               count=0; /* we don`t need continue checking */
               pRP_GENIOCTL->rph.Status=STATUS_DONE;
               *pInterface=CheckList[index_2].interface; /* Interface # we`ve  got */
               *pReportID=CheckList[index_2].reportID;   /* report ID we`ve got */
               break;

            }
         }


#ifdef DEBUG
   if( pRP_GENIOCTL->rph.Status==STATUS_DONE )
      dsPrint(DBG_HLVLFLOW,"USBMOUSE : Device can be served by driver\r\n");
   else
      dsPrint(DBG_HLVLFLOW,"USBMOUSE : Device CAN NOT be served by driver!\r\n");

   dsPrint2(DBG_SPECIFIC, "USBMOUSE : CheckService : Interface=%d, ReportID=%d\r\n", *pInterface, *pReportID);
#endif

   return(pRP_GENIOCTL->rph.Status);

}


/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  SetActiveDevice                                  */
/*                                                                    */
/* DESCRIPTIVE NAME:                                                  */
/*                                                                    */
/* FUNCTION:  try to add new USB mouse to internal DD`s data stack    */
/*                                                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT:                                                           */
/*                                                                    */
/* ENTRY POINT :  SetActiveDevice                                     */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:                                                             */
/*                                                                    */
/* EXIT-NORMAL:  Index  for new attached mouse                        */
/*                                                                    */
/* EXIT-ERROR: STECODE                                                */
/*                                                                    */
/* EFFECTS:  None                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  none                                         */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*    ROUTINES:          GetReportLength                              */
/*                       GetUsageOffset                               */
/*                       GetUsageSize                                 */
/*                                                                    */
/******************* END     OF  SPECIFICATIONS ***********************/


USHORT SetActiveDevice(PRP_GENIOCTL pRP_GENIOCTL, UCHAR interface, UCHAR reportID)
{
   UCHAR i, j;
   USBHIDServe FAR *ServDevData;
   USHORT       deviceIndex; 



#ifdef DEBUG
   dsPrint2(DBG_SPECIFIC, "USBMOUSE : SetActiveDevice : Interface=%d ReportID=%d\r\n", interface, reportID);
#endif

   /* get pointer to parameter`s packet */
   ServDevData=(USBHIDServe FAR *)pRP_GENIOCTL->ParmPacket;



   for( i=0; i<MAX_DEVICES; i++ )
      if( !gActiveMice[i].used )
      {
         gActiveMice[i].used=1; /* this item is used now */
         gActiveMice[i].pDeviceInfo=ServDevData->pDeviceInfo; //save device information
         gActiveMice[i].ReportInterface=interface; /* save interface #  */

         gActiveMice[i].DeviceData.deviceReportID=reportID;
         gMiceCounter++;
         deviceIndex=i;

         /* get interrupt buffer length for the device */
         gActiveMice[i].intBufferLength=
         GetReportLength(pRP_GENIOCTL,                  /* pointer to request packet */
         HID_REPORT_TAGS_MAIN_INPUT,    /* report type */
         gActiveMice[i].DeviceData.deviceReportID, /* reportID */
         gActiveMice[i].ReportInterface /* interface ID */
         );

#ifdef DEBUG
         dsPrint3(DBG_DETAILED,"USBMOUSE : SetActiveDevice : Device #%d DevAddr=%x served. Total devices=%d \r\n ",
         i,
         gActiveMice[i].pDeviceInfo->deviceAddress,
         gMiceCounter
         );
         dsPrint(DBG_IRQFLOW,"USBMOUSE : SetActiveDevice OK\r\n");
#endif 


/**********************************************************************************/
/***         Let`s get offsets for USB mouse data items (X, Y, Wheel, Buttons)  ***/
/**********************************************************************************/

         gActiveMice[i].DeviceData.items[REPORT_ITEM_AXE_X].itemOffset=
         GetUsageOffset(pRP_GENIOCTL,                             /* pointer to Request packet */
         HID_REPORT_TAGS_MAIN_INPUT,               /* main type */
         gActiveMice[i].DeviceData.deviceReportID, /* report ID */
         gActiveMice[i].ReportInterface,           /* Interface ID*/
         HID_USAGE_PAGE_GDESKTOP,                  /* main usage page */
         HID_GDESKTOP_USAGE_X);                    /* usage ID */

         gActiveMice[i].DeviceData.items[REPORT_ITEM_AXE_Y].itemOffset=
         GetUsageOffset(pRP_GENIOCTL,                              /* pointer to Request packet */
         HID_REPORT_TAGS_MAIN_INPUT,                /* main type */                
         gActiveMice[i].DeviceData.deviceReportID,  /* report ID */                
         gActiveMice[i].ReportInterface,            /* Interface ID*/              
         HID_USAGE_PAGE_GDESKTOP,                   /* main usage page */          
         HID_GDESKTOP_USAGE_Y);                 /* usage ID */

         gActiveMice[i].DeviceData.items[REPORT_ITEM_WHEEL].itemOffset=
         GetUsageOffset(pRP_GENIOCTL,                              /* pointer to Request packet */
         HID_REPORT_TAGS_MAIN_INPUT,                /* main type */                
         gActiveMice[i].DeviceData.deviceReportID,  /* report ID */                
         gActiveMice[i].ReportInterface,            /* Interface ID*/              
         HID_USAGE_PAGE_GDESKTOP,                   /* main usage page */          
         HID_GDESKTOP_USAGE_WHEEL);                 /* usage ID */

         /***********************/
         /* fill button values  */
         /***********************/
         for( j=REPORT_ITEM_BUTTON_1;j<REPORT_ITEM_BUTTON_3+1;j++ )
            gActiveMice[i].DeviceData.items[j].itemOffset=
            GetUsageOffset(pRP_GENIOCTL,                                /* pointer to Request packet */
            HID_REPORT_TAGS_MAIN_INPUT,                  /* main type */                
            gActiveMice[i].DeviceData.deviceReportID,    /* report ID */                
            gActiveMice[i].ReportInterface,              /* Interface ID*/              
            HID_USAGE_PAGE_BUTTON,                       /* main usage page */          
            (j-REPORT_ITEM_BUTTON_1)+1);                 /* usage ID */





/***********************************************************************************/
         gActiveMice[i].DeviceData.items[REPORT_ITEM_AXE_X].itemType=
         GetUsageType(pRP_GENIOCTL,                           /* pointer to Request packet */
         HID_REPORT_TAGS_MAIN_INPUT,                /* main type */                
         gActiveMice[i].DeviceData.deviceReportID,  /* report ID */                
         gActiveMice[i].ReportInterface,            /* Interface ID*/              
         HID_USAGE_PAGE_GDESKTOP,                   /* main usage page */          
         HID_GDESKTOP_USAGE_X);

         if( !gActiveMice[i].DeviceData.items[REPORT_ITEM_AXE_X].itemType&ITEM_TYPE_ARRAY_VARIABLE )
         {
            //array found
#ifdef DEBUG
            dsPrint1(DBG_SPECIFIC, "USBMOUSE : SetActiveDevice : Usage X ARRAY! itemType=%d \r\n", 
            gActiveMice[i].DeviceData.items[REPORT_ITEM_AXE_X].itemType);
#endif
            return(STECODE);
         }

         gActiveMice[i].DeviceData.items[REPORT_ITEM_AXE_Y].itemType=
         GetUsageType(pRP_GENIOCTL,                               /* pointer to Request packet */
         HID_REPORT_TAGS_MAIN_INPUT,                 /* main type */                
         gActiveMice[i].DeviceData.deviceReportID,   /* report ID */                
         gActiveMice[i].ReportInterface,             /* Interface ID*/              
         HID_USAGE_PAGE_GDESKTOP,                    /* main usage page */          
         HID_GDESKTOP_USAGE_Y);                 /* usage ID */

         if( !gActiveMice[i].DeviceData.items[REPORT_ITEM_AXE_Y].itemType&ITEM_TYPE_ARRAY_VARIABLE )
         {
            //array found
#ifdef DEBUG
            dsPrint1(DBG_SPECIFIC, "USBMOUSE : SetActiveDevice : Usage Y ARRAY! itemType=%d \r\n", 
            gActiveMice[i].DeviceData.items[REPORT_ITEM_AXE_Y].itemType);
#endif
            return(STECODE);
         }

         gActiveMice[i].DeviceData.items[REPORT_ITEM_WHEEL].itemType=
         GetUsageType(pRP_GENIOCTL,                               /* pointer to Request packet */
         HID_REPORT_TAGS_MAIN_INPUT,                 /* main type */                
         gActiveMice[i].DeviceData.deviceReportID,   /* report ID */                
         gActiveMice[i].ReportInterface,             /* Interface ID*/              
         HID_USAGE_PAGE_GDESKTOP,                    /* main usage page */          
         HID_GDESKTOP_USAGE_WHEEL); /* usage ID */

         if( !gActiveMice[i].DeviceData.items[REPORT_ITEM_WHEEL].itemType&ITEM_TYPE_ARRAY_VARIABLE )
         {
            //array found
#ifdef DEBUG
            dsPrint1(DBG_SPECIFIC, "USBMOUSE : SetActiveDevice : Usage WHEEL ARRAY! itemType=%d \r\n", 
            gActiveMice[i].DeviceData.items[REPORT_ITEM_WHEEL].itemType);
#endif
            return(STECODE);
         }







         for( j=0; j<REPORT_ITEM_THE_LAST; j++ )
            gActiveMice[i].DeviceData.items[j].used=FALSE;


/**********************************************************************************/
/***         Let`s get sizes for USB mouse data items  (X, Y, Wheel, Buttons)   ***/
/**********************************************************************************/


         gActiveMice[i].DeviceData.items[REPORT_ITEM_AXE_X].itemSize=
         GetUsageSize(pRP_GENIOCTL,                              /* pointer to Request packet */
         HID_REPORT_TAGS_MAIN_INPUT,                /* main type */                
         gActiveMice[i].DeviceData.deviceReportID,  /* report ID */                
         gActiveMice[i].ReportInterface,            /* Interface ID*/              
         HID_USAGE_PAGE_GDESKTOP,                   /* main usage page */          
         HID_GDESKTOP_USAGE_X); /* usage ID */





         gActiveMice[i].DeviceData.items[REPORT_ITEM_AXE_Y].itemSize=
         GetUsageSize(pRP_GENIOCTL,                               /* pointer to Request packet */
         HID_REPORT_TAGS_MAIN_INPUT,                 /* main type */                
         gActiveMice[i].DeviceData.deviceReportID,   /* report ID */                
         gActiveMice[i].ReportInterface,             /* Interface ID*/              
         HID_USAGE_PAGE_GDESKTOP,                    /* main usage page */          
         HID_GDESKTOP_USAGE_Y);                 /* usage ID */

         gActiveMice[i].DeviceData.items[REPORT_ITEM_WHEEL].itemSize=
         GetUsageSize(pRP_GENIOCTL,                               /* pointer to Request packet */
         HID_REPORT_TAGS_MAIN_INPUT,                 /* main type */                
         gActiveMice[i].DeviceData.deviceReportID,   /* report ID */                
         gActiveMice[i].ReportInterface,             /* Interface ID*/              
         HID_USAGE_PAGE_GDESKTOP,                    /* main usage page */          
         HID_GDESKTOP_USAGE_WHEEL);                 /* usage ID */

         /**********************/
         /* fill button values */
         /**********************/
         for( j=REPORT_ITEM_BUTTON_1;j<REPORT_ITEM_BUTTON_3+1;j++ )
            gActiveMice[i].DeviceData.items[j].itemSize=
            GetUsageSize(pRP_GENIOCTL,                                /* pointer to Request packet */
            HID_REPORT_TAGS_MAIN_INPUT,                  /* main type */                
            gActiveMice[i].DeviceData.deviceReportID,    /* report ID */                
            gActiveMice[i].ReportInterface,              /* Interface ID*/              
            HID_USAGE_PAGE_BUTTON,                       /* main usage page */          
            (j-REPORT_ITEM_BUTTON_1)+1);                 /* usage ID */


         /****************************************************************/
         /*  we need it in case, when we have item length more than byte */
         /****************************************************************/
         for( j=0; j<REPORT_ITEM_THE_LAST; j++ )
            if( gActiveMice[i].DeviceData.items[REPORT_ITEM_AXE_X].itemSize>BITS_IN_BYTE )
               if( !gActiveMice[i].DeviceData.items[REPORT_ITEM_AXE_X].itemSize%BITS_IN_BYTE )
                  gActiveMice[i].DeviceData.items[REPORT_ITEM_AXE_X].itemOffset+=
                  (gActiveMice[i].DeviceData.items[REPORT_ITEM_AXE_X].itemSize/BITS_IN_BYTE)*BITS_IN_BYTE-BITS_IN_BYTE;
               else
                  gActiveMice[i].DeviceData.items[REPORT_ITEM_AXE_X].itemOffset+=
                  (gActiveMice[i].DeviceData.items[REPORT_ITEM_AXE_X].itemSize/BITS_IN_BYTE)*BITS_IN_BYTE;






/********************************************************************************************/

         return(deviceIndex); //let`s say index for new device we`ve got
      }


#ifdef DEBUG
   dsPrint(DBG_CRITICAL,"USBMOUSE : SetActiveDevice FAILED\r\n");
#endif

   return(STECODE); //can`t add new device 
}


/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  ResetActiveDevice                                */
/*                                                                    */
/* DESCRIPTIVE NAME:   Reset Active Device                            */
/*                                                                    */
/* FUNCTION:   Delete detached device from active device list         */
/*                                                                    */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT:                                                           */
/*                                                                    */
/* ENTRY POINT :  ResetActiveDevice                                   */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:   PRP_GENIOCTL pRP_GENIOCTL                                 */
/*                                                                    */
/* EXIT-NORMAL:  0                                                    */
/*                                                                    */
/* EXIT-ERROR:   STECODE                                              */
/*                                                                    */
/* EFFECTS:  None                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  none                                         */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:  None                                         */
/*    ROUTINES:                                                       */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/

USHORT ResetActiveDevice(PRP_GENIOCTL pRP_GENIOCTL)
{
   USBDetach FAR *DetachDevData = (USBDetach FAR *)pRP_GENIOCTL->ParmPacket;  /* pointer to parameters packet */
   USHORT i;
   UCHAR j;


   if( !gMiceCounter )
      return(STECODE); //if we have no one active device


   /* search specified device in list and deletes it, if found */
   for( i=0;  i<MAX_DEVICES; i++ )
   {
      if( gActiveMice[i].used )
         if( gActiveMice[i].pDeviceInfo->deviceAddress==DetachDevData->deviceAddress )
         {  // device found
            gActiveMice[i].used=0;
            gMiceCounter--;  /* decrement active mice counter */

            if( gMouseNo!=FULL_BYTE )
               if( !gMiceCounter )
                  gMouseNo=gMouseNoBak;
               else
                  for( j=0; j<MAX_DEVICES; j++ )
                     if( gActiveMice[j].used )
                     {
                        gMouseNo=j;
                        break;
                     }
            #ifdef DEBUG
            dsPrint3(DBG_DETAILED,"USBMOUSE : ResetActiveDevice : Device #%d DevAddr=%x detached. Total devices=%d\r\n",i, DetachDevData->deviceAddress,gMiceCounter);
            #endif
            return(0); /* normal return  */
         }
   }
   return(STECODE); /* can`t delete device */
}



/******************* START OF SPECIFICATIONS **************************/
/*                                                                    */
/* SUBROUTINE NAME:  ClearStalled                                     */
/*                                                                    */
/* DESCRIPTIVE NAME:  Clears stalled communication pipe               */
/*                                                                    */
/* FUNCTION:  This routine calls USBHID driver to clear stalled pipe. */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task Time                                                 */
/*                                                                    */
/* ENTRY POINT :  ClearStalled                                        */
/*    LINKAGE  :  CALL NEAR                                           */
/*                                                                    */
/* INPUT:  RP_GENIOCTL FAR *pRP_GENIOCTL                              */
/*                                                                    */
/* EXIT-NORMAL:  none                                                 */
/*                                                                    */
/* EXIT-ERROR:  none                                                  */
/*                                                                    */
/* EFFECTS:  sets error code in pRP_GENIOCTL->rph.Status              */
/*                                                                    */
/* INTERNAL REFERENCES:  none                                         */
/*    ROUTINES:                                                       */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*    ROUTINES:          USBCallIDC                                   */
/*                                                                    */
/******************* END  OF  SPECIFICATIONS **************************/
void ClearStalled( RP_GENIOCTL FAR *pRP_GENIOCTL)
{
   USBRB FAR            *processedRB; //request packet we`ve got

   /* get pointer to the request packet */
   processedRB=(USBRB FAR *)pRP_GENIOCTL->ParmPacket;

#ifdef   DEBUG
   dsPrint3(DBG_IRQFLOW, "USBMOUSE: ClearStalled: clearing ctrlid=%d,address=%d,endpoint=%d\r\n",
   processedRB->controllerId, processedRB->deviceAddress, processedRB->endPointId);
   dsPrint2(DBG_IRQFLOW,"USBMOUSE : ClearStalled:  requestData1=%x, requestData2=%x\r\n",
   processedRB->requestData1,
   processedRB->requestData2);
#endif


   processedRB->requestData1=CLIENT_IRQ_CLRSTALL; /* save function id for itself*/

   pRP_GENIOCTL->rph.Cmd=CMDGenIOCTL;   // IOCTL
   pRP_GENIOCTL->Category=USB_IDC_CATEGORY_CLASS; //set IDC category
   pRP_GENIOCTL->Function=USB_IDC_FUNCTION_CLRSTALL; // set IDC function     

   USBCallIDC( gpUSBHIDIDC, gdsUSBIDC, pRP_GENIOCTL ); //call HID to process 

}


/******************* START OF SPECIFICATIONS *****************************/
/*                                                                       */
/* SUBROUTINE NAME:  CalculateItems                                      */
/*                                                                       */
/* DESCRIPTIVE NAME:   Calculate Items                                   */
/*                                                                       */
/* FUNCTION: Calculates data we need to get items from Interrupt buffer  */
/*                                                                       */
/*                                                                       */
/* NOTES:                                                                */
/*                                                                       */
/* CONTEXT:                                                              */
/*                                                                       */
/* ENTRY POINT :  CalculateItems                                         */
/*    LINKAGE  :  CALL NEAR                                              */
/*                                                                       */
/* INPUT:  USHORT deviceIndex                                            */
/*                                                                       */
/* EXIT-NORMAL: n/a                                                      */
/*                                                                       */
/* EXIT-ERROR:  n/a                                                      */
/*                                                                       */
/* EFFECTS:  None                                                        */
/*                                                                       */
/* INTERNAL REFERENCES:  none                                            */
/*    ROUTINES:                                                          */
/*                                                                       */
/* EXTERNAL REFERENCES:   none                                           */
/*    ROUTINES:                                                          */
/*                                                                       */
/******************* END  OF  SPECIFICATIONS *****************************/
#pragma optimize("eglt", off)
void CalculateItems(USHORT deviceIndex)
{
   UCHAR    mask;
   USHORT   i;
   UCHAR    isize;
   UCHAR    StartPosInByte;
   #define  ONE 1;



   for( i=0; i<REPORT_ITEM_THE_LAST; i++ )
   {
      /****************************************************************/
      /* calculate mask to get bit items in byte                      */
      /****************************************************************/


      /* old stuff */
      /*
      mask=(UCHAR)((gActiveMice[deviceIndex].DeviceData.items[i].itemOffset+             
                    gActiveMice[deviceIndex].DeviceData.items[i].itemSize)%BITS_IN_BYTE);

      gActiveMice[deviceIndex].DeviceData.items[i].mask=mask?mask:(UCHAR)FULL_BYTE;
      */


      /* 07/06/1998*/
      StartPosInByte=(UCHAR)((gActiveMice[deviceIndex].DeviceData.items[i].itemOffset+             
      gActiveMice[deviceIndex].DeviceData.items[i].itemSize)%BITS_IN_BYTE);



      isize=(UCHAR)gActiveMice[deviceIndex].DeviceData.items[i].itemSize; 


      _asm{
         cmp StartPosInByte, 0
         je  noSt
         push cx
         push ax

         xor  ax, ax
         mov  mask, al
         lp:
         mov  cl, StartPosInByte 
         dec  cl
         add  cl, al
         mov  ch, ONE
         shl  ch, cl
         or   mask, ch
         inc  ax
         cmp  al, isize
         jne  lp

         pop  ax
         pop  cx
         jmp  done
         noSt:
         mov  al, StartPosInByte
         mov  mask, al
         done:
      }

      /* endof 07/06/1998   */


      gActiveMice[deviceIndex].DeviceData.items[i].mask=mask?mask:(UCHAR)FULL_BYTE;


      /****************************************************************/
      /* calculate index in interrupt buffer data for specified mouse */
      /****************************************************************/
      gActiveMice[deviceIndex].DeviceData.items[i].indexInBuffer=
      (UCHAR)(gActiveMice[deviceIndex].DeviceData.items[i].itemOffset>>BITS_DIVIDER);
   }
   return;
}
#pragma optimize("", on)
/******************* START OF SPECIFICATIONS *****************************/
/*                                                                       */
/* SUBROUTINE NAME:  GetUsageType                                        */
/*                                                                       */
/* DESCRIPTIVE NAME:   Get Usage Type                                    */
/*                                                                       */
/* FUNCTION: find  the usage type                                        */
/*                                                                       */
/*                                                                       */
/* NOTES:                                                                */
/*                                                                       */
/* CONTEXT:                                                              */
/*                                                                       */
/* ENTRY POINT :  GetUsageType                                           */
/*    LINKAGE  :  CALL NEAR                                              */
/*                                                                       */
/* INPUT:                                                                */
/*          PRP_GENIOCTL pRP_GENIOCTL                                    */
/*          UCHAR ReportType                                             */
/*          UCHAR ReportID                                               */
/*          UCHAR interface                                              */
/*          USHORT UsagePage                                             */
/*          USHORT UsageID                                               */
/*                                                                       */
/*                                                                       */
/* EXIT-NORMAL: usage type                                               */
/*                                                                       */
/* EXIT-ERROR:  n/a                                                      */
/*                                                                       */
/* EFFECTS:  0                                                           */
/*                                                                       */
/* INTERNAL REFERENCES:  CheckTUsage                                     */
/*    ROUTINES:                                                          */
/*                                                                       */
/* EXTERNAL REFERENCES:   none                                           */
/*    ROUTINES:                                                          */
/*                                                                       */
/******************* END  OF  SPECIFICATIONS *****************************/

USHORT GetUsageType(PRP_GENIOCTL pRP_GENIOCTL, UCHAR ReportType, UCHAR ReportID, UCHAR interface, USHORT UsagePage, USHORT UsageID)
{
   USHORT usageType = 0;
   USHORT UsageMin;
   USHORT UsageMax;


   USBHIDServe FAR *ServDevData;
   USHORT reportIndex;


   ServDevData=(USBHIDServe FAR *)pRP_GENIOCTL->ParmPacket;/* get pointer to parameters packet */

   reportIndex=ServDevData->reportItemIndex;

   while( reportIndex!=LAST_INDEX )
   {

      /* to simplify typing */
      UsageMax=ServDevData->itemData[reportIndex].localFeatures.usageMax;
      UsageMin=ServDevData->itemData[reportIndex].localFeatures.usageMin;

      /* compare interface #, reportiD & usage page first */
      if( (UsagePage==ServDevData->itemData[reportIndex].itemFeatures.usagePage)&&
      (ReportID==ServDevData->itemData[reportIndex].itemFeatures.reportID)&&
      (interface==ServDevData->itemData[reportIndex].interface) )
      {  /* if we`ve found appropriate reportId interface & usage Page, then try to find our usage */
         if( (UsageID<=UsageMax)&&(UsageID>=UsageMin) )
         {
            usageType=ServDevData->itemData[reportIndex].itemFlags;
            break; /* usage is found */
         }
         else
         {  /* we are here if usage is not found in generic item data */
            /* let`s try to find it in secondary usage list */
            usageType=CheckTUsage((ItemFeatures FAR *)&ServDevData->itemData[reportIndex].itemFeatures, ServDevData->itemUsage, ServDevData->itemData[reportIndex].localFeatures.indexToUsageList, UsageID)?ServDevData->itemData[reportIndex].itemFlags:(USHORT)0;

            if( usageType ) break; /* if usage is found */

         }

      }
      reportIndex=ServDevData->itemData[reportIndex].indexToNextItem; /* get the next item */
   }


   return(usageType);
}


/******************* START OF SPECIFICATIONS *****************************/
/*                                                                       */
/* SUBROUTINE NAME:  CheckTUsage                                         */
/*                                                                       */
/* DESCRIPTIVE NAME:   Check Usage                                       */
/*                                                                       */
/* FUNCTION: Check the usage to be existing in the report                */
/*                                                                       */
/*                                                                       */
/* NOTES:                                                                */
/*                                                                       */
/* CONTEXT:                                                              */
/*                                                                       */
/* ENTRY POINT :  CheckTUsage                                            */
/*    LINKAGE  :  CALL NEAR                                              */
/*                                                                       */
/* INPUT:                                                                */
/*          ItemFeatures FAR *pitemFeatures                              */
/*          ItemUsage FAR *pUsageData                                    */
/*          USHORT IndexToUsageList                                      */
/*          USHORT UsageID                                               */
/*                                                                       */
/*                                                                       */
/* EXIT-NORMAL: 1                                                        */
/*                                                                       */
/* EXIT-ERROR:  0                                                        */
/*                                                                       */
/* EFFECTS:  None                                                        */
/*                                                                       */
/* INTERNAL REFERENCES:   none                                           */
/*    ROUTINES:                                                          */
/*                                                                       */
/* EXTERNAL REFERENCES:   none                                           */
/*    ROUTINES:                                                          */
/*                                                                       */
/******************* END  OF  SPECIFICATIONS *****************************/
USHORT CheckTUsage(ItemFeatures FAR *pitemFeatures, ItemUsage FAR *pUsageData, USHORT IndexToUsageList, USHORT UsageID)
{
   ItemUsage FAR *pUData;

   while( IndexToUsageList!=LAST_INDEX )
   {
      pUData=pUsageData+IndexToUsageList;

      if( (UsageID>=pUData->usageMin)&&(UsageID<=pUData->usageMax) )
         return(1); /* we`ve find the usage */

      IndexToUsageList=pUData->indexToNextUsageData;
   }//while

   return(0); /*  0 means that usage is not found */
}


