home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / What's New? / Development Kits / Mac OS / USB DDK 1.4.6f4 / Examples / MouseModule / MouseModule.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-25  |  22.2 KB  |  668 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        MouseModule.c
  3.  
  4.     Contains:    HID Module for USB Mouse
  5.  
  6.     Version:    xxx put version here xxx
  7.  
  8.     Copyright:    © 1997-1999 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11.  
  12.  
  13. /*
  14.     Notes to developers:
  15.     
  16.     1. The WatchDog functionality is *NOT* needed in your drivers.  It is part of an experiment to determine
  17.     if IntReads are ever dropped on the floor.  It was left in (but disabled) and checked into the 
  18.     projector database so that the coding effort wasn't lost.  We do not believe that IntReads are lost, so
  19.     your drivers should not need this WatchDog functionality.
  20.     
  21.     2. Apple reserves the right to do the following:
  22.         Release Mouse or Keyboard drivers that are vendor specific for Apple products
  23.         Release said mouse or keyboard drivers in binary form (but not necessarily in source form)
  24.         Prevent 3rd parties from writing generic drivers
  25.  
  26. */
  27.  
  28.  
  29. #include <DriverServices.h>
  30. #include <Devices.h>
  31. #include <LowMem.h>
  32. #include <MacTypes.h>
  33. #include <Processes.h>
  34. #include <USB.h>
  35.  
  36. #include "MouseModule.h"
  37.  
  38. enum{
  39.     kCheckEvery = 10000,
  40.     kFastCheck = 1000
  41.     };
  42.  
  43. #ifndef DDKBuild
  44.     #include <USBPriv.h>
  45. #endif
  46.  
  47. #define    EnableWatchDog    0
  48. #define EnableRemoteWakeup 0
  49.  
  50. usbMousePBStruct myMousePB;
  51. usbMousePBStruct watchDogPB;
  52.  
  53. void InitParamBlock(USBReference theInterfaceRef, USBPB * paramblock)
  54. {
  55.     paramblock->usbReference = theInterfaceRef;
  56.     paramblock->pbVersion = kUSBCurrentPBVersion;
  57.     
  58.     paramblock->usb.cntl.WIndex = 0;             
  59.     paramblock->usb.cntl.WValue = 0;
  60.     
  61.     paramblock->usbBuffer = nil;        
  62.     paramblock->usbActCount = 0;
  63.     paramblock->usbReqCount = 0;
  64.     paramblock->usbFlags = 0;
  65.     paramblock->usbOther = 0;
  66.     
  67.     paramblock->usbStatus = noErr;
  68. }
  69.  
  70.  
  71.  
  72. Boolean immediateError(OSStatus err)
  73. {
  74.     return((err != kUSBPending) && (err != noErr) );
  75. }
  76.  
  77. void MouseInitiateTransaction(USBPB *pb)
  78. {
  79. usbMousePBStruct *pMousePB;
  80. OSStatus myErr;
  81.  
  82.     pMousePB = (usbMousePBStruct *)(pb);
  83.     pMousePB->transDepth++;
  84.     if (pMousePB->transDepth < 0)
  85.     {
  86.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth < 0 (initiation)", pMousePB->pb.usbRefcon );
  87.     }
  88.     
  89.     if (pMousePB->transDepth > 1)
  90.     {
  91.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth > 1 (initiation)", pMousePB->pb.usbRefcon );
  92.     }
  93.     
  94.     if (pMousePB->driverRemovalPending)
  95.     {
  96.         pMousePB->pb.usbRefcon = kReturnFromDriver;
  97.         return;
  98.     }
  99.  
  100.     switch(pMousePB->pb.usbRefcon & ~kRetryTransaction)
  101.     {
  102.         case kConfigureInterface:
  103.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  104.             
  105.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  106.             pMousePB->pb.usbRefcon |= kCompletionPending;
  107.             
  108.             myErr = USBConfigureInterface( &pMousePB->pb );
  109.             if(immediateError(myErr))
  110.             {
  111.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kConfigureInterface - immediate error", myErr);
  112.                 pMousePB->pb.usbRefcon = kReturnFromDriver;
  113.             }
  114.             break;
  115.         
  116.         case kSetProtocol:
  117.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  118.             
  119.             pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  120.             pMousePB->pb.usb.cntl.BRequest = kHIDRqSetProtocol;
  121.             pMousePB->pb.usb.cntl.WValue = kHIDBootProtocolValue; 
  122.             pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber;
  123.             
  124.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  125.             pMousePB->pb.usbRefcon |= kCompletionPending;
  126.         
  127.             myErr = USBDeviceRequest(&pMousePB->pb);
  128.             if (immediateError(myErr))
  129.             {
  130.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kSetProtocol - immediate error", myErr);
  131.             }
  132.             break;
  133.             
  134.         case kSetIdleRequest:
  135.             USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Do a SetIdle on non-Apple mice, as some 3rd party mice don't send reports on button up", pMousePB->pipeRef);
  136.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  137.             
  138.             pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  139.             
  140.             pMousePB->pb.usb.cntl.BRequest = kHIDRqSetIdle;
  141.             pMousePB->pb.usb.cntl.WValue = ((24/4)<<8);                 // force a read completion if idle for more than 24ms
  142.             pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber;
  143.             
  144.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  145.             pMousePB->pb.usbRefcon |= kCompletionPending;
  146.  
  147.             myErr = USBDeviceRequest(&pMousePB->pb);
  148.             if(immediateError(myErr))
  149.             {
  150.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kSetIdleRequest - immediate error", myErr);
  151.             }
  152.             break;
  153.  
  154. #if EnableRemoteWakeup
  155.         case kSetRemoteWakeup:
  156.             USBExpertStatusLevel(3, pMousePB->interfaceRef, kMouseModuleName": Set remote wakeup for mouse", pMousePB->pipeRef);
  157.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  158.             
  159.             pMousePB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBDevice);            
  160.             
  161.             pMousePB->pb.usb.cntl.BRequest = kUSBRqSetFeature;
  162.             pMousePB->pb.usb.cntl.WValue = kUSBFeatureDeviceRemoteWakeup; 
  163.             pMousePB->pb.usb.cntl.WIndex = 0;
  164.             
  165.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  166.             pMousePB->pb.usbRefcon |= kCompletionPending;
  167.  
  168.             myErr = USBDeviceRequest(&pMousePB->pb);
  169.             if(immediateError(myErr))
  170.             {
  171.                 USBExpertFatalError(pMousePB->interfaceRef, myErr, kMouseModuleName": set remote wakeup request - immediate error", myErr);
  172.             }
  173.             break;
  174. #endif
  175.  
  176.         case kFindPipe:
  177.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  178.             
  179.             pMousePB->pb.usbFlags = kUSBIn;
  180.             pMousePB->pb.usbClassType = kUSBInterrupt;
  181.             
  182.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  183.             pMousePB->pb.usbRefcon |= kCompletionPending;
  184.         
  185.             myErr = USBFindNextPipe( &pMousePB->pb );
  186.             if((immediateError(myErr)) || (pMousePB->pb.usbBuffer == nil))
  187.             {
  188.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kFindPipe - immediate error", myErr);
  189.                 pMousePB->pb.usbRefcon = kReturnFromDriver;
  190.             }
  191.             
  192.             break;
  193.         
  194.         case kReadInterruptPipe:
  195.             InitParamBlock(pMousePB->pipeRef, &pMousePB->pb);
  196.  
  197.             pMousePB->pb.usbBuffer = (Ptr)pMousePB->hidReport;
  198.             pMousePB->pb.usbReqCount = pMousePB->maxPacketSize;
  199.             pMousePB->pb.usb.cntl.WIndex = pMousePB->interfaceDescriptor.interfaceNumber;    
  200.             
  201.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  202.             pMousePB->pb.usbRefcon |= kCompletionPending;
  203.             #ifndef DDKBuild
  204.             pMousePB->pb.usbFlags |= kUSBDebugAwareFlag;
  205.             #endif
  206.         
  207.             myErr = USBIntRead(&pMousePB->pb);
  208.             if(immediateError(myErr))
  209.             {
  210.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": Read Interrupt Pipe (ImmediateError)", myErr);
  211.             }
  212.             break;
  213.             
  214.         case kResetMouse:
  215.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  216.             
  217.             pMousePB->pb.usbRefcon |= kCompletionPending;
  218.             pMousePB->pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  219.  
  220.             myErr = USBResetDevice( &pMousePB->pb );
  221.             
  222.             if(myErr == kUSBDeviceBusy)
  223.             {
  224.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": reset busy, backing off", myErr);
  225.                 pMousePB->pb.usbReqCount = 100;
  226.                 pMousePB->pb.usbRefcon = kResetMouseDelay | kCompletionPending;
  227.                 USBDelay(  &pMousePB->pb );
  228.             }
  229.             else if(immediateError(myErr))
  230.             {
  231.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kResetMouse - immediate error", myErr);
  232.                 pMousePB->pb.usbRefcon = kReturnFromDriver;
  233.             }
  234.             break;
  235.  
  236.         case kGetPortStatus:
  237.             InitParamBlock(pMousePB->interfaceRef, &pMousePB->pb);
  238.             pMousePB->pb.usbRefcon |= kCompletionPending;
  239.             myErr = USBPortStatus(  &pMousePB->pb );
  240.             if(myErr == kUSBDeviceBusy)
  241.             {
  242.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": status busy, backing off", myErr);
  243.                 pMousePB->pb.usbReqCount = 100;
  244.                 pMousePB->pb.usbRefcon = kPortStatusDelay | kCompletionPending;
  245.                 USBDelay(  &pMousePB->pb );
  246.             }
  247.             else if(immediateError(myErr))
  248.             {
  249.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": kGetPortStatus - immediate error", myErr);
  250.                 pMousePB->pb.usbRefcon = kReturnFromDriver;
  251.             }
  252.             break;
  253.  
  254.         default:
  255.             USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": Transaction initiated with bad refcon value", pMousePB->pb.usbRefcon);
  256.             pMousePB->pb.usbRefcon = kUndefined + kReturnFromDriver;
  257.             break;
  258.     }
  259.     
  260. // At this point the control is returned to the system.  If a USB transaction
  261. // has been initiated, then it will call the Complete procs
  262. // (below) to handle the results of the transaction.
  263. }
  264.  
  265. void WatchDogCompletionProc(USBPB *pb)
  266. {
  267. usbMousePBStruct *pWatchDogPB;
  268. OSStatus myErr;
  269. UInt32    delayTime = 0;
  270.  
  271.     pWatchDogPB = (usbMousePBStruct *)(pb);
  272.     if (!pWatchDogPB->driverRemovalPending)
  273.     {
  274.         delayTime = 50;        // come back in 50ms if we're currently processing a completion callback
  275.         if (myMousePB.pb.usbRefcon & kCompletionInProgess)
  276.         {
  277.             USBExpertStatusLevel(5, pWatchDogPB->interfaceRef, kMouseModuleName": Watchdog occurred while processing a completion callback (check again in 50ms)", myMousePB.pb.usbRefcon);
  278.         }
  279.         else
  280.         {
  281.             switch(pWatchDogPB->watchDogState)
  282.             {
  283.                 case kDelay10Seconds:
  284.                     
  285.                     if (pWatchDogPB->watchDogActivityFlag)
  286.                     {
  287.                         USBExpertStatusLevel(5, pWatchDogPB->interfaceRef, kMouseModuleName": Watchdog - Mouse activity detected", pWatchDogPB->watchDogState);
  288.                         delayTime = kCheckEvery;
  289.                         pWatchDogPB->watchDogAbortFlag = false;
  290.                     }
  291.                     else
  292.                     {
  293.                         USBExpertStatusLevel(5, pWatchDogPB->interfaceRef, kMouseModuleName": Watchdog - No mouse activity detected, aborting pipe", pWatchDogPB->watchDogState);
  294.                         delayTime = kFastCheck;
  295.                         pWatchDogPB->watchDogState = kCheckForAbort;
  296.                     }
  297.                     break;
  298.         
  299.                 case kCheckForAbort:
  300.                     delayTime = kCheckEvery;
  301.                     pWatchDogPB->watchDogState = kDelay10Seconds;
  302.                     
  303.                     if (pWatchDogPB->watchDogAbortFlag)
  304.                     {
  305.                         USBExpertStatusLevel(5, pWatchDogPB->interfaceRef, kMouseModuleName": Watchdog - Abort detected in completion routine", pWatchDogPB->watchDogState);
  306.                     }
  307.                     else
  308.                     {
  309.                         USBExpertStatusLevel(4, pWatchDogPB->interfaceRef, kMouseModuleName": Watchdog - No abort detected, restarting int read", pWatchDogPB->watchDogState);
  310.                         InitParamBlock(myMousePB.pipeRef, &myMousePB.pb);
  311.             
  312.                         myMousePB.pb.usbBuffer = (Ptr)myMousePB.hidReport;
  313.                         myMousePB.pb.usbReqCount = myMousePB.maxPacketSize;
  314.                         myMousePB.pb.usb.cntl.WIndex = myMousePB.interfaceDescriptor.interfaceNumber;    
  315.                         
  316.                         myMousePB.pb.usbCompletion = (USBCompletion)MouseCompletionProc;
  317.                         myMousePB.pb.usbRefcon = kReadInterruptPipe + kCompletionPending;
  318.                         #ifndef DDKBuild
  319.                         myMousePB.pb.usbFlags |= kUSBDebugAwareFlag;
  320.                         #endif
  321.                     
  322.                         myErr = USBIntRead(&myMousePB.pb);
  323.                         if(immediateError(myErr))
  324.                         {
  325.                             USBExpertFatalError(myMousePB.interfaceRef, kUSBInternalErr, kMouseModuleName": Watchdog - Read Interrupt Pipe (ImmediateError)", myErr);
  326.                         }
  327.                     }
  328.                     pWatchDogPB->watchDogAbortFlag = false;
  329.                     break;
  330.                     
  331.             }
  332.             pWatchDogPB->watchDogActivityFlag = false;
  333.             pWatchDogPB->watchDogAbortFlag = false;
  334.             if (pWatchDogPB->watchDogState == kCheckForAbort)
  335.             {
  336.                 USBAbortPipeByReference(pWatchDogPB->pipeRef);
  337.             }
  338.         }
  339.         InitParamBlock( pWatchDogPB->interfaceRef, &pWatchDogPB->pb );
  340.         
  341.         pWatchDogPB->pb.usbBuffer = 0;
  342.         pWatchDogPB->pb.usbActCount = 0;
  343.         pWatchDogPB->pb.usbReqCount = delayTime;            
  344.         
  345.         pWatchDogPB->pb.usbRefcon = 0;
  346.         pWatchDogPB->pb.usbCompletion = (USBCompletion)WatchDogCompletionProc;
  347.         
  348.         USBDelay(&pWatchDogPB->pb);
  349.         
  350.     }
  351.     return;
  352. }
  353.  
  354.  
  355. void MouseCompletionProc(USBPB *pb)
  356. {
  357. usbMousePBStruct     *pMousePB;
  358. unsigned char        * errstring;
  359. USBPipeState         pipeState;
  360.  
  361. #if EnableWatchDog
  362. OSStatus            myErr;
  363. #endif
  364.  
  365.     pMousePB = (usbMousePBStruct *)(pb);
  366.     pMousePB->transDepth--;
  367.     if (pMousePB->transDepth < 0)
  368.     {
  369.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth < 0 (completion)", pMousePB->pb.usbRefcon );
  370.     }
  371.     
  372.     if (pMousePB->transDepth > 1)
  373.     {
  374.         USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": transDepth > 1 (completion)", pMousePB->pb.usbRefcon );
  375.     }
  376.     
  377.     pMousePB->pb.usbRefcon |= kCompletionInProgess;                                            // make certain the watchdog routine doesn't race us
  378.     
  379.     if( (pMousePB->pb.usbStatus != noErr) && ((pMousePB->pb.usbRefcon & kStageMask) != kGetPortStatus) )        // was there an error?
  380.     {
  381.         switch(pMousePB->pb.usbRefcon & kStageMask)                                            // yes, so show where the error occurred
  382.         {
  383.             case kSetProtocol:                    errstring = kMouseModuleName": Error during kSetProtocol"; break;
  384.             case kSetIdleRequest:                  errstring = kMouseModuleName": Error during kSetIdleRequest"; break;
  385. #if EnableRemoteWakeup
  386.             case kSetRemoteWakeup:              errstring = kMouseModuleName": Error during kSetRemoteWakeup"; break;
  387. #endif
  388.             case kConfigureInterface:            errstring = kMouseModuleName": Error during kConfigureInterface"; break;
  389.             case kFindPipe:                      errstring = kMouseModuleName": Error during kFindPipe"; break;
  390.             case kReadInterruptPipe:
  391.                 {
  392.                 errstring = kMouseModuleName": Error during ReadInterruptPipe";
  393.                 LMSetMouseButtonState(0x80);    // release any possibly held-down mouse button
  394.                 break;
  395.                 }
  396.             default:                              errstring = kMouseModuleName": Error occurred, but state is unknown"; break;
  397.         };
  398.         
  399.         pMousePB->pb.usbRefcon &= (kStageMask + kCompletionInProgess);                        // save the refcon & completion in progress flag
  400.         pMousePB->pb.usbRefcon |= kRetryTransaction;                                        // set up to retry the transaction
  401.         pMousePB->retryCount--;
  402.         
  403.         // don't put out a fatal error message if an expected abort has occurred
  404.         if ((pMousePB->pb.usbStatus != kUSBAbortedError) || (watchDogPB.watchDogState != kCheckForAbort))
  405.         {
  406.             USBExpertFatalError(pMousePB->interfaceRef, pMousePB->pb.usbStatus, errstring, (pMousePB->pb.usbRefcon & kStageMask));
  407.         }
  408.         
  409.         if ((pMousePB->retryCount == 1) && ((pMousePB->pb.usbRefcon & kStageMask) == kSetIdleRequest))
  410.         {
  411.             USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Device doesn't accept SetIdle", pMousePB->interfaceRef);
  412.             pMousePB->pb.usbRefcon = 
  413. #if EnableRemoteWakeup
  414.             kSetRemoteWakeup
  415. #else
  416.             kFindPipe
  417. #endif
  418.             ;
  419.             pMousePB->pb.usbStatus = noErr;
  420.         }
  421.         else
  422.         {
  423.             if ((pMousePB->pb.usbStatus == kUSBAbortedError) && (watchDogPB.watchDogState == kCheckForAbort))
  424.             {
  425.                 USBExpertStatusLevel(5, pMousePB->interfaceRef, kMouseModuleName": Expected abort has occurred - retry int read", pMousePB->interfaceRef);
  426.                 if (pMousePB->pipeRef)
  427.                 {    
  428.                         watchDogPB.watchDogAbortFlag = true;                                // flag that we had the abort
  429.                 }
  430.                 USBGetPipeStatusByReference(pMousePB->pipeRef, &pipeState);                    // yes, so what it's state?
  431.                 if (pipeState != kUSBActive)                                                // if it's not active, try to clear it.  It might be stalled...
  432.                 {
  433.                     USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Pipe is open and stalled, clearing stall...", pMousePB->interfaceRef);
  434.                     USBClearPipeStallByReference(pMousePB->pipeRef);
  435.                 }
  436.             }
  437.             else if ((!pMousePB->retryCount) || (pMousePB->pb.usbStatus == kUSBAbortedError))    // have we exhausted the retries?
  438.             {                                                                                // or received an abort?
  439.                 USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Pipe abort or unable to recover from error", pMousePB->interfaceRef);
  440.                 pMousePB->pb.usbRefcon = kReturnFromDriver + kCompletionInProgess;            // if so, just exit.
  441.                 pMousePB->intPipeAborted = true;    
  442.             }
  443.             else                                                                            // if it didn't abort and there's retries left, then...
  444.             {
  445.                 if (pMousePB->pipeRef)                                                        // check if the pipe is open.
  446.                 {
  447.                     USBGetPipeStatusByReference(pMousePB->pipeRef, &pipeState);                // yes, so what it's state?
  448.                     if (pipeState != kUSBActive)                                            // if it's not active, try to clear it.  It might be stalled...
  449.                     {
  450.                         USBExpertStatus(pMousePB->interfaceRef, kMouseModuleName": Pipe is open and stalled, clearing stall...", pMousePB->interfaceRef);
  451.                         USBClearPipeStallByReference(pMousePB->pipeRef);
  452.                     }
  453.                 }
  454.                 if( (pMousePB->pb.usbStatus == kUSBNotRespondingErr)  ) 
  455.                 {
  456.                     USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": doing port status", pMousePB->interfaceRef);
  457.                     pMousePB->previousState = pMousePB->pb.usbRefcon;
  458.                     pMousePB->pb.usbRefcon = kGetPortStatus;
  459.                 }
  460.             }
  461.         }
  462.     }
  463.     else
  464.     {
  465.         pMousePB->pb.usbRefcon &= ~kRetryTransaction;
  466.         pMousePB->retryCount = kMouseRetryCount;
  467.     }
  468.  
  469.     if (pMousePB->pb.usbRefcon & kCompletionPending)             
  470.     {                                                
  471.         pMousePB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
  472.         switch(pMousePB->pb.usbRefcon & kStageMask)
  473.         {
  474.             case kConfigureInterface:
  475.                 pMousePB->pb.usbRefcon = kSetProtocol + kCompletionInProgess;
  476.                 break;
  477.                 
  478.             case kSetProtocol:
  479.                 if (kVendorID_AppleComputer == USBToHostWord(pMousePB->deviceDescriptor.vendor) )
  480.                 {
  481.                     pMousePB->pb.usbRefcon = 
  482. #if EnableRemoteWakeup
  483.                     kSetRemoteWakeup
  484. #else
  485.                     kFindPipe
  486. #endif
  487.                     + kCompletionInProgess;
  488.                 }
  489.                 else
  490.                 {
  491.                     pMousePB->pb.usbRefcon = kSetIdleRequest + kCompletionInProgess;
  492.                 }
  493.                 break;
  494.                 
  495.             case kSetIdleRequest:
  496.                 pMousePB->pb.usbRefcon = 
  497. #if EnableRemoteWakeup
  498.             kSetRemoteWakeup
  499. #else 
  500.             kFindPipe
  501. #endif
  502.                 + kCompletionInProgess;
  503.                 break;
  504.                 
  505. #if EnableRemoteWakeup
  506.             case kSetRemoteWakeup:
  507.                 pMousePB->pb.usbRefcon = kFindPipe;
  508.                 break;
  509. #endif
  510.                 
  511.             case kFindPipe:
  512.                 pMousePB->maxPacketSize = pMousePB->pb.usb.cntl.WValue;
  513.                 pMousePB->pipeRef = pMousePB->pb.usbReference;
  514.                 pMousePB->pb.usbRefcon = kReadInterruptPipe + kCompletionInProgess;
  515.  
  516.                 USBExpertStatus( watchDogPB.interfaceRef, kMouseModuleName": Initialize watchdog", 0);
  517.                 InitParamBlock( watchDogPB.interfaceRef, &watchDogPB.pb );
  518.                 
  519.                 watchDogPB.pipeRef = pMousePB->pipeRef;
  520.                 watchDogPB.watchDogState = kDelay10Seconds;
  521.                 
  522.                 watchDogPB.pb.usbBuffer = 0;
  523.                 watchDogPB.pb.usbActCount = 0;
  524.                 watchDogPB.pb.usbReqCount = 20000;            // check for mouse activity every twenty seconds
  525.                 watchDogPB.watchDogActivityFlag = false;
  526.                 
  527.                 watchDogPB.pb.usbRefcon =  0;
  528.                 watchDogPB.pb.usbCompletion = (USBCompletion)WatchDogCompletionProc;
  529.                 
  530.                 
  531. #if EnableWatchDog
  532.                 myErr = USBDelay(&watchDogPB.pb);
  533.                 if(immediateError(myErr))
  534.                 {
  535.                     USBExpertFatalError(pb->usbReference, myErr, kMouseModuleName": Setting up watchdog - USBDelay immediate error", 0);
  536.                 }
  537. #endif
  538.  
  539.                 break;
  540.                 
  541.             case kReadInterruptPipe:
  542.                 watchDogPB.watchDogActivityFlag = true;
  543.                 if (myMousePB.pNotificationRoutine)
  544.                 {
  545.                     (*myMousePB.pNotificationRoutine)(myMousePB.notificationRefcon, pMousePB->pb.usbActCount, (void *)pMousePB->hidReport, myMousePB.interfaceRef);
  546.                 }
  547.                 pMousePB->pb.usbRefcon = kReadInterruptPipe + kCompletionInProgess;
  548.                 break;
  549.  
  550.             case kPortStatusDelay:
  551.                     USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": kPortStatusDelay", pMousePB->interfaceRef);
  552.                     pMousePB->pb.usbRefcon = kGetPortStatus;
  553.                 break;
  554.  
  555.             case kResetMouseDelay:
  556.                     USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": kPortStatusDelay", pMousePB->interfaceRef);
  557.                     pMousePB->pb.usbRefcon = kResetMouse;
  558.                 break;
  559.  
  560.             case kResetMouse:
  561.                     USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": mouse now reset", pMousePB->interfaceRef);
  562.                     // Just give up here, the composite driver should now take care of things.
  563.                 break;
  564.  
  565.             case kGetPortStatus:
  566.                 if(pb->usbStatus == kUSBDeviceDisconnected)
  567.                 {
  568.                     USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": port status gives device disconnected, exiting", pMousePB->interfaceRef);
  569.                     pMousePB->pb.usbRefcon = kReturnFromDriver + kCompletionInProgess;            // if so, just exit.
  570.                 }
  571.                 else if(pb->usbStatus == kUSBPortDisabled)
  572.                 {
  573.                     USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": port status gives port disabled, resetting", pMousePB->interfaceRef);
  574.                     pMousePB->pb.usbRefcon = kResetMouse;
  575.                 }
  576.                 else if(pb->usbStatus == noErr)
  577.                 {
  578.                     USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": port status transient error, restarting", pMousePB->interfaceRef);
  579.                     //pMousePB->retryCount = kMouseRetryCount;    --> done automatically
  580.  
  581.                     pMousePB->pb.usbRefcon = pMousePB->previousState;
  582.                 }
  583.                 else
  584.                 {
  585.                     USBExpertStatusLevel(1, pMousePB->interfaceRef, kMouseModuleName": port status unknown error", pb->usbStatus);
  586.                 }
  587.             
  588.                 break;
  589.  
  590.             default:
  591.                 USBExpertFatalError(pMousePB->interfaceRef, kUSBInternalErr, kMouseModuleName": Transaction completed with bad refcon value", pMousePB->pb.usbRefcon );
  592.                 pMousePB->pb.usbRefcon = kUndefined + kReturnFromDriver + kCompletionInProgess;
  593.                 break;
  594.         }
  595.     }
  596.     
  597.     pMousePB->pb.usbRefcon &= ~(kCompletionInProgess);
  598.     if (!(pMousePB->pb.usbRefcon & kReturnFromDriver) && (!pMousePB->driverRemovalPending))
  599.         MouseInitiateTransaction(pb);
  600. }
  601.  
  602.  
  603. void InterfaceEntry(UInt32 interfacenum, USBInterfaceDescriptorPtr pInterfaceDescriptor, USBDeviceDescriptorPtr pDeviceDescriptor, USBReference theInterfaceRef)
  604. {
  605. #pragma unused (interfacenum)
  606.  
  607. static Boolean beenThereDoneThat = false;
  608.  
  609.     if(beenThereDoneThat)
  610.     {
  611.         USBExpertFatalError(theInterfaceRef, kUSBInternalErr, kMouseModuleName" is not reentrant", 0);
  612.         return;
  613.     }
  614.     beenThereDoneThat = true;
  615.     
  616.     // DebugStr("\pIn Mouse Interface Entry routine");
  617.  
  618.     watchDogPB.watchDogState = 0;
  619.     watchDogPB.watchDogAbortFlag = false;
  620.     watchDogPB.watchDogActivityFlag = false;
  621.     watchDogPB.driverRemovalPending = false;
  622.     watchDogPB.interfaceRef = theInterfaceRef;        
  623.     watchDogPB.pipeRef = nil;        
  624.     watchDogPB.pb.pbLength = sizeof(usbMousePBStruct);
  625.  
  626.     myMousePB.driverRemovalPending = false;
  627.     myMousePB.intPipeAborted = false;    
  628.  
  629.     myMousePB.deviceDescriptor = *pDeviceDescriptor;                
  630.     myMousePB.interfaceDescriptor = *pInterfaceDescriptor;            
  631.     
  632.     myMousePB.transDepth = 0;                            
  633.     myMousePB.retryCount = kMouseRetryCount;
  634.       
  635.     myMousePB.pSHIMInterruptRoutine = nil;
  636.     myMousePB.pSavedInterruptRoutine = nil;
  637.     
  638.     myMousePB.notificationRefcon = 0;
  639.     myMousePB.pNotificationRoutine = NotifyRegisteredHIDUser;
  640.  
  641.     myMousePB.interfaceRef = theInterfaceRef;        
  642.     myMousePB.pipeRef = nil;        
  643.     
  644.     InitParamBlock(theInterfaceRef, &myMousePB.pb);
  645.     
  646.     myMousePB.pb.usbReference = theInterfaceRef;
  647.     myMousePB.pb.pbLength = sizeof(usbMousePBStruct);
  648.     myMousePB.pb.usbRefcon = kConfigureInterface;        
  649.     
  650.     if ((myMousePB.deviceDescriptor.vendor == USB_CONSTANT16(0x046e)) &&
  651.         (myMousePB.deviceDescriptor.product == USB_CONSTANT16(0x6782)))
  652.     {
  653.         myMousePB.unitsPerInch = (Fixed)(100<<16);
  654.     }
  655.     else
  656.     {
  657.         myMousePB.unitsPerInch = (Fixed)(400<<16);
  658.     }
  659.     
  660.     myMousePB.pCursorDeviceInfo = 0;                
  661.     USBHIDControlDevice(kHIDEnableDemoMode,0);
  662.  
  663.     MouseInitiateTransaction(&myMousePB.pb);
  664. }
  665.  
  666.  
  667.  
  668.