/* SCCSID = "src/dev/usb/HID/HIDPREP.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:  HIDPREP.C                                             */
/*                                                                            */
/*   DESCRIPTIVE NAME:  Human Interface Device Class Report data processing   */
/*                      routines.                                             */
/*                                                                            */
/*   FUNCTION: These routines processes HID report data and creates its       */
/*             linear representation for use in HID client drivers.           */
/*                                                                            */
/*   NOTES:                                                                   */
/*      DEPENDENCIES: None                                                    */
/*      RESTRICTIONS: None                                                    */
/*                                                                            */
/*   ENTRY POINTS:                                                            */
/*             HIDProcessReport                                               */
/*                                                                            */
/*   EXTERNAL REFERENCES:                                                     */
/*                                                                            */
/* Change Log                                                                 */
/*                                                                            */
/*  Mark    yy/mm/dd  Programmer      Comment                                 */
/*  ----    --------  ----------      -------                                 */
/*          98/01/31  MB                                                      */
/*                                                                            */
/**************************** END OF SPECIFICATIONS ***************************/

#include "hid.h"

static BOOL GetItem ( UCHAR FAR * FAR *reportBuffer, UCHAR FAR *lastAddr, UCHAR FAR *tag, UCHAR FAR *type,
                      ULONG FAR *uItemData, LONG FAR *sItemData );
static USHORT GetNewItem( USHORT previousItemIndex, USHORT parColIndex, UCHAR interface );
static USHORT GetNewUsageItem( USHORT parentItemIndex, USHORT usagePage, USHORT usageMin, USHORT usageMax );
static USHORT GetNewDesignator( USHORT parentItemIndex, USHORT designatorMin, USHORT designatorMax );
static USHORT GetNewString( USHORT parentItemIndex, UCHAR stringMin, UCHAR stringMax );
static void FreeUsage ( USHORT firstUsageIndex );
static void FreeDesignator ( USHORT firstDesignatorIndex );
static void FreeStrings ( USHORT firstStringIndex );
/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  HIDProcessReport                                 */
/*                                                                    */
/* DESCRIPTIVE NAME:  Processes HID device Report data.               */
/*                                                                    */
/* FUNCTION:  The function of this routine is process HID report data */
/*            and fill in report item data array for later use.       */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  HIDProcessReport                                     */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  USHORT startIndex - index to 1st report item               */
/*         UCHAR interface - interface index                          */
/*         UCHAR *reportData - pointer to HID Report data             */
/*         USHORT reportLength - HID Report data length               */
/*                                                                    */
/* EXIT-NORMAL: index to 1st report item in gReportItemData table     */
/*                                                                    */
/* EXIT-ERROR:  0xffff                                                */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  GetItem                                      */
/*                       GetNewItem                                   */
/*                       GetNewUsageItem                              */
/*                       GetNewDesignator                             */
/*                       GetNewString                                 */
/*                                                                    */
/* EXTERNAL REFERENCES:  setmem                                       */
/*                       movmem                                       */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
#define  GLOBAL_STACK_DEPTH   3

#define  LF_USAGEMIN_SET      0x01
#define  LF_USAGEMAX_SET      0x02
#define  LF_DSGNTMIN_SET      0x04
#define  LF_DSGNTMAX_SET      0x08
#define  LF_STRNGMIN_SET      0x10
#define  LF_STRNGMAX_SET      0x20

USHORT HIDProcessReport(USHORT startIndex, UCHAR interface, UCHAR *reportData, USHORT reportLength)
{
   ItemFeatures   globalFeatures[GLOBAL_STACK_DEPTH];
   LocalFeatures  localFeatures;
   USHORT         stackIndex=0;
   UCHAR          FAR *currBuff,  FAR *lastBuff, tag, type;
   ULONG          itemData;
   LONG           signedData;
   BOOL           rc=TRUE, needNewItem;
   USHORT         currIndex;
   USHORT         usageCount=0, parColIndex=LAST_INDEX;
   USHORT         newIndex, firstIndex;
   UCHAR          localFeatureFlags;

   currBuff=reportData; lastBuff=reportData+reportLength;
   setmem((PSZ)globalFeatures,0, sizeof(globalFeatures));   // set global defaults
   setmem((PSZ)&localFeatures,0, sizeof(localFeatures));    // set local feature defaults
   localFeatures.indexToUsageList=LAST_INDEX;
   localFeatures.indexToDesignator=LAST_INDEX;
   localFeatures.indexToStrings=LAST_INDEX;
   localFeatureFlags=0; // no features set

   // get index to last used item
   firstIndex=startIndex;
   for (;startIndex!=LAST_INDEX;startIndex=gReportItemData[startIndex].indexToNextItem)
   {
      if (gReportItemData[startIndex].indexToNextItem==LAST_INDEX)
         break;
   }

   currIndex=GetNewItem(startIndex,parColIndex,interface);
   if (currIndex==LAST_INDEX)
      rc=FALSE;
   if (firstIndex==LAST_INDEX)
      firstIndex=currIndex;
   while (GetItem ( &currBuff, lastBuff, &tag, &type, &itemData, &signedData ) && rc)
   {
      switch (type)
      {
      case HID_REPORT_ITYPE_MAIN:
         switch (tag)
         {
         case HID_REPORT_TAGS_MAIN_INPUT:
         case HID_REPORT_TAGS_MAIN_OUTPUT: 
         case HID_REPORT_TAGS_MAIN_FEATURE: 
            needNewItem=TRUE; 
            break;
         case HID_REPORT_TAGS_MAIN_COLL:
            parColIndex=currIndex;
            needNewItem=TRUE; 
            break;
         case HID_REPORT_TAGS_MAIN_ENDCOLL:
            if (parColIndex!=LAST_INDEX)
               parColIndex=gReportItemData[parColIndex].parColIndex;
         default:
            needNewItem=FALSE;
            break;
         }
         if (needNewItem)
         {
            gReportItemData[currIndex].mainType=tag;
            gReportItemData[currIndex].itemFlags=(USHORT)itemData;
            movmem((PSZ)&gReportItemData[currIndex].itemFeatures,
                   (PSZ)&globalFeatures[stackIndex], sizeof(gReportItemData[currIndex].itemFeatures));
            movmem((PSZ)&gReportItemData[currIndex].localFeatures,
                   (PSZ)&localFeatures, sizeof(gReportItemData[currIndex].localFeatures));
            setmem((PSZ)&localFeatures,0, sizeof(localFeatures));     // set local feature defaults
            localFeatures.indexToUsageList=LAST_INDEX;
            localFeatures.indexToDesignator=LAST_INDEX;
            localFeatures.indexToStrings=LAST_INDEX;
            localFeatureFlags=0; // no features set
            currIndex=GetNewItem(currIndex,parColIndex,interface);
            if (currIndex==LAST_INDEX)
               rc=FALSE;
         }
         usageCount=0;
         break; 
      case HID_REPORT_ITYPE_GLOBAL:
         switch (tag)
         {
         case HID_REPORT_TAGS_GLOBAL_UPAGE:
            globalFeatures[stackIndex].usagePage=(USHORT)itemData;
            break; 
         case HID_REPORT_TAGS_GLOBAL_LMIN: 
            globalFeatures[stackIndex].logMin=signedData;
            break;
         case HID_REPORT_TAGS_GLOBAL_LMAX: 
            globalFeatures[stackIndex].logMax=signedData;
            break;
         case HID_REPORT_TAGS_GLOBAL_PMIN: 
            globalFeatures[stackIndex].phyMin=signedData;
            break;
         case HID_REPORT_TAGS_GLOBAL_PMAX: 
            globalFeatures[stackIndex].phyMax=signedData;
            break;
         case HID_REPORT_TAGS_GLOBAL_UEXP: 
            globalFeatures[stackIndex].unitExponent=(UCHAR)itemData;
            break;
         case HID_REPORT_TAGS_GLOBAL_UNIT: 
            globalFeatures[stackIndex].unit=(ULONG)itemData;
            break;
         case HID_REPORT_TAGS_GLOBAL_RSIZE: 
            globalFeatures[stackIndex].reportSize=(ULONG)itemData;
            break;
         case HID_REPORT_TAGS_GLOBAL_RID: 
            globalFeatures[stackIndex].reportID=(UCHAR)itemData;
            break;
         case HID_REPORT_TAGS_GLOBAL_RCOUNT: 
            globalFeatures[stackIndex].reportCount=(ULONG)itemData;
            break;
         case HID_REPORT_TAGS_GLOBAL_PUSH:
            stackIndex++;
            if (stackIndex>=GLOBAL_STACK_DEPTH)
               rc=FALSE;
            else
               globalFeatures[stackIndex-1]=globalFeatures[stackIndex];
            break;
         case HID_REPORT_TAGS_GLOBAL_POP: 
            stackIndex--;
            if (stackIndex==LAST_INDEX)
               rc=FALSE;
            break;
         default:
            break;
         }
         break; 
      case HID_REPORT_ITYPE_LOCAL:
         if (tag==HID_REPORT_TAGS_LOCAL_DELIM && itemData)
            usageCount++;
         if (usageCount<=1)
            switch (tag)
            {
            case HID_REPORT_TAGS_LOCAL_USAGE:
               if ((localFeatureFlags&LF_USAGEMIN_SET) || (localFeatureFlags&LF_USAGEMAX_SET))
               {
                  newIndex=GetNewUsageItem(localFeatures.indexToUsageList,localFeatures.usagePage,
                                           localFeatures.usageMin,localFeatures.usageMax);
                  if (localFeatures.indexToUsageList==LAST_INDEX)
                     localFeatures.indexToUsageList=newIndex;
               }
               if (HIUSHORT(itemData))  // use locally defined usage page
                  localFeatures.usagePage=HIUSHORT(itemData);
               else  // use global usage page if no other specififed
                  localFeatures.usagePage=globalFeatures[stackIndex].usagePage;
               localFeatures.usageMin=(USHORT)itemData;
               localFeatures.usageMax=(USHORT)itemData;
               localFeatureFlags|=LF_USAGEMIN_SET | LF_USAGEMAX_SET;
               break; 
            case HID_REPORT_TAGS_LOCAL_UMIN: 
               if (localFeatureFlags&LF_USAGEMIN_SET)
               {
                  newIndex=GetNewUsageItem(localFeatures.indexToUsageList,localFeatures.usagePage,
                                           localFeatures.usageMin,localFeatures.usageMax);
                  if (localFeatures.indexToUsageList==LAST_INDEX)
                     localFeatures.indexToUsageList=newIndex;
                  localFeatureFlags&=~LF_USAGEMAX_SET;
               }
               if (HIUSHORT(itemData))  // use locally defined usage page
                  localFeatures.usagePage=HIUSHORT(itemData);
               else  // use global usage page if no other specififed
                  localFeatures.usagePage=globalFeatures[stackIndex].usagePage;
               localFeatures.usageMin=(USHORT)itemData;
               localFeatureFlags|=LF_USAGEMIN_SET;
               break;
            case HID_REPORT_TAGS_LOCAL_UMAX: 
               if (localFeatureFlags&LF_USAGEMAX_SET)
               {
                  newIndex=GetNewUsageItem(localFeatures.indexToUsageList,localFeatures.usagePage,
                                           localFeatures.usageMin,localFeatures.usageMax);
                  if (localFeatures.indexToUsageList==LAST_INDEX)
                     localFeatures.indexToUsageList=newIndex;
                  localFeatureFlags&=~LF_USAGEMIN_SET;
               }
               if (HIUSHORT(itemData))  // use locally defined usage page
                  localFeatures.usagePage=HIUSHORT(itemData);
               else  // use global usage page if no other specififed
                  localFeatures.usagePage=globalFeatures[stackIndex].usagePage;
               localFeatures.usageMax=(USHORT)itemData;
               localFeatureFlags|=LF_USAGEMAX_SET;
               break;
            case HID_REPORT_TAGS_LOCAL_DINDEX:
               if ((localFeatureFlags&LF_DSGNTMIN_SET) || (localFeatureFlags&LF_DSGNTMAX_SET))
               {
                  newIndex=GetNewDesignator(localFeatures.indexToDesignator,localFeatures.designatorMin,localFeatures.designatorMax);
                  if (localFeatures.indexToDesignator==LAST_INDEX)
                     localFeatures.indexToDesignator=newIndex;
               }
               localFeatures.designatorMin=(USHORT)itemData;
               localFeatures.designatorMax=(USHORT)itemData;
               localFeatureFlags|=LF_DSGNTMIN_SET | LF_DSGNTMAX_SET;
               break;
            case HID_REPORT_TAGS_LOCAL_DMIN: 
               if (localFeatureFlags&LF_DSGNTMIN_SET)
               {
                  newIndex=GetNewDesignator(localFeatures.indexToDesignator,localFeatures.designatorMin,localFeatures.designatorMax);
                  if (localFeatures.indexToDesignator==LAST_INDEX)
                     localFeatures.indexToDesignator=newIndex;
                  localFeatureFlags&=~LF_DSGNTMAX_SET;
               }
               localFeatures.designatorMin=(USHORT)itemData;
               localFeatureFlags|=LF_DSGNTMIN_SET;
               break;
            case HID_REPORT_TAGS_LOCAL_DMAX: 
               if (localFeatureFlags&LF_DSGNTMAX_SET)
               {
                  newIndex=GetNewDesignator(localFeatures.indexToDesignator,localFeatures.designatorMin,localFeatures.designatorMax);
                  if (localFeatures.indexToDesignator==LAST_INDEX)
                     localFeatures.indexToDesignator=newIndex;
                  localFeatureFlags&=~LF_DSGNTMIN_SET;
               }
               localFeatures.designatorMax=(USHORT)itemData;
               localFeatureFlags|=LF_DSGNTMAX_SET;
               break;
            case HID_REPORT_TAGS_LOCAL_SINDEX: 
               if ((localFeatureFlags&LF_STRNGMIN_SET) || (localFeatureFlags&LF_STRNGMAX_SET))
               {
                  newIndex=GetNewString(localFeatures.indexToStrings,localFeatures.stringMin,localFeatures.stringMax);
                  if (localFeatures.indexToStrings==LAST_INDEX)
                     localFeatures.indexToStrings=newIndex;
               }
               localFeatures.stringMin=(UCHAR)itemData;
               localFeatures.stringMax=(UCHAR)itemData;
               localFeatureFlags|=LF_STRNGMIN_SET | LF_STRNGMAX_SET;
               break;
            case HID_REPORT_TAGS_LOCAL_SMIN: 
               if (localFeatures.stringMin)
               {
                  newIndex=GetNewString(localFeatures.indexToStrings,localFeatures.stringMin,localFeatures.stringMax);
                  if (localFeatures.indexToStrings==LAST_INDEX)
                     localFeatures.indexToStrings=newIndex;
                  localFeatureFlags&=~LF_STRNGMAX_SET;
               }
               localFeatures.stringMin=(UCHAR)itemData;
               localFeatureFlags|=LF_STRNGMIN_SET;
               break;
            case HID_REPORT_TAGS_LOCAL_SMAX: 
               if (localFeatures.stringMax)
               {
                  newIndex=GetNewString(localFeatures.indexToStrings,localFeatures.stringMin,localFeatures.stringMax);
                  if (localFeatures.indexToStrings==LAST_INDEX)
                     localFeatures.indexToStrings=newIndex;
                  localFeatureFlags&=~LF_STRNGMIN_SET;
               }
               localFeatures.stringMax=(UCHAR)itemData;
               localFeatureFlags|=LF_STRNGMAX_SET;
               break;
            case HID_REPORT_TAGS_LOCAL_DELIM: 
               break;
            default:
               break;
            }
         break;
      default:
         break;
      }
   }
   return (firstIndex);
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  GetItem                                          */
/*                                                                    */
/* DESCRIPTIVE NAME:  Get item routine.                               */
/*                                                                    */
/* FUNCTION:  The function of this routine is to extract next report  */
/*            item from report descriptor.                            */
/*                                                                    */
/* NOTES: routine ignores "long" items                                */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  GetItem                                              */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  UCHAR FAR * FAR *reportBuffer - pointer to report          */
/*                        descriptor address (adjusted on each call)  */
/*         UCHAR FAR *lastAddr - last address in descriptor area      */
/*         UCHAR FAR *tag - extracted item tag value                  */
/*         UCHAR FAR *type - extracted item type value                */
/*         ULONG FAR *uItemData - extracted item value (unsigned)     */
/*         LONG FAR *sItemData - extracted item value (signed)        */
/*                                                                    */
/* EXIT-NORMAL: TRUE - item data retrieved                            */
/*                                                                    */
/* EXIT-ERROR:  FALSE - no more items in report descriptor            */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  movmem                                       */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
#define  REPORT_LONG_ITEM_PREFIX    0xfe
#define  REPORT_ITEM_LENGTH_MASK    0x03
#define  REPORT_ITEM_TYPE_MASK      0x0c
#define  REPORT_ITEM_DATA_SIGNFLG   0x80
static BOOL GetItem ( UCHAR FAR * FAR *reportBuffer, UCHAR FAR *lastAddr, UCHAR FAR *tag,
                      UCHAR FAR *type, ULONG FAR *uItemData, LONG FAR *sItemData )
{
   UCHAR    prefix, length;
   *sItemData=0;
   *uItemData=0;
   for (prefix=**reportBuffer; *reportBuffer<lastAddr && prefix==REPORT_LONG_ITEM_PREFIX;
       *reportBuffer+= *((*reportBuffer)+1)+2);   // ignore long items
   if (*reportBuffer>=lastAddr)
      return (FALSE);
   length=(UCHAR)(prefix&REPORT_ITEM_LENGTH_MASK);
   *tag=(UCHAR)(prefix>>4);
   *type=(UCHAR)((prefix&REPORT_ITEM_TYPE_MASK)>>2);
   if (length)
   {
      if (*((*reportBuffer)+length)&REPORT_ITEM_DATA_SIGNFLG)
         *sItemData=(ULONG)-1L;  // to convert to signed
      movmem((PSZ)sItemData, (PSZ)(*reportBuffer)+1, length);
      movmem((PSZ)uItemData, (PSZ)(*reportBuffer)+1, length);
   }
   (*reportBuffer)+=1+length;
   return (TRUE);
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  GetNewItem                                       */
/*                                                                    */
/* DESCRIPTIVE NAME:  Get New item index routine.                     */
/*                                                                    */
/* FUNCTION:  The function of this routine is to find free item in    */
/*            report item table and return index to this item.        */
/*            Allocated item is added as last to item chain.          */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  GetNewItem                                           */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  USHORT previousItemIndex - index to previous report item   */
/*                        or 0xffff for the first item                */
/*         USHORT parColIndex - index to parent collection item or    */
/*                              0xffff if none                        */
/*         UCHAR interface - index to interface                       */
/*                                                                    */
/* EXIT-NORMAL: index to allocated item                               */
/*                                                                    */
/* EXIT-ERROR:  0xffff - no unused items available                    */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
static USHORT GetNewItem(USHORT previousItemIndex, USHORT parColIndex, UCHAR interface)
{
   USHORT      itemIndex;

   for (itemIndex=0; itemIndex<gMaxRepItems; itemIndex++)
   {
      if (!gReportItemData[itemIndex].used)
         break;
   }

   if (itemIndex>=gMaxRepItems)
      return (LAST_INDEX);

   gReportItemData[itemIndex].used=TRUE;
   gReportItemData[itemIndex].interface=interface;
   gReportItemData[itemIndex].mainType=0;
   gReportItemData[itemIndex].itemFlags=0;
   gReportItemData[itemIndex].parColIndex=parColIndex;
   if (previousItemIndex!=LAST_INDEX)
      gReportItemData[previousItemIndex].indexToNextItem=itemIndex;
   gReportItemData[itemIndex].indexToNextItem=LAST_INDEX;

   gReportItemData[itemIndex].localFeatures.indexToUsageList=LAST_INDEX;
   gReportItemData[itemIndex].localFeatures.indexToDesignator=LAST_INDEX;
   gReportItemData[itemIndex].localFeatures.indexToStrings=LAST_INDEX;   

   return (itemIndex);
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  GetNewUsageItem                                  */
/*                                                                    */
/* DESCRIPTIVE NAME:  Get New "usage item" index.                     */
/*                                                                    */
/* FUNCTION:  The function of this routine is to find free item in    */
/*            usage item table and return index to this item.         */
/*            Allocated usage item is added as last to specified      */
/*            usage item chain.                                       */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  GetNewUsageItem                                      */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  USHORT parentItemIndex - index to previous usage item      */
/*                        or 0xffff for the first item                */
/*         USHORT usagePage - current usage page (can be different    */
/*                            from defined in global item data        */
/*         USHORT usageMin - usage minimum value for this item        */
/*         USHORT usageMax - usage maximum value for this item        */
/*                                                                    */
/* EXIT-NORMAL: index to allocated usage item                         */
/*                                                                    */
/* EXIT-ERROR:  0xffff - no unused usage items available              */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
static USHORT GetNewUsageItem( USHORT parentItemIndex, USHORT usagePage, USHORT usageMin, USHORT usageMax )
{
   USHORT      itemIndex, newItemIndex;

   for (newItemIndex=0;newItemIndex<gMaxItemUsages; newItemIndex++)
   {
      if (gItemUsage[newItemIndex].used)
         continue;
      gItemUsage[newItemIndex].used=TRUE;
      break;
   }
   if (newItemIndex>=gMaxItemUsages)
      return (LAST_INDEX);

   if (parentItemIndex!=LAST_INDEX)
   {
      for (itemIndex=parentItemIndex;itemIndex!=LAST_INDEX;
          itemIndex=gItemUsage[itemIndex].indexToNextUsageData)
      {
         if (gItemUsage[itemIndex].indexToNextUsageData!=LAST_INDEX)
            continue;
         gItemUsage[itemIndex].indexToNextUsageData=newItemIndex;
         break;
      }
   }
   gItemUsage[newItemIndex].indexToNextUsageData=LAST_INDEX;
   gItemUsage[newItemIndex].usagePage=usagePage;
   gItemUsage[newItemIndex].usageMin=usageMin;
   gItemUsage[newItemIndex].usageMax=usageMax;

   return (newItemIndex);
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  GetNewDesignator                                 */
/*                                                                    */
/* DESCRIPTIVE NAME:  Get New "designator item" index.                */
/*                                                                    */
/* FUNCTION:  The function of this routine is to find free item in    */
/*            designator item table and return index to this item.    */
/*            Allocated usage item is added as last to specified      */
/*            designator item chain.                                  */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  GetNewDesignator                                     */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  USHORT parentItemIndex - index to previous designator item */
/*                        or 0xffff for the first item                */
/*         USHORT designatorMin - designator minimum value for this   */
/*                                item                                */
/*         USHORT designatorMax - designator maximum value for this   */
/*                                item                                */
/*                                                                    */
/* EXIT-NORMAL: index to allocated designator item                    */
/*                                                                    */
/* EXIT-ERROR:  0xffff - no unused designator items available         */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
static USHORT GetNewDesignator( USHORT parentItemIndex, USHORT designatorMin, USHORT designatorMax )
{
   USHORT      itemIndex, newItemIndex;

   for (newItemIndex=0;newItemIndex<gMaxItemDesignators; newItemIndex++)
   {
      if (gItemDesignator[newItemIndex].used)
         continue;
      gItemDesignator[newItemIndex].used=TRUE;
      break;
   }
   if (newItemIndex>=gMaxItemDesignators)
      return (LAST_INDEX);

   if (parentItemIndex!=LAST_INDEX)
   {
      for (itemIndex=parentItemIndex;itemIndex!=LAST_INDEX;
          itemIndex=gItemDesignator[itemIndex].indexToNextDesignatorData)
      {
         if (gItemDesignator[itemIndex].indexToNextDesignatorData!=LAST_INDEX)
            continue;
         gItemDesignator[itemIndex].indexToNextDesignatorData=newItemIndex;
         break;
      }
   }
   gItemDesignator[newItemIndex].indexToNextDesignatorData=LAST_INDEX;
   gItemDesignator[newItemIndex].designatorMin=designatorMin;
   gItemDesignator[newItemIndex].designatorMax=designatorMax;

   return (newItemIndex);
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  GetNewString                                     */
/*                                                                    */
/* DESCRIPTIVE NAME:  Get New "string item" index.                    */
/*                                                                    */
/* FUNCTION:  The function of this routine is to find free item in    */
/*            string item table and return index to this item.        */
/*            Allocated string item is added as last to specified     */
/*            string item chain.                                      */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  GetNewString                                         */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  USHORT parentItemIndex - index to previous sting index     */
/*                        item or 0xffff for the first item           */
/*         USHORT stringMin - string index minimum value for this item*/
/*         USHORT stringMax - string index maximum value for this item*/
/*                                                                    */
/* EXIT-NORMAL: index to allocated string item                        */
/*                                                                    */
/* EXIT-ERROR:  0xffff - no unused string items available             */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */
/*                                                                    */
/* EXTERNAL REFERENCES:                                               */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
static USHORT GetNewString( USHORT parentItemIndex, UCHAR stringMin, UCHAR stringMax )
{
   USHORT      itemIndex, newItemIndex;

   for (newItemIndex=0;newItemIndex<gMaxItemStrings; newItemIndex++)
   {
      if (gItemString[newItemIndex].used)
         continue;
      gItemString[newItemIndex].used=TRUE;
      break;
   }
   if (newItemIndex>=gMaxItemStrings)
      return (LAST_INDEX);

   if (parentItemIndex!=LAST_INDEX)
   {
      for (itemIndex=parentItemIndex;itemIndex!=LAST_INDEX;
          itemIndex=gItemString[itemIndex].indexToNextStringData)
      {
         if (gItemString[itemIndex].indexToNextStringData!=LAST_INDEX)
            continue;
         gItemString[itemIndex].indexToNextStringData=newItemIndex;
         break;
      }
   }
   gItemString[newItemIndex].indexToNextStringData=LAST_INDEX;
   gItemString[newItemIndex].stringMin=stringMin;
   gItemString[newItemIndex].stringMax=stringMax;

   return (newItemIndex);
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  FreeReportItems                                  */
/*                                                                    */
/* DESCRIPTIVE NAME:  Frees HID device Report data items.             */
/*                                                                    */
/* FUNCTION:  The function of this routine is to release report       */
/*            data items and related usage, designator and string     */
/*            items.                                                  */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  FreeReportItems                                      */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  USHORT firstItemIndex - index to 1st report item           */
/*                                                                    */
/* EXIT-NORMAL: n/a                                                   */
/*                                                                    */
/* EXIT-ERROR:  n/a                                                   */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:  FreeUsage                                    */
/*                       FreeDesignator                               */
/*                       FreeStrings                                  */
/*                                                                    */
/* EXTERNAL REFERENCES:  none                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
void FreeReportItems ( USHORT firstItemIndex )
{
   for (;firstItemIndex!=LAST_INDEX; firstItemIndex=gReportItemData[firstItemIndex].indexToNextItem)
   {
      FreeUsage(gReportItemData[firstItemIndex].localFeatures.indexToUsageList);
      FreeDesignator(gReportItemData[firstItemIndex].localFeatures.indexToDesignator);
      FreeStrings(gReportItemData[firstItemIndex].localFeatures.indexToStrings);
      gReportItemData[firstItemIndex].used=0;
   }
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  FreeUsage                                        */
/*                                                                    */
/* DESCRIPTIVE NAME:  Frees HID device Report usage items.            */
/*                                                                    */
/* FUNCTION:  The function of this routine is to release report       */
/*            usage items.                                            */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  FreeUsage                                            */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  USHORT firstUsageIndex - index to 1st usage item           */
/*                                                                    */
/* EXIT-NORMAL: n/a                                                   */
/*                                                                    */
/* EXIT-ERROR:  n/a                                                   */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  none                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
static void FreeUsage ( USHORT firstUsageIndex )
{
   for (;firstUsageIndex!=LAST_INDEX; firstUsageIndex=gItemUsage[firstUsageIndex].indexToNextUsageData)
   {
      gItemUsage[firstUsageIndex].used=0;
   }
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  FreeDesignator                                   */
/*                                                                    */
/* DESCRIPTIVE NAME:  Frees HID device Report designstor items.       */
/*                                                                    */
/* FUNCTION:  The function of this routine is to release report       */
/*            designator items.                                       */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  FreeDesignator                                       */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  USHORT firstDesignatorIndex - index to 1st designator item */
/*                                                                    */
/* EXIT-NORMAL: n/a                                                   */
/*                                                                    */
/* EXIT-ERROR:  n/a                                                   */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  none                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
static void FreeDesignator ( USHORT firstDesignatorIndex )
{
   for (;firstDesignatorIndex!=LAST_INDEX; firstDesignatorIndex=gItemDesignator[firstDesignatorIndex].indexToNextDesignatorData)
   {
      gItemDesignator[firstDesignatorIndex].used=0;
   }
}

/********************** START OF SPECIFICATIONS ***********************/
/*                                                                    */
/* SUBROUTINE NAME:  FreeStrings                                      */
/*                                                                    */
/* DESCRIPTIVE NAME:  Frees HID device Report string items.           */
/*                                                                    */
/* FUNCTION:  The function of this routine is to release report       */
/*            string items.                                           */
/*                                                                    */
/* NOTES:                                                             */
/*                                                                    */
/* CONTEXT: Task time                                                 */
/*                                                                    */
/* ENTRY POINT:  FreeStrings                                          */
/*    LINKAGE:  CALL NEAR                                             */
/*                                                                    */
/* INPUT:  USHORT firstUsageIndex - index to 1st usage item           */
/*                                                                    */
/* EXIT-NORMAL: n/a                                                   */
/*                                                                    */
/* EXIT-ERROR:  n/a                                                   */
/*                                                                    */
/* EFFECTS:  none                                                     */
/*                                                                    */
/* INTERNAL REFERENCES:                                               */
/*                                                                    */
/* EXTERNAL REFERENCES:  none                                         */
/*                                                                    */
/************************ END OF SPECIFICATIONS ***********************/
static void FreeStrings ( USHORT firstStringIndex )
{
   for (;firstStringIndex!=LAST_INDEX; firstStringIndex=gItemString[firstStringIndex].indexToNextStringData)
   {
      gItemString[firstStringIndex].used=0;
   }
}

