home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 June: Reference Library / Dev.CD Jun 99 RL Disk 1.toast / What's New / Development Kits / Mac_OS_USB_DDK_v1.2 / Examples / KeyboardModule / KeyboardModule.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-04-15  |  13.7 KB  |  384 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        KeyboardModule.c
  3.  
  4.     Contains:    HID Module for USB Keyboard
  5.  
  6.     Version:    xxx put version here xxx
  7.  
  8.     Copyright:    © 1997-1999 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11.  
  12. #include <Types.h>
  13. #include <Devices.h>
  14. #include <processes.h>
  15. #include <DriverServices.h>
  16. #include <USB.h>
  17.  
  18. #include "KeyboardModule.h"
  19.  
  20. usbKeyboardPBStruct myKeyboardPB;
  21. usbKeyboardPBStruct shimKeyboardPB;
  22.  
  23.  
  24.  
  25. void InitParamBlock(USBReference theInterfaceRef, USBPB * paramblock)
  26. {
  27.     paramblock->usbReference = theInterfaceRef;
  28.     paramblock->pbVersion = kUSBCurrentPBVersion;
  29.     
  30.     paramblock->usb.cntl.WIndex = 0;             
  31.     paramblock->usb.cntl.WValue = 0;
  32.     
  33.     paramblock->usbBuffer = nil;        
  34.     paramblock->usbActCount = 0;
  35.     paramblock->usbReqCount = 0;
  36.     paramblock->usbFlags = 0;
  37.     paramblock->usbOther = 0;
  38.     
  39.     paramblock->usbStatus = noErr;
  40. }
  41.  
  42. static Boolean immediateError(OSStatus err)
  43. {
  44.     return((err != kUSBPending) && (err != noErr) );
  45. }
  46.  
  47. void KeyboardInitiateTransaction(USBPB *pb)
  48. {
  49. register usbKeyboardPBStruct *pKeyboardPB;
  50. OSStatus myErr;
  51.  
  52.     pKeyboardPB = (usbKeyboardPBStruct *)(pb);
  53.     pKeyboardPB->transDepth++;
  54.     if (pKeyboardPB->transDepth < 0)
  55.     {
  56.         USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": transDepth < 0 (initiation)", pKeyboardPB->pb.usbRefcon );
  57.     }
  58.     
  59.     if (pKeyboardPB->transDepth > 1)
  60.     {
  61.         USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": transDepth > 1 (initiation)", pKeyboardPB->pb.usbRefcon );
  62.     }
  63.     
  64.     if (pKeyboardPB->driverRemovalPending)
  65.     {
  66.         pKeyboardPB->pb.usbRefcon = kReturnFromDriver;
  67.         return;
  68.     }
  69.     
  70.     switch(pKeyboardPB->pb.usbRefcon & ~kRetryTransaction)
  71.     {
  72.         case kSetKeyboardLEDs:
  73.             InitParamBlock(pKeyboardPB->interfaceRef, &pKeyboardPB->pb);
  74.             
  75.             pKeyboardPB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  76.             
  77.             pKeyboardPB->pb.usb.cntl.BRequest = kHIDRqSetReport;
  78.             pKeyboardPB->pb.usb.cntl.WValue = (kHIDRtOutputReport << 8); 
  79.             pKeyboardPB->pb.usb.cntl.WIndex = pKeyboardPB->interfaceDescriptor.interfaceNumber;
  80.             
  81.             pKeyboardPB->pb.usbBuffer = (Ptr)&pKeyboardPB->hidReport[0];
  82.             pKeyboardPB->pb.usbReqCount = 1;
  83.                 
  84.             pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc;
  85.             pKeyboardPB->pb.usbRefcon |= kCompletionPending;
  86.             
  87.             myErr = USBDeviceRequest(&pKeyboardPB->pb);
  88.             if(immediateError(myErr))
  89.             {
  90.                 USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": kSetKeyboardLEDs - immediate error", myErr);
  91.             }
  92.             break;
  93.  
  94.         case kConfigureInterface:
  95.             InitParamBlock(pKeyboardPB->interfaceRef, &pKeyboardPB->pb);
  96.             
  97.             pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc;
  98.             pKeyboardPB->pb.usbRefcon |= kCompletionPending;
  99.             
  100.             myErr = USBConfigureInterface( &pKeyboardPB->pb );
  101.             if(immediateError(myErr))
  102.             {
  103.                 USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": kConfigureInterface - immediate error", myErr);
  104.                 pKeyboardPB->pb.usbRefcon = kReturnFromDriver;
  105.             }
  106.             break;
  107.         
  108.         case kSetProtocol:
  109.             InitParamBlock(pKeyboardPB->interfaceRef, &pKeyboardPB->pb);
  110.             
  111.             pKeyboardPB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  112.             pKeyboardPB->pb.usb.cntl.BRequest = kHIDRqSetProtocol;
  113.             pKeyboardPB->pb.usb.cntl.WValue = kHIDBootProtocolValue; 
  114.             pKeyboardPB->pb.usb.cntl.WIndex = pKeyboardPB->interfaceDescriptor.interfaceNumber;
  115.             
  116.             pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc;
  117.             pKeyboardPB->pb.usbRefcon |= kCompletionPending;
  118.         
  119.             myErr = USBDeviceRequest(&pKeyboardPB->pb);
  120.             if (immediateError(myErr))
  121.             {
  122.                 USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": kSetProtocol - immediate error", myErr);
  123.             }
  124.             break;
  125.             
  126.         case kSetIdleRequest:
  127.             USBExpertStatus(pKeyboardPB->interfaceRef, kKeyboardModuleName": Do a SetIdle on non-Apple keyboards, as some 3rd party keyboards don't send reports on key release", pKeyboardPB->pipeRef);
  128.             InitParamBlock(pKeyboardPB->interfaceRef, &pKeyboardPB->pb);
  129.             
  130.             pKeyboardPB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  131.             
  132.             pKeyboardPB->pb.usb.cntl.BRequest = kHIDRqSetIdle;
  133.             pKeyboardPB->pb.usb.cntl.WValue = ((24/4)<<8);                 // force a read completion if idle for more than 24ms
  134.             pKeyboardPB->pb.usb.cntl.WIndex = pKeyboardPB->interfaceDescriptor.interfaceNumber;
  135.             
  136.             pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc;
  137.             pKeyboardPB->pb.usbRefcon |= kCompletionPending;
  138.  
  139.             myErr = USBDeviceRequest(&pKeyboardPB->pb);
  140.             if(immediateError(myErr))
  141.             {
  142.                 USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": kSetIdleRequest - immediate error", myErr);
  143.             }
  144.             break;
  145.  
  146.         case kFindPipe:
  147.             InitParamBlock(pKeyboardPB->interfaceRef, &pKeyboardPB->pb);
  148.             
  149.             pKeyboardPB->pb.usbFlags = kUSBIn;
  150.             pKeyboardPB->pb.usbClassType = kUSBInterrupt;
  151.             
  152.             pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc;
  153.             pKeyboardPB->pb.usbRefcon |= kCompletionPending;
  154.         
  155.             myErr = USBFindNextPipe( &pKeyboardPB->pb );
  156.             if((immediateError(myErr)) || (pKeyboardPB->pb.usbBuffer == nil))
  157.             {
  158.                 USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": kFindPipe - immediate error", myErr);
  159.                 pKeyboardPB->pb.usbRefcon = kReturnFromDriver;
  160.             }
  161.             break;
  162.         
  163.         case kReadInterruptPipe:
  164.             InitParamBlock(pKeyboardPB->pipeRef, &pKeyboardPB->pb);
  165.  
  166.             pKeyboardPB->pb.usbBuffer = (Ptr)pKeyboardPB->hidReport;
  167.             pKeyboardPB->pb.usbReqCount = 0x08;
  168.             pKeyboardPB->pb.usb.cntl.WIndex = pKeyboardPB->interfaceDescriptor.interfaceNumber;    
  169.             
  170.             pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc;
  171.             pKeyboardPB->pb.usbRefcon |= kCompletionPending;
  172.         
  173.             myErr = USBIntRead(&pKeyboardPB->pb);
  174.             if(immediateError(myErr))
  175.             {
  176.                 USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": kReadInterruptPipe - immediate error", myErr);
  177.             }
  178.             break;
  179.             
  180.         case kClearFeature:
  181.             USBExpertStatus(pKeyboardPB->interfaceRef, kKeyboardModuleName": Do a clear feature on the interrupt endpoint", pKeyboardPB->pipeRef);
  182.             InitParamBlock(pKeyboardPB->pipeRef, &pKeyboardPB->pb);
  183.             pKeyboardPB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBEndpoint);
  184.             
  185.             pKeyboardPB->pb.usb.cntl.BRequest = kUSBRqClearFeature;
  186.             pKeyboardPB->pb.usb.cntl.WValue = kUSBFeatureEndpointStall;
  187.             
  188.             pKeyboardPB->pb.usbFlags = kUSBAddressRequest;                /* kUSBAddressRequest asks the USL to do a translation of piperef to endpoint number */
  189.  
  190.             pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc;
  191.             pKeyboardPB->pb.usbRefcon |= kCompletionPending;
  192.  
  193.             myErr = USBDeviceRequest(pb);
  194.             if(immediateError(myErr))
  195.             {
  196.                 USBExpertFatalError(pKeyboardPB->pb.usbReference, kUSBInternalErr, kKeyboardModuleName": kClearFeature - immediate error", myErr);
  197.             }
  198.             break;
  199.                 
  200.         default:
  201.             USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName" - Transaction completed with bad refcon value", pKeyboardPB->pb.usbRefcon );
  202.             pKeyboardPB->pb.usbRefcon = kUndefined + kReturnFromDriver;
  203.             break;
  204.     }
  205.     
  206. // At this point the control is returned to the system.  If a USB transaction
  207. // has been initiated, then it will call the Completion proc
  208. // (below) to handle the results of the transaction.
  209. }
  210.  
  211. void KeyboardCompletionProc(USBPB *pb)
  212. {
  213. unsigned char    * errstring;
  214. register usbKeyboardPBStruct *pKeyboardPB;
  215. USBPipeState pipeState;
  216.  
  217.     pKeyboardPB = (usbKeyboardPBStruct *)(pb);
  218.     pKeyboardPB->transDepth--;
  219.     if (pKeyboardPB->transDepth < 0)
  220.     {
  221.         USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": transDepth < 0 (completion)", pKeyboardPB->pb.usbRefcon );
  222.     }
  223.     
  224.     if (pKeyboardPB->transDepth > 1)
  225.     {
  226.         USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName": transDepth > 1 (completion)", pKeyboardPB->pb.usbRefcon );
  227.     }
  228.     
  229.     if(pKeyboardPB->pb.usbStatus != noErr)                                                    // was there an error?
  230.     {
  231.         switch(pKeyboardPB->pb.usbRefcon & 0x0fff)                                            // yes, so show where the error occurred
  232.         {
  233.             case kSetKeyboardLEDs:              errstring = kKeyboardModuleName": Error during kSetKeyboardLEDs"; break;
  234.             case kSetProtocol:                    errstring = kKeyboardModuleName": Error during kSetProtocol"; break;
  235.             case kSetIdleRequest:                  errstring = kKeyboardModuleName": Error during kSetIdleRequest"; break;
  236.             case kConfigureInterface:            errstring = kKeyboardModuleName": Error during kConfigureInterface"; break;
  237.             case kFindPipe:                      errstring = kKeyboardModuleName": Error during kFindPipe"; break;
  238.             case kReadInterruptPipe:              errstring = kKeyboardModuleName": Error during kReadInterruptPipe"; break;
  239.             case kClearFeature:                  errstring = kKeyboardModuleName": Error during kClearFeature"; break;
  240.             default:                              errstring = kKeyboardModuleName": Error occurred, but state is unknown"; break;
  241.         };
  242.         USBExpertFatalError(pKeyboardPB->interfaceRef, pKeyboardPB->pb.usbStatus, errstring, (pKeyboardPB->pb.usbRefcon & 0x0fff));
  243.         
  244.         pKeyboardPB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver);                // set up to retry the transaction
  245.         pKeyboardPB->pb.usbRefcon |= kRetryTransaction;
  246.         pKeyboardPB->retryCount--;
  247.         
  248.         if ((!pKeyboardPB->retryCount)    || (pKeyboardPB->pb.usbStatus == kUSBAbortedError))    // have we exhausted the retries?
  249.         {                                                                                    // or received an abort?
  250.             USBExpertStatus(pKeyboardPB->interfaceRef, kKeyboardModuleName": Pipe abort or unable to recover from error", pKeyboardPB->interfaceRef);
  251.             pKeyboardPB->pb.usbRefcon = kReturnFromDriver;                                    // if so, just exit.
  252.             pKeyboardPB->intPipeAborted = true;                                                
  253.         }
  254.         else                                                                                // if it didn't abort and there's retries left, then...
  255.         {
  256.             if (pKeyboardPB->pipeRef)                                                        // check if the pipe is open.
  257.             {
  258.                 USBGetPipeStatusByReference(pKeyboardPB->pipeRef, &pipeState);                // yes, so what it's state?
  259.                 if (pipeState != kUSBActive)                                                // if it's not active, try to clear it.  It might be stalled...
  260.                 {
  261.                     USBExpertStatus(pKeyboardPB->interfaceRef, kKeyboardModuleName": Pipe is open and stalled, clearing stall...", pKeyboardPB->interfaceRef);
  262.                     USBClearPipeStallByReference(pKeyboardPB->pipeRef);
  263.                 }
  264.             }
  265.         }
  266.     }
  267.     else
  268.     {
  269.         pKeyboardPB->pb.usbRefcon &= ~kRetryTransaction;
  270.         pKeyboardPB->retryCount = kKeyboardRetryCount;
  271.     }
  272.  
  273.     if (pKeyboardPB->pb.usbRefcon & kCompletionPending)             
  274.     {                                                
  275.         pKeyboardPB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
  276.         switch(pKeyboardPB->pb.usbRefcon)
  277.         {
  278.             case kSetKeyboardLEDs:
  279.                 pKeyboardPB->pb.usbRefcon = kReturnFromDriver;
  280.                 break;
  281.                 
  282.             case kConfigureInterface:
  283.                 pKeyboardPB->pb.usbRefcon = kSetProtocol;
  284.                 break;
  285.                 
  286.             case kSetProtocol:
  287.                 if (kVendorID_AppleComputer == USBToHostWord(pKeyboardPB->deviceDescriptor.vendor))
  288.                 {
  289.                     pKeyboardPB->pb.usbRefcon = kFindPipe;
  290.                 }
  291.                 else
  292.                 {
  293.                     pKeyboardPB->pb.usbRefcon = kSetIdleRequest;
  294.                 }
  295.                 break;
  296.                 
  297.             case kSetIdleRequest:
  298.                 pKeyboardPB->pb.usbRefcon = kFindPipe;
  299.                 break;
  300.                 
  301.             case kFindPipe:
  302.                 pKeyboardPB->pipeRef = pKeyboardPB->pb.usbReference;
  303.                 pKeyboardPB->pb.usbRefcon = kReadInterruptPipe;
  304.                 pKeyboardPB->keyboardReady = true;
  305.                 shimKeyboardPB.keyboardReady = true;
  306.                 break;
  307.                 
  308.             case kReadInterruptPipe:
  309.                 NotifyRegisteredHIDUser(pKeyboardPB->hidDeviceType, pKeyboardPB->hidReport);
  310.                 pKeyboardPB->pb.usbRefcon = kReadInterruptPipe;
  311.                 break;
  312.                 
  313.             case kClearFeature:
  314.                 pKeyboardPB->pb.usbRefcon = kReadInterruptPipe;
  315.                 break;
  316.                 
  317.             default:
  318.                 USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, kKeyboardModuleName" - Transaction completed with bad refcon value", pKeyboardPB->pb.usbRefcon );
  319.                 pKeyboardPB->pb.usbRefcon = kUndefined + kReturnFromDriver;
  320.                 break;
  321.         }
  322.     }
  323.     if (!(pKeyboardPB->pb.usbRefcon & kReturnFromDriver) && (!pKeyboardPB->driverRemovalPending))
  324.         KeyboardInitiateTransaction(pb);
  325. }
  326.  
  327.  
  328. void InterfaceEntry(UInt32 interfacenum, USBInterfaceDescriptorPtr pInterfaceDescriptor, USBDeviceDescriptorPtr pDeviceDescriptor, USBReference theInterfaceRef)
  329. {
  330. #pragma unused (interfacenum)
  331.  
  332. static Boolean beenThereDoneThat = false;
  333.  
  334.     if(beenThereDoneThat)
  335.     {
  336.         USBExpertFatalError(theInterfaceRef, kUSBInternalErr, kKeyboardModuleName" is not reentrant", 12);
  337.         return;
  338.     }
  339.     beenThereDoneThat = true;
  340.     
  341.     //DebugStr("\pIn Keyboard Module Interface entry routine");
  342.     shimKeyboardPB.driverRemovalPending = false;
  343.     shimKeyboardPB.deviceDescriptor = *pDeviceDescriptor;                
  344.     shimKeyboardPB.interfaceDescriptor = *pInterfaceDescriptor;                
  345.     shimKeyboardPB.transDepth = 0;                            
  346.     shimKeyboardPB.retryCount = kKeyboardRetryCount;
  347.     shimKeyboardPB.pSHIMInterruptRoutine = nil;
  348.     shimKeyboardPB.pSavedInterruptRoutine = nil;
  349.     shimKeyboardPB.interfaceRef = theInterfaceRef;
  350.     shimKeyboardPB.pipeRef = 0;
  351.     shimKeyboardPB.keyboardReady = false;
  352.     shimKeyboardPB.intPipeAborted = false;
  353.     
  354.     InitParamBlock(theInterfaceRef, &shimKeyboardPB.pb);
  355.     shimKeyboardPB.pb.pbLength = sizeof(usbKeyboardPBStruct);
  356.     shimKeyboardPB.pb.usbRefcon = 0;                
  357.  
  358.     myKeyboardPB.driverRemovalPending = false;
  359.     myKeyboardPB.deviceDescriptor = *pDeviceDescriptor;                
  360.     myKeyboardPB.interfaceDescriptor = *pInterfaceDescriptor;                
  361.     myKeyboardPB.transDepth = 0;                            
  362.     myKeyboardPB.retryCount = kKeyboardRetryCount;
  363.     myKeyboardPB.pSHIMInterruptRoutine = nil;
  364.     myKeyboardPB.pSavedInterruptRoutine = nil;
  365.     myKeyboardPB.interfaceRef = theInterfaceRef;
  366.     myKeyboardPB.pipeRef = 0;
  367.     myKeyboardPB.keyboardReady = false;
  368.     myKeyboardPB.intPipeAborted = false;
  369.  
  370.     myKeyboardPB.sendRawReportFlag = false;
  371.     myKeyboardPB.hidEmulationInit = false;
  372.     
  373.     InitParamBlock(theInterfaceRef, &myKeyboardPB.pb);
  374.     myKeyboardPB.pb.pbLength = sizeof(usbKeyboardPBStruct);
  375.     myKeyboardPB.pb.usbRefcon = kConfigureInterface;                    
  376.     
  377.     
  378.     USBHIDControlDevice(kHIDEnableDemoMode,0);
  379.     KeyboardInitiateTransaction(&myKeyboardPB.pb);
  380. }
  381.  
  382.  
  383.  
  384.