home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 January: Mac OS SDK / Dev.CD Jan 99 SDK2.toast / Development Kits / USBDDK_v1.0.1_updated / Examples / USBTabletModule / USBTabletModule.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-09-29  |  11.3 KB  |  322 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        USBTabletModule.c
  3.  
  4.     Contains:    HID Module for USB Tablet
  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 "USBTabletModule.h"
  19.  
  20. usbTabletPBStruct myTabletPB;
  21.  
  22. void InitParamBlock(USBDeviceRef theDeviceRef, USBPB * paramblock)
  23. {
  24.     paramblock->usbReference = theDeviceRef;
  25.     paramblock->pbVersion = kUSBCurrentPBVersion;
  26.     paramblock->usbStatus = noErr;
  27.     paramblock->usbBuffer = nil;        
  28.     paramblock->usbActCount = 0;
  29.     paramblock->usbReqCount = 0;
  30.     paramblock->usbFlags = 0;
  31.     paramblock->usbOther = 0;
  32. }
  33.  
  34.  
  35.  
  36. Boolean immediateError(OSStatus err)
  37. {
  38.     return((err != kUSBPending) && (err != noErr) );
  39. }
  40.  
  41. void InitiateTransactionProc(USBPB *pb)
  42. {
  43. register usbTabletPBStruct *pTabletPB;
  44. OSStatus myErr;
  45.  
  46.     pTabletPB = (usbTabletPBStruct *)(pb);
  47.     pTabletPB->transDepth++;
  48.     if (pTabletPB->transDepth < 0)
  49.     {
  50.         USBExpertFatalError(pTabletPB->deviceRef, kUSBInternalErr, "\pTablet Driver: transDepth < 0 (initiation)", pTabletPB->pb.usbRefcon );
  51.     }
  52.     
  53.     if (pTabletPB->transDepth > 1)
  54.     {
  55.         USBExpertFatalError(pTabletPB->deviceRef, kUSBInternalErr, "\pTablet Driver: transDepth > 1 (initiation)", pTabletPB->pb.usbRefcon );
  56.     }
  57.     
  58.     switch(pTabletPB->pb.usbRefcon & ~kRetryTransaction)
  59.     {
  60.         case kFindInterface:
  61.             InitParamBlock(pTabletPB->deviceRef, &pTabletPB->pb);
  62.             pTabletPB->pb.usbWIndex = 0;
  63.             pTabletPB->pb.usbWValue = 0;
  64.             pTabletPB->pb.usbClassType = kUSBHIDInterfaceClass;
  65.             pTabletPB->pb.usbSubclass = kUSBBootInterfaceSubClass;
  66.             pTabletPB->pb.usbProtocol = kUSBMouseInterfaceProtocol;
  67.             pTabletPB->pb.usbRefcon |= kCompletionPending;
  68.             pTabletPB->pb.usbCompletion = (USBCompletion)TransactionCompletionProc;
  69.             myErr = USBFindNextInterface(pb);
  70.             if(immediateError(myErr))
  71.             {
  72.                 USBExpertFatalError(pTabletPB->pb.usbReference, kUSBInternalErr, "\pTablet Driver: USBFindNextInterface (immediate error)", myErr);
  73.                 pTabletPB->pb.usbRefcon = kReturnFromDriver;
  74.             }
  75.             break;
  76.             
  77.         case kOpenDevice:
  78.             InitParamBlock(pTabletPB->deviceRef, &pTabletPB->pb);
  79.             pTabletPB->pb.usbWValue = pTabletPB->configurationNumber;
  80.             pTabletPB->pb.usbRefcon |= kCompletionPending;
  81.             
  82.             pTabletPB->pb.usbCompletion = (USBCompletion)TransactionCompletionProc;
  83.             myErr = USBOpenDevice(pb);
  84.             if(immediateError(myErr))
  85.             {
  86.                 USBExpertFatalError(pTabletPB->pb.usbReference, kUSBInternalErr, "\pTablet Driver: USBOpenDevice (immediate error)", myErr);
  87.                 pTabletPB->pb.usbRefcon = kReturnFromDriver;
  88.             }
  89.             break;
  90.             
  91.         case kNewInterfaceRef:
  92.             InitParamBlock(pTabletPB->deviceRef, &pTabletPB->pb);
  93.             pTabletPB->pb.usbWIndex = pTabletPB->interfaceNumber;
  94.             pTabletPB->pb.usbRefcon |= kCompletionPending;
  95.             
  96.             pTabletPB->pb.usbCompletion = (USBCompletion)TransactionCompletionProc;
  97.             myErr = USBNewInterfaceRef(pb);
  98.             if(immediateError(myErr))
  99.             {
  100.                 USBExpertFatalError(pTabletPB->pb.usbReference, kUSBInternalErr, "\pTablet Driver: USBNewInterfaceRef (immediate error)", myErr);
  101.                 pTabletPB->pb.usbRefcon = kReturnFromDriver;
  102.             }
  103.             break;
  104.             
  105.         case kConfigureInterface:
  106.             InitParamBlock(pTabletPB->interfaceRef, &pTabletPB->pb);
  107.             pTabletPB->pb.usbRefcon |= kCompletionPending;
  108.             
  109.             pTabletPB->pb.usbCompletion = (USBCompletion)TransactionCompletionProc;
  110.             myErr = USBConfigureInterface(pb);
  111.             if(immediateError(myErr))
  112.             {
  113.                 USBExpertFatalError(pTabletPB->pb.usbReference, kUSBInternalErr, "\pTablet Driver: USBConfigureInterface (immediate error)", myErr);
  114.                 pTabletPB->pb.usbRefcon = kReturnFromDriver;
  115.             }
  116.             break;
  117.             
  118.         case kSetProtocol:
  119.             InitParamBlock(pTabletPB->interfaceRef, &pTabletPB->pb);
  120.             
  121.             pTabletPB->pb.usbBMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBInterface);            
  122.             pTabletPB->pb.usbBRequest = kHIDRqSetProtocol;
  123.             pTabletPB->pb.usbWValue = kHIDReportProtocolValue; 
  124.             pTabletPB->pb.usbWIndex = pTabletPB->interfaceNumber;
  125.             pTabletPB->pb.usbRefcon |= kCompletionPending;
  126.             
  127.             pTabletPB->pb.usbCompletion = (USBCompletion)TransactionCompletionProc;
  128.             myErr = USBDeviceRequest(&pTabletPB->pb);
  129.             if (immediateError(myErr))
  130.             {
  131.                 USBExpertFatalError(pTabletPB->deviceRef, kUSBInternalErr, "\pTablet Driver: kHIDRqSetProtocol (immediate error)", myErr);
  132.                 pTabletPB->pb.usbRefcon = kReturnFromDriver;
  133.             }
  134.             break;
  135.             
  136.         case kGetReportDescriptor:
  137.             InitParamBlock(pTabletPB->deviceRef, &pTabletPB->pb);
  138.             pTabletPB->pb.usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBInterface);
  139.             pTabletPB->pb.usbBRequest = kUSBRqGetDescriptor;
  140.             pTabletPB->pb.usbWValue = (0x22 << 8) + 1;             // get the first report descriptor
  141.             pTabletPB->pb.usbWIndex = pTabletPB->interfaceNumber;
  142.             pTabletPB->pb.usbReqCount = 0x66;
  143.             pTabletPB->pb.usbBuffer = pTabletPB->hidReportDescriptor;
  144.             
  145.             pTabletPB->pb.usbRefcon |= kCompletionPending;
  146.             pTabletPB->pb.usbCompletion = (USBCompletion)TransactionCompletionProc;
  147.             myErr = USBDeviceRequest(pb);
  148.             if(immediateError(myErr))
  149.             {
  150.                 USBExpertFatalError(pTabletPB->pb.usbReference, kUSBInternalErr, "\pTablet Driver: kGetReportDescriptor - immediate error", myErr);
  151.             }
  152.             break;
  153.         
  154.         case kFindInterruptPipe:
  155.             InitParamBlock(pTabletPB->interfaceRef, &pTabletPB->pb);
  156.             pTabletPB->pb.usbFlags = kUSBIn;
  157.             pTabletPB->pb.usbClassType = kUSBInterrupt; 
  158.             
  159.             pTabletPB->pb.usbRefcon |= kCompletionPending;
  160.             pTabletPB->pb.usbCompletion = (USBCompletion)TransactionCompletionProc;
  161.             myErr = USBFindNextPipe(&pTabletPB->pb);
  162.             if (immediateError(myErr))
  163.             {
  164.                 USBExpertFatalError(pTabletPB->deviceRef, kUSBInternalErr, "\pTablet Driver: kFindInterruptPipe (immediate error)", myErr);
  165.                 pTabletPB->pb.usbRefcon = kReturnFromDriver;
  166.             }
  167.             break;
  168.             
  169.         case kReadInterruptPipe:
  170.             InitParamBlock(pTabletPB->pipeRef, &pTabletPB->pb);
  171.  
  172.             pTabletPB->pb.usbBuffer = (Ptr)pTabletPB->hidReport;
  173.             pTabletPB->pb.usbReqCount = 7;
  174.             pTabletPB->pb.usbWIndex = pTabletPB->interfaceNumber;    
  175.             
  176.             pTabletPB->pb.usbRefcon |= kCompletionPending;
  177.             pTabletPB->pb.usbCompletion = (USBCompletion)TransactionCompletionProc;
  178.             myErr = USBIntRead(&pTabletPB->pb);
  179.             if(immediateError(myErr))
  180.             {
  181.                 USBExpertFatalError(pTabletPB->deviceRef, kUSBInternalErr, "\pTablet Driver: kReadInterruptPipe (ImmediateError)", myErr);
  182.             }
  183.             break;
  184.             
  185.         default:
  186.             USBExpertFatalError(pTabletPB->deviceRef, kUSBInternalErr, "\pTablet Driver: Transaction initiated with bad refcon value", pTabletPB->pb.usbRefcon);
  187.             pTabletPB->pb.usbRefcon = kUndefined + kReturnFromDriver;
  188.             break;
  189.     }
  190.     
  191. // At this point the control is returned to the system.  If a USB transaction
  192. // has been initiated, then it will call the Complete procs
  193. // (below) to handle the results of the transaction.
  194. }
  195.  
  196.  
  197. void TransactionCompletionProc(USBPB *pb)
  198. {
  199. register usbTabletPBStruct *pTabletPB;
  200. unsigned char    * errstring;
  201. USBPipeState     pipeState;
  202.  
  203.     pTabletPB = (usbTabletPBStruct *)(pb);
  204.     pTabletPB->transDepth--;
  205.     if (pTabletPB->transDepth < 0)
  206.     {
  207.         USBExpertFatalError(pTabletPB->deviceRef, kUSBInternalErr, "\pTablet Driver: transDepth < 0 (completion)", pTabletPB->pb.usbRefcon );
  208.     }
  209.     
  210.     if (pTabletPB->transDepth > 1)
  211.     {
  212.         USBExpertFatalError(pTabletPB->deviceRef, kUSBInternalErr, "\pTablet Driver: transDepth > 1 (completion)", pTabletPB->pb.usbRefcon );
  213.     }
  214.     
  215.     if(pTabletPB->pb.usbStatus != noErr)                                                        // was there an error?
  216.     {
  217.         switch(pTabletPB->pb.usbRefcon & 0x0fff)                                                // yes, so show where the error occurred
  218.         {
  219.             case kFindInterface:                  errstring = "\pTablet Driver: Error during kFindInterface"; break;
  220.             case kOpenDevice:                    errstring = "\pTablet Driver: Error during kOpenDevice"; break;
  221.             case kNewInterfaceRef:                errstring = "\pTablet Driver: Error during kNewInterfaceRef"; break;
  222.             case kConfigureInterface:              errstring = "\pTablet Driver: Error during kConfigureInterface"; break;
  223.             case kSetProtocol:                      errstring = "\pTablet Driver: Error during kSetProtocol"; break;
  224.             case kGetReportDescriptor:              errstring = "\pTablet Driver: Error during kGetReportDescriptor"; break;
  225.             case kFindInterruptPipe:              errstring = "\pTablet Driver: Error during kFindInterruptPipe"; break;
  226.             case kReadInterruptPipe:              errstring = "\pTablet Driver: Error during kReadInterruptPipe"; break;
  227.             default:                              errstring = "\pTablet Driver: Error occurred, but state is unknown"; break;
  228.         };
  229.         USBExpertFatalError(pTabletPB->deviceRef, pTabletPB->pb.usbStatus, errstring, (pTabletPB->pb.usbRefcon & 0x0fff));
  230.         
  231.         pTabletPB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver);                // set up to retry the transaction
  232.         pTabletPB->pb.usbRefcon |= kRetryTransaction;
  233.         pTabletPB->retryCount--;
  234.         
  235.         if ((!pTabletPB->retryCount)    || (pTabletPB->pb.usbStatus == kUSBAbortedError))    // have we exhausted the retries?
  236.         {                                                                                // or received an abort?
  237.             USBExpertStatus(pTabletPB->deviceRef, "\pTablet Driver: Pipe abort or unable to recover from error", pTabletPB->deviceRef);
  238.             pTabletPB->pb.usbRefcon = kReturnFromDriver;                                    // if so, just exit.
  239.         }
  240.         else                                                                            // if it didn't abort and there's retries left, then...
  241.         {
  242.             if (pTabletPB->pipeRef)                                                        // check if the pipe is open.
  243.             {
  244.                 USBGetPipeStatusByReference(pTabletPB->pipeRef, &pipeState);                // yes, so what it's state?
  245.                 if (pipeState != kUSBActive)                                            // if it's not active, try to clear it.  It might be stalled...
  246.                 {
  247.                     USBExpertStatus(pTabletPB->deviceRef, "\pTablet Driver: Pipe is open and stalled, clearing stall...", pTabletPB->deviceRef);
  248.                     USBClearPipeStallByReference(pTabletPB->pipeRef);
  249.                 }
  250.             }
  251.         }
  252.     }
  253.     else
  254.     {
  255.         pTabletPB->pb.usbRefcon &= ~kRetryTransaction;
  256.         pTabletPB->retryCount = kTabletRetryCount;
  257.     }
  258.  
  259.     if (pTabletPB->pb.usbRefcon & kCompletionPending)             
  260.     {                                                
  261.         pTabletPB->pb.usbRefcon &= ~(kCompletionPending + kReturnFromDriver);
  262.         switch(pTabletPB->pb.usbRefcon)
  263.         {
  264.             case kFindInterface:
  265.                 if ((pTabletPB->pb.usbClassType == kUSBHIDInterfaceClass) && 
  266.                     (pTabletPB->pb.usbSubclass == kUSBBootInterfaceSubClass) &&
  267.                     (pTabletPB->pb.usbProtocol == kUSBMouseInterfaceProtocol))
  268.                 {
  269.                     pTabletPB->pb.usbRefcon = kOpenDevice;
  270.                     pTabletPB->interfaceNumber = pTabletPB->pb.usbWIndex;
  271.                     pTabletPB->configurationNumber = pTabletPB->pb.usbWValue;
  272.                 }
  273.                 else
  274.                 {
  275.                     pTabletPB->pb.usbRefcon = kReturnFromDriver;
  276.                 }
  277.                 break;
  278.                 
  279.             case kOpenDevice:
  280.                 pTabletPB->pb.usbRefcon = kNewInterfaceRef;
  281.                 break;
  282.                 
  283.             case kNewInterfaceRef:
  284.                 pTabletPB->interfaceRef = pTabletPB->pb.usbReference;
  285.                 pTabletPB->pb.usbRefcon = kConfigureInterface;
  286.                 break;
  287.             
  288.             case kConfigureInterface:
  289.                 pTabletPB->pb.usbRefcon = kGetReportDescriptor;
  290.                 break;
  291.             
  292.             case kGetReportDescriptor:
  293.                 pTabletPB->pb.usbRefcon = kFindInterruptPipe;
  294.                 break;
  295.                 
  296.             case kFindInterruptPipe:
  297.                 if ((pTabletPB->pb.usbClassType == kUSBInterrupt) && 
  298.                     (pTabletPB->pb.usbFlags == kUSBIn))
  299.                 {
  300.                     pTabletPB->hidReportSize = pTabletPB->pb.usbWValue;
  301.                     pTabletPB->pipeRef = pTabletPB->pb.usbReference;
  302.                     pTabletPB->pb.usbRefcon = kReadInterruptPipe;
  303.                 }
  304.                 else
  305.                 {
  306.                     pTabletPB->pb.usbRefcon = kReturnFromDriver;
  307.                 }
  308.                 break;
  309.                 
  310.             case kReadInterruptPipe:
  311.                 //DebugStr("\pTablet read completed");
  312.                 ProcessInterruptReport(pTabletPB->refcon, pTabletPB->hidReport);
  313.                 pTabletPB->pb.usbRefcon = kReadInterruptPipe;
  314.                 break;
  315.  
  316.         }
  317.     }
  318.     if (!(pTabletPB->pb.usbRefcon & kReturnFromDriver))
  319.         InitiateTransactionProc(pb);
  320. }
  321.  
  322.