Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
TbltDrvr.a
* |
* Apple Macintosh Developer Technical Support |
* |
* Sample 'ADBS' Resource |
* |
* TbltDrvr |
* |
* TbltDrvr.a - Assembler Source |
* |
* Copyright © 1989 Apple Computer, Inc. |
* All rights reserved. |
* |
* Versions: |
* 1.00 04/89 |
* |
* Components: |
* TbltDrvr.a April 1, 1989 |
* |
* ******************************************************************* |
* BUILD COMMANDS: |
* |
* asm TbltDrvr.a -lo TbltDrvr.a.lst -l |
* link TbltDrvr.a.o -o 'MrBootDisk:System Folder:System' -rt ADBS=4 -ra =16 |
* |
* ******************************************************************* |
* ADBS resources are loaded and executed at boot time (before |
* INIT 31), and are made of two main parts, the installation/ |
* initialization code and the the actual driver. |
* |
* In this example, the installation portion allocates memory |
* in the system heap for the service routine and the "optional |
* data area". It installs the driver using the ADB Mgr call SetADBInfo. |
* |
* Generally speaking, ADB devices are intended to be user input devices. |
* The ADB Manager polls the bus every 11 milliseconds to see if a device |
* has new user input data. This is accomplished by sending a talk R0 command |
* to the last active device. The last active device is the last device that |
* had data to send to the host. If another device has data, it can request |
* a poll by sending a service request signal to the host. |
* |
* When a device has responded to a poll, the ADB Manager will call the driver |
* to process the data. This is done a interrupt time (level 1), and |
* The driver is passed the data, by getting a pointer to a pascal string |
* which contains the actual data. |
* |
* In this example, the data is in the form of a pointing device's coordinates |
* and button(s) state(s). When the driver gets the data, it stores the |
* coordinate information in RawMouse and MTemp. We stuff both RawMouse and MTemp, |
* because the tablet is an "absolute" device. It also checks the state of |
* the button, against MBState, and if there has been a change, it will update |
* MBState, and post either a mouseUp or mouseDown event, as appropriate. |
* |
* NOTE: This code demonstrate how to move the cursor position. This information |
* is meant for input device drivers only, this technique should not |
* be used by applications to move the cursor around. It's bad user |
* interface, and nobody likes a bad user interface, so Just Say No! |
* |
*********************************************************************** |
STRING ASIS |
PRINT OFF |
INCLUDE 'Traps.a' |
INCLUDE 'SysEqu.a' |
PRINT ON |
**************************** Driver Offsets *************************** |
;this is the structure of the "optional data area" |
StartDataArea EQU 0 |
TabltID EQU StartDataArea ;ID so Apps can find this data (should contain 'TBLT') |
; this identifies the structure for this driver, |
; if your structure is different, you should have |
; a different ID. |
R0Count EQU TabltID+4 ;count byte of Pascal data string returned by ADB |
R0Data EQU R0Count+1 ;data can be up to 8 bytes (but reference from R0Count |
; for even address access) |
R1Count EQU R0Data+8 ;count byte of Pascal data string returned by ADB |
;data can be up to 8 bytes (reference from R1Data |
R1Data EQU R1Count+1 ; for even address access) |
MyFlags EQU R1Data+8 ;hi nibble are flags, bit 7 = update system cursor (zero = yes) |
;bit 6 = new R0 data, bit 5 = new R1 data (1 = new) |
;lo nibble is the address we ended up at (set by installer) |
MyTalkR0 EQU MyFlags+1 ;This byte used to build a talk R0 cmd byte with our new address |
RsrvdPtr EQU MyTalkR0+1 ;Back door for Apple (you never knowÉ) |
Scratch EQU RsrvdPtr+4 ;scratch area |
ADBSvRt EQU Scratch+2 ;pointer to service routine |
ADBDtAr EQU ADBSvRt+4 ;pointer to optional data area |
NextjADBProc EQU ADBDtAr+4 ;a place to keep pointer to next guy in jADBProc chain |
EndDataArea EQU NextjADBProc+4 ;this is my end marker & how big it is |
******************************** Equates ****************************** |
TalkR0 EQU $0C ;ADB Talk register zero (installer fills in the device address in upper nibble) |
TalkR1 EQU $0D ;ADB Talk register one (installer fills in the device address in upper nibble) |
DoSysCrsr EQU $80 ;mask for "update system cursor?" flag (in MyFlags) |
FreshR0 EQU $40 ;mask for new R0 data (in MyFlags) |
FreshR1 EQU $20 ;mask for new R1 data (in MyFlags) |
TabltType EQU $7F ;Device type of digitizing tablet |
* jADBProc EQU $6B8 ;can't find this in MPW equ's! |
************************ Entry and installation *********************** |
*** |
*** When the ADBS is loaded and jumped to, it comes here and branches |
*** around the actual driver to the installation code. |
*** |
*** On Entry: A0 = Pointer to this routine |
*** D0 = ADB device address (0-15) |
*** D1 = ADB Device Type |
*** |
*********************************************************************** |
Entry MAIN |
ALIGN 2 |
bra Installer |
Entry2 ;this is how we enter the relocated installer |
move.l a2,a0 |
_DisposHandle ;dispose the original ADBS |
move.l #0,a2 ;clear this handle |
bra noChoice ;now do that installation thang! |
************************ My ADB Service Routine *********************** |
*** |
*** ADB service routine for digitizing tablets. |
*** |
*** This routine is called as a result of the successful completion |
*** of a Talk R0 or Talk R1 command. The successful completion of Talk R0 means |
*** that the tablet has either new coordinate data or a change in a |
*** button state, or both. This routine is also able to handle the |
*** completion of a Talk R1 command, and will update the data area |
*** with R1's contents. |
*** |
*** On Entry: A0 = Pointer to Device Data |
*** A1 = Pointer to this routine |
*** A2 = Pointer to optional data area |
*** D0 = ADB Command that got us called |
*** |
*********************************************************************** |
DataCount EQU 0 ;this is the format of the tablet data |
SwitchWord EQU DataCount+1 ;info about switch(es) state(s) |
XCoord EQU SwitchWord+2 ;hi byte = LSB of X, lo byte = MSB of X |
YCoord EQU XCoord+2 ;hi byte = LSB of Y, lo byte = MSB of Y |
ZCoord EQU YCoord+2 ;hi byte = LSB of Z, lo byte = MSB of Z |
SwitchMask EQU $80 ;bit seven = any button down (if one) |
MySrvcRt |
movem.l a0-a3/d0-d2,-(a7) ;save regs we will abuse |
cmp.b MyTalkR0(a2),d0 |
bne DoOther ;if not a Talk R0, see if a Talk R1 |
move.b MyFlags(a2),d1 |
andi.b #DoSysCrsr,d1 ;see if current app wants us to update the system cursor |
bne.s NoUpdate ;if bit 7 set, just update data area, and check button |
move.b YCoord(a0),MTemp ;move coordinate data into cursor low mem locations |
move.b YCoord+1(a0),MTemp+1 |
move.b XCoord(a0),MTemp+2 |
move.b XCoord+1(a0),MTemp+3 |
move.l MTemp,RawMouse ;cursor guy likes to see this twice |
;to make the position absolute. If RawMouse were not |
;updated, jCrsrTask would attempt to scale the move |
MOVE.B CrsrCouple,CrsrNew ; note the change |
NoUpdate |
lea R0Count(a2),a3 ;set up the destination in a3, source is a0 |
bsr.s MoveData ;go update the data area |
ori.b #FreshR0,MyFlags(a2) ;flag to say the data is new |
; The following code with capatalized mnemonics (can |
; you say that?) is stolen from the Mac II ROM |
; source. Thanks to the 4th floor, DA3 (or wherever |
; they are nowÉ). |
MOVEQ #1, D0 ; D0 holds the event (1 = mouse button down) |
move.b #$00,d2 ;our new MBState, assume mouse down |
move.b SwitchWord+1(a0),d1 ;get switch state |
andi.b #SwitchMask,d1 ;mask for button(s) down |
bne.s Down ;if zero, no button down |
MOVEQ #2, D0 ; set D0 to 2 if mouse button is up |
move.b #$80,d2 ;well, turns out the button's up |
Down MOVE.B MBState, D1 ; get copy of last state |
EOR.B D2, D1 ; did it change? |
BPL.S MyExit ; if it didn't, no event |
; the mouse button changed, do debounce it , only generate event if it wasn't a bounce |
MOVE.L TICKS,D1 ; get current system ticks |
SUB.L MBTICKS,D1 ; and subtract ticks when the button changed |
CMP.L #1,D1 ; was it long enough? |
BLT.S MyExit ; if not, don't post an event |
ADD.L D1,RndSeed ; randomize our seed |
MOVE.L TICKS,MBTICKS ; since it changed, update the ticks |
AND.B #$80, D2 ; just store high bit |
MOVE.B D2, MBState ; also update the state |
; post the mouse button event |
;********************************************************************************************** |
;add call to jCrsrTask!!!!! |
;********************************************************************************************** |
MOVE.L D0, A0 ; get event number where it belongs |
MOVEQ #0, D0 ; no message |
_PostEvent ; post the event |
MyExit movem.l (a7)+,a0-a3/d0-d2 ;restore regs we abused |
rts |
DoOther |
move.b Myflags(a2),d2 |
lsl.b #4,d2 ;move address up to hi nibble |
ori.b #TalkR1,d2 ;now we've built a Talk R1 at our address |
cmp.b d2,d0 ;so we can see if that's why we're here |
bne.s MyExit ;wasn't a Talk R0, or a Talk R1, so get out |
lea R1Count(a2),a3 ;we got a Talk R1, so point to R1 data area for move |
bsr.s MoveData ;go put the R1 data in the data area |
ori.b #FreshR1,MyFlags(a2) ;flag that says data is new |
bra.s MyExit ;all done |
MoveData ;A0 points to source, A3 points to destination |
movem.l a0/a3/d0,-(a7) ;save the regs |
move.w #$08,d0 ;get the count (never more than 9 bytes) |
MD1 move.b (a0)+,(a3)+ ;move a byte at a timeÉ |
dbra d0,MD1 ;until low word of d0 = -1 |
movem.l (a7)+,a0/a3/d0 ;restore the regs |
rts |
************************ My ADBReInit Procedure ********************** |
*** |
*** ADBReInit Proc for deallocating memory before re-initializing |
*** the ADB Mgr |
*** |
*** On Entry: D0 = 0 for pre processing, 1 for post processing |
*** A0 = Pointer to this routine |
*** |
*********************************************************************** |
jProc |
cmpi.b #1,d0 |
beq.s outtaHere ;only do the pre-processing |
move.b d0,d2 |
lea MySrvcRtEnd,a2 ;get a pointer to the data area |
move.l NextjADBProc(a2),-(a7) ;push address of next guy in the chain |
move.l ADBSvRt(a2),a0 |
_DisposPtr ;dispose the service routine and data area pointer |
move.b d2,d0 ;restore d0 |
rts |
outtaHere |
move.l NextjADBProc(a2),-(a7) ;push address of next guy in the chain |
rts |
MySrvcRtEnd ;and begin optional data area |
******************************* Installer ***************************** |
*** On Entry: A0 = Pointer to this routine |
*** D0 = ADB device address (0-15) |
*** D1 = ADB Device Type |
*********************************************************************** |
******************************** Equates ****************************** |
DataSiz EQU EndDataArea-StartDataArea ;this is how big my optional data area is |
RoutineSiz EQU MySrvcRtEnd-MySrvcRt ;this is how big my service routine is |
NewPtrSiz EQU RoutineSiz+DataSiz |
jADBProcOffset EQU jProc-MySrvcRt ;offset from NewPtr to my jADBProc (after blockmove) |
jmpOffset EQU entry2-entry |
Installer |
movem.l a0-a3/d0-d2,-(a7) ;protect the virtue of the registers we use |
move.b d0,d2 ;save device address for later |
move.l #0,a2 ;zero our handle regs (a2 for original ADBS and a3 the new one) |
move.l #0,a3 |
lea Entry,a0 ;get a handle on the ADBS |
_RecoverHandle |
move.l a0,a2 ;keep this handle around, we need to dispose is later |
cmp.b #TabltType,d1 ;see if it's our kind of device |
bne exit ;if not, quit |
_GetHandleSize ;this code relocates the ADBS hi in the heap, to |
;try and cause the least amount of heap fragmentation |
bmi exit ;something's wrong, let's get outta here |
move.l d0,d1 ;we'll need the size later for BlockMove |
_NewHandle ,SYS ;get a new handle of our same size |
bne.s noChoice ;if we can't get memory, go ahead and fragment the sys heap |
move.l a0,a3 ;remember the new handle |
_MoveHHi ;move this new handle up in the heap (error shouldn't be possible) |
_Hlock ;lock it down (error shouldn't occur) |
move.l d1,d0 ;get our size |
move.l (a0),a1 ;set up destination ptr |
move.l (a2),a0 ;and source |
_BlockMove ;move entire ADBS up hi in the heap |
;do this so that the NewPtr will be as low as |
;possible in the heap, avoiding fragmentation due to |
;ADBS being below NewPtr |
adda.l #jmpOffset,a1 ;a0 now points to Entry2 in the copy of this ADBS |
jmp (a1) ;now we start execution in our MoveHHi'd ADBS |
noChoice |
move.l #NewPtrSiz,d0 ;make a block for the driver and data area |
_NewPtr ,SYS,CLEAR ;we likes our bytes clean, we does |
bne.s exit ;abort if error |
move.l a0,a1 ;set up destination for BlockMove |
lea MySrvcRt,a0 ;and source pointer |
move.l #RoutineSiz,d0 ;and how many bytes to move |
_BlockMove ;now move the driver into our new ptr (no errors) |
move.l a1,a0 ;now create pointer to the data area |
adda.l #RoutineSiz,a0 ;a0 now points to area past the service routine |
move.l a0,ADBDtAr(a0) ;keep pointer to data area in data area |
move.l a1,ADBSvRt(a0) ;keep pointer to service routine in data area |
;initialize the data area |
move.l #'TBLT',TabltID(a0) ;set up the drivers data area |
andi.b #$0F,d2 ;clear hi nibble of device address |
or.b d2,MyFlags(a0) ;fill in our address for the driver's sake |
move.b d2,d0 ;set the device addrs for our tablet (for _SetADBInfo) |
lsl.b #4,d2 ;now move the address into the hi nibble |
move.b d2,MyTalkR0(a0) ;Create a TalkR0 command byte for the drvr to compare with |
ori.b #TalkR0,MyTalkR0(a0) ;now we've built a Talk R0 at our address |
move.l a0,d2 ;keep pointer to data area for later |
lea ADBSvRt(a0),a0 ;set up for installing my stuff |
_SetADBInfo ;install it! |
tst.w d0 ;any error? |
bne.s badExit ;if so, abort |
move.l d2,a0 ;get pointer to data area back |
move.l jADBProc,NextjADBProc(a0) ;get the next guy's address |
lea jADBProcOffset(a1),a0 ;set up the jADBProc for _ADBReInt (Just in caseÉ) |
move.l a0,jADBProc ;all done |
exit move.l a2,a0 ;the handle of the original ADBS |
cmpa.l #0,a0 ;make sure it's a real handle |
beq.s exit2 |
_DisposHandle ;nuke it! |
exit2 move.l a3,a0 ;enter here with handle to dispose in a3 |
cmpa.l #0,a0 ;if handle is nil, don't dispose |
beq.s around |
_DisposHandle ; |
around movem.l (a7)+,a0-a3/d0-d2 ;restore the registers we use |
rts ;Return To Sender |
badExit ;error occured after allocating new ptr |
move.l a1,a0 |
_DisposPtr ;get rid of our pointer |
bra.s exit |
END |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14