**	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