home *** CD-ROM | disk | FTP | other *** search
- /*
- file: SetLED.c
- Sample program to demonstrate the use of the ADBOp call, including use
- of the completion routine under 68K, CFM68K, and PPC.
-
- demonstrates a workaround for a bug with the CFM68K InterfaceLib glue
- code such that a call to ADBOp under CFM68K results in a bus error.
- This bug was identified with MacOS 8.1 running on different 68040 CPU's
-
- By: Rich Kubota 4/7/98
- Macintosh Developer Support
-
- */
-
- #include <Types.h>
- #include <Events.h>
- #include <OSUtils.h>
- #include <DeskBus.h>
- #include <MixedMode.h>
-
-
- // keyboard ADB constants
- #define kTalkCommand 8+4
- #define kListenCommand 8
- #define kLEDRegister 2
-
- #if TARGET_CPU_68K && !TARGET_RT_MAC_CFM
- pascal long GetA2( void ) ONEWORDINLINE(0x2E8A);
- #endif // TARGET_CPU_68K && !TARGET_RT_MAC_CFM
-
- static long gCompletionFlag;
- static ADBServiceRoutineUPP completionProc;
- static pascal void CompADBOp(void);
-
- pascal OSErr MyADBOp(Ptr refCon, ADBServiceRoutineUPP compRout,
- Ptr buffer, short commandNum);
-
- // example completion routine for use with ADBOp
- pascal void CompADBOp(void)
- {
- #if TARGET_CPU_PPC || TARGET_RT_MAC_CFM
- // Under, we can access global variables which is simpler
- // than trying to write the glue code required so that
- // the completion routine is called with the registers
- // set as per Inside Mac V-368
- // set flag to indicate completion routine has completed
- gCompletionFlag = 1;
- #else // TARGET_CPU_PPC || TARGET_RT_MAC_CFM
-
- // under 68K, but not CFM-68K, all of the arguments are passed
- // in registers so we use inline functions to access those
- // arguments. In this sample, the optional data
- // buffer argument is interest since we want to set a boolean flag to
- // indicate that the completion routine has been executed. A similar
- // macro as that for GetA2 can be written to access the command buffer
- // pointer in register A0
- long *completionFlagPtr;
-
- // set flag to indicate completion routine has run; A2 points to the flag
- completionFlagPtr = (long*)GetA2();
- *completionFlagPtr = 1;
- #endif // TARGET_CPU_PPC || TARGET_RT_MAC_CFM
- } /* end of CompADBOp */
-
- #if TARGET_CPU_68K && TARGET_RT_MAC_CFM
- // The following code is implemented to fix a bug that exists with the
- // 68K InterfaceLib glue code. In order for the glue code to work,
- // a pointer to an ADBOpBlock structure must be passed in register A0.
- // We define the global ADBOpBlock structure to support
- // the asynch ADBOp call
-
- ADBOpBlock gADBOpBlock;
- #endif // TARGET_CPU_68K && TARGET_RT_MAC_CFM
-
- // Instead of making the ADBOp directly, call MyADBOp which makes
- // the appropriate call depending on the target architecture.
- // For CFM68K, the ADBOpBlock structure is filled in and the
- // ADBGlue routine above is called. For regular 68K and PPC, the
- // ADBOp call is made straightaway.
-
- pascal OSErr MyADBOp(
- Ptr refCon,
- ADBServiceRoutineUPP compRout,
- Ptr buffer,
- short commandNum)
- {
- #if TARGET_CPU_68K && TARGET_RT_MAC_CFM
- ADBOpBlock adbOpBlock;
-
- adbOpBlock.dataBuffPtr = buffer;
- adbOpBlock.opServiceRtPtr = compRout;
- adbOpBlock.opDataAreaPtr = refCon;
-
- // Important Note: In this sample, we declare the adbOpBlock
- // structure as a stack variable. Normally it is bad practice
- // to use a stack parameter for any asynchronous call.
- // ADBOp makes a copy of the contents of the structure so the
- // structure does not need to exist for the life of the
- // asynchronous call.
-
- // Note that the refCon value is placed into the ADBOpBlock
- // structure for completeness.
- // This program sample assumes that a completion routine, under
- // CFM, will access the refCon and the data buffer as globals
- // to the process, since under CFM, this is possible.
- // Otherwise, more glue code is required so that when CFM calls
- // the completion routine, the 68K registers will be set as
- // per Inside Mac V-368.
-
- return (OSErr) CallUniversalProc((UniversalProcPtr)NGetTrapAddress(0xA07C, 0),
- kRegisterBased |
- RESULT_SIZE(SIZE_CODE(sizeof(OSErr))) |
- REGISTER_RESULT_LOCATION(kRegisterD0) |
- REGISTER_ROUTINE_PARAMETER(1,
- kRegisterA0, SIZE_CODE(sizeof(&gADBOpBlock))) |
- REGISTER_ROUTINE_PARAMETER(2,
- kRegisterD0, SIZE_CODE(sizeof(commandNum))),
- &gADBOpBlock,
- commandNum);
- #else // TARGET_CPU_68K && TARGET_RT_MAC_CFM
- return (ADBOp(refCon, compRout, buffer, commandNum));
- #endif // TARGET_CPU_68K && TARGET_RT_MAC_CFM
- }
-
- // set the leds to the given pattern }
- static void kb_SetMacNumLockLED( Boolean ledOn )
- {
- OSErr retCode;
- ADBAddress anADBadd; // address of each device
- Byte regBuff[9]; // buffer for ADBOp commands
- Byte oldReg;
- Byte LEDPattern;
-
- if ( ledOn )
- LEDPattern = 0x07;
- else
- LEDPattern = 0x00;
-
- // get an address for an ADB device - here we just talk to whatever keyboard
- // is at ADB Address 2. A more complete program might check the type of
- // keyboard present to ensure that it has an LED present.
- anADBadd = 2;
-
- regBuff[0] = (Byte)0; // initial data buffer length
- regBuff[1] = 0;
- regBuff[2] = 0;
-
- // initialize the completion flag so that we will know when the ADBOp call
- // has completed.
- gCompletionFlag = 0;
-
- retCode = MyADBOp( (Ptr)&gCompletionFlag, completionProc, (Ptr)®Buff,
- kTalkCommand + kLEDRegister + 16 * anADBadd );
-
- if ( retCode != noErr ) // queue was full, try again
- {
- gCompletionFlag = 0;
- retCode = MyADBOp( (Ptr)&gCompletionFlag, completionProc, (Ptr)®Buff,
- kTalkCommand + kLEDRegister + 16 * anADBadd );
-
- if ( retCode != noErr ) // queue was still full, give up
- return;
- }
-
- // do nothing until completion routine has run
- do
- {
- }
- while ( ! gCompletionFlag );
-
- regBuff[0] = (Byte)2; // initial data buffer length
- // extended keyboard has a word of data, LEDs are low 3 bits
- oldReg = regBuff[2];
-
- // set the specified bits; note that a clear bit indicates a lit LED
- // note that if LEDpattern is 7, then all three LED's will enable.
- regBuff[2] = (oldReg & 255-7) | (7 - LEDPattern);
-
- // initialize the completion flag so that we will know when the ADBOp call
- // has completed.
- gCompletionFlag = 0;
-
- retCode = MyADBOp( (Ptr)&gCompletionFlag, completionProc, (Ptr)®Buff,
- kListenCommand + kLEDRegister + 16 * anADBadd );
-
- if (retCode != noErr)
- DebugStr("\p error on ADBOp for listen");
- else
- {
- // do nothing until completion routine has run
- do
- {
- }
- while ( ! gCompletionFlag );
- }
-
- } /* end of kb_SetMacNumLockLED */
-
-
- void main (void)
- {
- unsigned long dummy;
- short i;
-
- completionProc = NewADBServiceRoutineProc( CompADBOp );
-
- i = 0;
- // press the button to quit the test
- while (!Button())
- {
- i++;
- kb_SetMacNumLockLED(i % 2);
- Delay(15, &dummy);
- }
-
- if (completionProc != nil)
- DisposeRoutineDescriptor( completionProc );
- }
-