home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 February: Tool Chest / Dev.CD Feb 99 TC.toast / What's New? / Development Kits / Mac OS USB v1.1f3 DDK / Examples / KeyboardModule / KeyboardModule.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-01-07  |  12.9 KB  |  361 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-1998 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, "\pUSBHIDKeyboardModule: transDepth < 0 (initiation)", pKeyboardPB->pb.usbRefcon );
  57.     }
  58.     
  59.     if (pKeyboardPB->transDepth > 1)
  60.     {
  61.         USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, "\pUSBHIDKeyboardModule: transDepth > 1 (initiation)", pKeyboardPB->pb.usbRefcon );
  62.     }
  63.     
  64.     switch(pKeyboardPB->pb.usbRefcon & ~kRetryTransaction)
  65.     {
  66.         case kSetKeyboardLEDs:
  67.             InitParamBlock(pKeyboardPB->interfaceRef, &pKeyboardPB->pb);
  68.             
  69.             pKeyboardPB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  70.             
  71.             pKeyboardPB->pb.usb.cntl.BRequest = kHIDRqSetReport;
  72.             pKeyboardPB->pb.usb.cntl.WValue = (kHIDRtOutputReport << 8); 
  73.             pKeyboardPB->pb.usb.cntl.WIndex = pKeyboardPB->interfaceDescriptor.interfaceNumber;
  74.             
  75.             pKeyboardPB->pb.usbBuffer = (Ptr)&pKeyboardPB->hidReport[0];
  76.             pKeyboardPB->pb.usbReqCount = 1;
  77.                 
  78.             pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc;
  79.             pKeyboardPB->pb.usbRefcon |= kCompletionPending;
  80.             
  81.             myErr = USBDeviceRequest(&pKeyboardPB->pb);
  82.             if(immediateError(myErr))
  83.             {
  84.                 USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, "\pUSBHIDKeyboardModule: kSetKeyboardLEDs - immediate error", myErr);
  85.             }
  86.             break;
  87.  
  88.         case kConfigureInterface:
  89.             InitParamBlock(pKeyboardPB->interfaceRef, &pKeyboardPB->pb);
  90.             
  91.             pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc;
  92.             pKeyboardPB->pb.usbRefcon |= kCompletionPending;
  93.             
  94.             myErr = USBConfigureInterface( &pKeyboardPB->pb );
  95.             if(immediateError(myErr))
  96.             {
  97.                 USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, "\pUSBHIDKeyboardModule: kConfigureInterface - immediate error", myErr);
  98.                 pKeyboardPB->pb.usbRefcon = kReturnFromDriver;
  99.             }
  100.             break;
  101.         
  102.         case kSetProtocol:
  103.             InitParamBlock(pKeyboardPB->interfaceRef, &pKeyboardPB->pb);
  104.             
  105.             pKeyboardPB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  106.             pKeyboardPB->pb.usb.cntl.BRequest = kHIDRqSetProtocol;
  107.             pKeyboardPB->pb.usb.cntl.WValue = kHIDBootProtocolValue; 
  108.             pKeyboardPB->pb.usb.cntl.WIndex = pKeyboardPB->interfaceDescriptor.interfaceNumber;
  109.             
  110.             pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc;
  111.             pKeyboardPB->pb.usbRefcon |= kCompletionPending;
  112.         
  113.             myErr = USBDeviceRequest(&pKeyboardPB->pb);
  114.             if (immediateError(myErr))
  115.             {
  116.                 USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, "\pUSBHIDKeyboardModule: kSetProtocol - immediate error", myErr);
  117.             }
  118.             break;
  119.             
  120.         case kSetIdleRequest:
  121.             InitParamBlock(pKeyboardPB->interfaceRef, &pKeyboardPB->pb);
  122.             
  123.             pKeyboardPB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  124.             
  125.             pKeyboardPB->pb.usb.cntl.BRequest = kHIDRqSetIdle;
  126.             pKeyboardPB->pb.usb.cntl.WValue = ((24/4)<<8);                 // force a read completion if idle for more than 24ms
  127.             pKeyboardPB->pb.usb.cntl.WIndex = pKeyboardPB->interfaceDescriptor.interfaceNumber;
  128.             
  129.             pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc;
  130.             pKeyboardPB->pb.usbRefcon |= kCompletionPending;
  131.  
  132.             myErr = USBDeviceRequest(&pKeyboardPB->pb);
  133.             if(immediateError(myErr))
  134.             {
  135.                 USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, "\pUSBHIDKeyboardModule: kSetIdleRequest - immediate error", myErr);
  136.             }
  137.             break;
  138.  
  139.         case kFindPipe:
  140.             InitParamBlock(pKeyboardPB->interfaceRef, &pKeyboardPB->pb);
  141.             
  142.             pKeyboardPB->pb.usbFlags = kUSBIn;
  143.             pKeyboardPB->pb.usbClassType = kUSBInterrupt;
  144.             
  145.             pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc;
  146.             pKeyboardPB->pb.usbRefcon |= kCompletionPending;
  147.         
  148.             myErr = USBFindNextPipe( &pKeyboardPB->pb );
  149.             if((immediateError(myErr)) || (pKeyboardPB->pb.usbBuffer == nil))
  150.             {
  151.                 USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, "\pUSBHIDKeyboardModule: kFindPipe - immediate error", myErr);
  152.                 pKeyboardPB->pb.usbRefcon = kReturnFromDriver;
  153.             }
  154.             break;
  155.         
  156.         case kReadInterruptPipe:
  157.             InitParamBlock(pKeyboardPB->pipeRef, &pKeyboardPB->pb);
  158.  
  159.             pKeyboardPB->pb.usbBuffer = (Ptr)pKeyboardPB->hidReport;
  160.             pKeyboardPB->pb.usbReqCount = 0x08;
  161.             pKeyboardPB->pb.usb.cntl.WIndex = pKeyboardPB->interfaceDescriptor.interfaceNumber;    
  162.             
  163.             pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc;
  164.             pKeyboardPB->pb.usbRefcon |= kCompletionPending;
  165.         
  166.             myErr = USBIntRead(&pKeyboardPB->pb);
  167.             if(immediateError(myErr))
  168.             {
  169.                 USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, "\pUSBHIDKeyboardModule: kReadInterruptPipe - immediate error", myErr);
  170.             }
  171.             break;
  172.             
  173.         case kClearFeature:
  174.             USBExpertStatus(pKeyboardPB->interfaceRef, "\pUSBHIDKeyboardModule: Do a clear feature on the interrupt endpoint", pKeyboardPB->pipeRef);
  175.             InitParamBlock(pKeyboardPB->pipeRef, &pKeyboardPB->pb);
  176.             pKeyboardPB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBEndpoint);
  177.             
  178.             pKeyboardPB->pb.usb.cntl.BRequest = kUSBRqClearFeature;
  179.             pKeyboardPB->pb.usb.cntl.WValue = kUSBFeatureEndpointStall;
  180.             
  181.             pKeyboardPB->pb.usbFlags = kUSBAddressRequest;                /* kUSBAddressRequest asks the USL to do a translation of piperef to endpoint number */
  182.  
  183.             pKeyboardPB->pb.usbCompletion = (USBCompletion)KeyboardCompletionProc;
  184.             pKeyboardPB->pb.usbRefcon |= kCompletionPending;
  185.  
  186.             myErr = USBDeviceRequest(pb);
  187.             if(immediateError(myErr))
  188.             {
  189.                 USBExpertFatalError(pKeyboardPB->pb.usbReference, kUSBInternalErr, "\pUSBHIDKeyboardModule: kClearFeature - immediate error", myErr);
  190.             }
  191.             break;
  192.                 
  193.         default:
  194.             USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, "\pUSBHIDKeyboardModule - Transaction completed with bad refcon value", pKeyboardPB->pb.usbRefcon );
  195.             pKeyboardPB->pb.usbRefcon = kUndefined + kReturnFromDriver;
  196.             break;
  197.     }
  198.     
  199. // At this point the control is returned to the system.  If a USB transaction
  200. // has been initiated, then it will call the Complete procs
  201. // (below) to handle the results of the transaction.
  202. }
  203.  
  204. void KeyboardCompletionProc(USBPB *pb)
  205. {
  206. unsigned char    * errstring;
  207. register usbKeyboardPBStruct *pKeyboardPB;
  208. USBPipeState pipeState;
  209.  
  210.     pKeyboardPB = (usbKeyboardPBStruct *)(pb);
  211.     pKeyboardPB->transDepth--;
  212.     if (pKeyboardPB->transDepth < 0)
  213.     {
  214.         USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, "\pUSBHIDKeyboardModule: transDepth < 0 (completion)", pKeyboardPB->pb.usbRefcon );
  215.     }
  216.     
  217.     if (pKeyboardPB->transDepth > 1)
  218.     {
  219.         USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, "\pUSBHIDKeyboardModule: transDepth > 1 (completion)", pKeyboardPB->pb.usbRefcon );
  220.     }
  221.     
  222.     if(pKeyboardPB->pb.usbStatus != noErr)                                                    // was there an error?
  223.     {
  224.         switch(pKeyboardPB->pb.usbRefcon & 0x0fff)                                            // yes, so show where the error occurred
  225.         {
  226.             case kSetKeyboardLEDs:              errstring = "\pUSBHIDKeyboardModule: Error during kSetKeyboardLEDs"; break;
  227.             case kSetProtocol:                    errstring = "\pUSBHIDKeyboardModule: Error during kSetProtocol"; break;
  228.             case kSetIdleRequest:                  errstring = "\pUSBHIDKeyboardModule: Error during kSetIdleRequest"; break;
  229.             case kConfigureInterface:            errstring = "\pUSBHIDKeyboardModule: Error during kConfigureInterface"; break;
  230.             case kFindPipe:                      errstring = "\pUSBHIDKeyboardModule: Error during kFindPipe"; break;
  231.             case kReadInterruptPipe:              errstring = "\pUSBHIDKeyboardModule: Error during kReadInterruptPipe"; break;
  232.             case kClearFeature:                  errstring = "\pUSBHIDKeyboardModule: Error during kClearFeature"; break;
  233.             default:                              errstring = "\pUSBHIDKeyboardModule: Error occurred, but state is unknown"; break;
  234.         };
  235.         USBExpertFatalError(pKeyboardPB->interfaceRef, pKeyboardPB->pb.usbStatus, errstring, (pKeyboardPB->pb.usbRefcon & 0x0fff));
  236.         
  237.         pKeyboardPB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver);                // set up to retry the transaction
  238.         pKeyboardPB->pb.usbRefcon |= kRetryTransaction;
  239.         pKeyboardPB->retryCount--;
  240.         
  241.         if ((!pKeyboardPB->retryCount)    || (pKeyboardPB->pb.usbStatus == kUSBAbortedError))    // have we exhausted the retries?
  242.         {                                                                                    // or received an abort?
  243.             USBExpertStatus(pKeyboardPB->interfaceRef, "\pUSBHIDKeyboardModule: Pipe abort or unable to recover from error", pKeyboardPB->interfaceRef);
  244.             pKeyboardPB->pb.usbRefcon = kReturnFromDriver;                                    // if so, just exit.
  245.         }
  246.         else                                                                                // if it didn't abort and there's retries left, then...
  247.         {
  248.             if (pKeyboardPB->pipeRef)                                                        // check if the pipe is open.
  249.             {
  250.                 USBGetPipeStatusByReference(pKeyboardPB->pipeRef, &pipeState);                // yes, so what it's state?
  251.                 if (pipeState != kUSBActive)                                                // if it's not active, try to clear it.  It might be stalled...
  252.                 {
  253.                     USBExpertStatus(pKeyboardPB->interfaceRef, "\pUSBHIDKeyboardModule: Pipe is open and stalled, clearing stall...", pKeyboardPB->interfaceRef);
  254.                     USBClearPipeStallByReference(pKeyboardPB->pipeRef);
  255.                 }
  256.             }
  257.         }
  258.     }
  259.     else
  260.     {
  261.         pKeyboardPB->pb.usbRefcon &= ~kRetryTransaction;
  262.         pKeyboardPB->retryCount = kKeyboardRetryCount;
  263.     }
  264.  
  265.     if (pKeyboardPB->pb.usbRefcon & kCompletionPending)             
  266.     {                                                
  267.         pKeyboardPB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
  268.         switch(pKeyboardPB->pb.usbRefcon)
  269.         {
  270.             case kSetKeyboardLEDs:
  271.                 pKeyboardPB->pb.usbRefcon = kReturnFromDriver;
  272.                 break;
  273.                 
  274.             case kConfigureInterface:
  275.                 pKeyboardPB->pb.usbRefcon = kSetProtocol;
  276.                 break;
  277.                 
  278.             case kSetProtocol:
  279.                 pKeyboardPB->pb.usbRefcon = kSetIdleRequest;
  280.                 break;
  281.                 
  282.             case kSetIdleRequest:
  283.                 pKeyboardPB->pb.usbRefcon = kFindPipe;
  284.                 break;
  285.                 
  286.             case kFindPipe:
  287.                 pKeyboardPB->pipeRef = pKeyboardPB->pb.usbReference;
  288.                 pKeyboardPB->pb.usbRefcon = kReadInterruptPipe;
  289.                 break;
  290.                 
  291.             case kReadInterruptPipe:
  292.                 NotifyRegisteredHIDUser(pKeyboardPB->hidDeviceType, pKeyboardPB->hidReport);
  293.                 pKeyboardPB->pb.usbRefcon = kReadInterruptPipe;
  294.                 break;
  295.                 
  296.             case kClearFeature:
  297.                 pKeyboardPB->pb.usbRefcon = kReadInterruptPipe;
  298.                 break;
  299.                 
  300.             default:
  301.                 USBExpertFatalError(pKeyboardPB->interfaceRef, kUSBInternalErr, "\pUSBHIDKeyboardModule - Transaction completed with bad refcon value", pKeyboardPB->pb.usbRefcon );
  302.                 pKeyboardPB->pb.usbRefcon = kUndefined + kReturnFromDriver;
  303.                 break;
  304.         }
  305.     }
  306.     if (!(pKeyboardPB->pb.usbRefcon & kReturnFromDriver))
  307.         KeyboardInitiateTransaction(pb);
  308. }
  309.  
  310.  
  311. void InterfaceEntry(UInt32 interfacenum, USBInterfaceDescriptorPtr pInterfaceDescriptor, USBDeviceDescriptorPtr pDeviceDescriptor, USBReference theInterfaceRef)
  312. {
  313. #pragma unused (interfacenum)
  314.  
  315. static Boolean beenThereDoneThat = false;
  316.  
  317.     if(beenThereDoneThat)
  318.     {
  319.         USBExpertFatalError(theInterfaceRef, kUSBInternalErr, "\pUSBHIDKeyboardModule is not reentrant", 12);
  320.         return;
  321.     }
  322.     beenThereDoneThat = true;
  323.     
  324.     //DebugStr("\pIn Keyboard Module Interface entry routine");
  325.     shimKeyboardPB.deviceDescriptor = *pDeviceDescriptor;                
  326.     shimKeyboardPB.interfaceDescriptor = *pInterfaceDescriptor;                
  327.     shimKeyboardPB.transDepth = 0;                            
  328.     shimKeyboardPB.retryCount = kKeyboardRetryCount;
  329.     shimKeyboardPB.pSHIMInterruptRoutine = nil;
  330.     shimKeyboardPB.pSavedInterruptRoutine = nil;
  331.     shimKeyboardPB.interfaceRef = theInterfaceRef;
  332.     shimKeyboardPB.pipeRef = 0;
  333.     
  334.     InitParamBlock(theInterfaceRef, &shimKeyboardPB.pb);
  335.     shimKeyboardPB.pb.pbLength = sizeof(usbKeyboardPBStruct);
  336.     shimKeyboardPB.pb.usbRefcon = 0;                
  337.  
  338.     myKeyboardPB.deviceDescriptor = *pDeviceDescriptor;                
  339.     myKeyboardPB.interfaceDescriptor = *pInterfaceDescriptor;                
  340.     myKeyboardPB.transDepth = 0;                            
  341.     myKeyboardPB.retryCount = kKeyboardRetryCount;
  342.     myKeyboardPB.pSHIMInterruptRoutine = nil;
  343.     myKeyboardPB.pSavedInterruptRoutine = nil;
  344.     myKeyboardPB.interfaceRef = theInterfaceRef;
  345.     myKeyboardPB.pipeRef = 0;
  346.  
  347.     myKeyboardPB.sendRawReportFlag = false;
  348.     myKeyboardPB.hidEmulationInit = false;
  349.     
  350.     InitParamBlock(theInterfaceRef, &myKeyboardPB.pb);
  351.     myKeyboardPB.pb.pbLength = sizeof(usbKeyboardPBStruct);
  352.     myKeyboardPB.pb.usbRefcon = kConfigureInterface;                    
  353.     
  354.     
  355.     USBHIDControlDevice(kHIDEnableDemoMode,0);
  356.     KeyboardInitiateTransaction(&myKeyboardPB.pb);
  357. }
  358.  
  359.  
  360.  
  361.