home *** CD-ROM | disk | FTP | other *** search
- // Sample AppleTalk atlk resource
- // (C) October 1994-1995 Stuart Cheshire <cheshire@cs.stanford.edu>
- //
- // You need to contact Apple to get an adev id assigned.
- // This file must be compiled into a code resource of type 'atlk' with your id.
- // The Think C 7 project file provided will build an adev file containing
- // the adev resource, the atlk resource, and other required resources.
- //
- // The main routine in assembly code here calls various C routines below:
- // Some of the parameters to the C routines are declared volatile to provide
- // call-by-value-return semantics, to allow the C code to easily return values
- // in registers without having to use even more nasty inline assembly code.
- // If your compiler doesn't honour volatile parameters you'll have to write
- // inline assembly code.
- //
- // You should also read the "Macintosh AppleTalk® Connections Programmer's Guide"
- // available from Apple.
-
- #include <AppleTalk.h>
- #include "LAPEqu.h"
-
- #include "StuTypes.h"
- #include "StuAppleTalk.h"
-
- #include "adev.h"
- #include "atlk.h"
-
- #define MESSAGES 0
-
- local MPPglobals *ourMPPvars;
- local Boolean driveropen;
-
- // -------------------------------------------------------------------------------
- #pragma mark Entry point
-
- local OSErr AtlkControl(short const d0, long const d1, Byte const d4, long const a1);
- local OSErr doWrite(void *const completion, WDSElement *const wds,
- MPPglobals *const MPPVars, Byte const addr, const short portcode);
- local OSErr doProbe(void *const completion, Byte *const portUse,
- MPPglobals *const MPPVars, Byte const addr, const short portcode);
-
- // Note: Special structure of code resource; do not change.
- // Write/Probe entry point at start of resource
- // Control routines entry point at offset 2 from start of resource
- export void main(void)
- {
- asm {
- @0 bra.s @write ; Branch immediately to the write routne
-
- ; CONTROL entry point
- move.l a4, -(sp) ; Save A4
- lea @0, a4 ; set up global register
-
- move.l a1, -(sp) ; push parameters
- move.b d4, -(sp)
- move.l d1, -(sp)
- move.w d0, -(sp)
- bsr AtlkControl
- lea 2(sp), sp ; restore registers (except return value in d0)
- move.l (sp)+, d1
- move.b (sp)+, d4
- move.l (sp)+, a1
-
- move.l (sp)+, a4 ; Restore A4 and return
- rts
-
- ; ----------------------------------------------------------------------------
-
- ; WRITE/PROBE entry point
- @write move.l a4, -(sp) ; Save A4
- lea @0, a4 ; set up global register
-
- move.w d3, -(sp) ; port code
- move.b d2, -(sp) ; address
- move.l a2, -(sp) ; MPP globals
- move.l a1, -(sp) ; WDS (for write) or port use byte (probe)
- move.l a0, -(sp) ; Completion routine address
-
- tst.b d0
- bne.s @probe
- bsr doWrite
- bra @done
- @probe bsr doProbe
-
- @done move.l (sp)+, a0 ; Put the registers back
- move.l (sp)+, a1
- move.l (sp)+, a2
- move.b (sp)+, d2
- move.w (sp)+, d3
-
- move.l (sp)+, a4 ; Restore A4
- cmpi.w #1, d0 ; if return code is 1
- beq.s @async ; it means competion will be asyncronous
- jsr (a0)
- @async clr.w d0
- }
- }
-
- // -------------------------------------------------------------------------------
- #pragma mark Utility Routines
-
- // Glue to call back to the LAP Manager
- #pragma parameter __D0 CallLAPMgr(__D0, __A0, __D1, __D2, __A1)
- local long CallLAPMgr(long CallCode, void *Pa0, long Pd1, long Pd2, long Pd4) =
- {
- 0x2F04, // MOVE.L D4,-(A7) ; preserve D4
- 0x2809, // MOVE.L A1,D4 ; put port number in d4
- 0x2278, 0x0B18, // MOVEA.L $0B18,A1 ; get address of LAP Manager
- 0x4EA9, 0x0002, // JSR $0002(A1) ; and call it
- 0x281F // MOVEA.L (A7)+,D4 ; restore D4
- };
-
- // -------------------------------------------------------------------------------
- // Global variables
-
- local u_short num_ports;
- local MPPglobals *ourMPPglobals;
-
- // -------------------------------------------------------------------------------
- #pragma mark Sending Routines
-
- // Note if we give a return code value 1 here, the glue returns with rts
- // Otherwise, it does the appropriate magic to do the immediate return via a0
- // Also note, portcode passed in d3 seems to be 0x28A + (port number * 0x10)
- local OSErr doWrite(void *const completion, WDSElement *const wds,
- MPPglobals *const MPPVars, Byte const addr, short const portcode)
- {
- OSErr retcode = noErr;
- // If the packet is sent asynchronously, return 1
- // If the packet is sent synchronously, return noErr
- // Otherwise, return an error code
-
- #if DEBUG
- char buffer[1024], *ptr = buffer+1;
- WDSElement *w = wds;
- while (w->entryLength)
- {
- BlockMoveData(w->entryPtr, ptr, w->entryLength);
- ptr += w->entryLength;
- w++;
- }
- asm { lea buffer, a0 }
- asm { move.l ptr, d0 }
- asm { sub.l a0, d0 }
- DebugStr("\pPacket at a0+1 length+1 in d0; dm a0 d0");
- #endif
-
- return(retcode);
- }
-
- local OSErr doProbe(void *const completion, Byte *const portUse,
- MPPglobals *const MPPVars, Byte const addr, short const portcode)
- {
- // Probe packet: To: FF; From: US; Protocol: ShortDDP; Length: 0002
- static u_char probe[5] = { 0xFF, 0, 1, 00, 02 };
- static WDSElement wds[2];
- OSErr retcode = noErr;
- ourMPPvars = MPPVars;
- wds[0].entryLength = sizeof(probe);
- wds[0].entryPtr = (Ptr)probe;
- return(doWrite(completion, wds, MPPVars, addr, portcode));
- }
-
- // -------------------------------------------------------------------------------
- #pragma mark Receiving Routines
-
- // This assembly glue defines the routines for readpacket and readrest
- local void dispatch_table(void)
- {
- asm { bra.s @RdPkt ; readpacket entry point
-
- sub.w d1, d3 ; readrest entry point: subtract packet size from request
- bpl.s @rr_1 ; OK: packet is smaller or equal to buffer size
- add.w d3, d1 ; Not OK: shorten packet to buffer size
- bra.s @rr_1
- @rr_0 move.b (a0)+, (a3)+ ; copy the data to the requested destination
- @rr_1 dbra d1, @rr_0
- clr.l d1 ; set Z flag to indicate no error
- @finish move.l a1, a5 ; must now restore a5, as promised in IM II-326
- rts
-
- @RdPkt sub.w d3, d1 ; Subtract requested count (d3) from bytes remaining (d1)
- bpl.s @rp_1 ; OK: bytes remaining is higher or same
- moveq #-1, d3 ; No: return error code
- bra.s @finish ; Must restore A5 before exit if error (see IM II-328)
- @rp_0 move.b (a0)+, (a3)+ ; copy the data to the requested destination
- @rp_1 dbra d3, @rp_0
- clr.l d3 ; reset d3 to zero and set Z flag to indicate no error
- }
- }
-
- local void DeliverPacket(u_char *packet, u_short length)
- {
- // Note: Be careful here: Remember that the C compiler is using registers too
- // Spec of ReadPacket/ReadRest (TN NW13 p7) says:
- // Registers D0, D2, and D3 can be used freely throughout the socket listener.
- // A6, and D4 to D7 must be preserved.
- // From entry to socket listener until ReadRest is called:
- // The A5 register can be used. Registers A0-A2, A4, and D1 must be preserved.
- // From ReadRest until exit from socket listener:
- // The A5 register must be preserved. Registers A0-A3 and D0-D3 are free to use.
- asm {
- movem.l d0-d7/a0-a5, -(sp) ; preserve registers
- move.l packet, a0 ; put pointer to data in a0
- move.l a5, a1 ; put a5 in a1, where we can find it later
- move.l ourMPPvars, a2 ; set up a2 as required
- lea MPPglobals.destnode(a2), a3 ; initialize a3 to start of RHA
- move.l (a0)+, (a3)+ ; copy first five bytes of packet into RHA
- move.b (a0)+, (a3)+
- lea dispatch_table, a4 ; set up a4 to point to dispatch table
- clr.l d1
- move.w length, d1 ; set up d1 with length of AppleTalk packet
- sub.l #2, d1 ; subtract the length bytes we just read
- move.b MPPglobals.ALAPproto(a2), d2 ; read protocol type into d2
-
- move.l LAPMgrPtr,a5 ; Now call the LAP manager
- move.l #LRdDispatch, d0
- pea @0
- jsr LAPMgrCall(a5)
- lea 4(sp), sp ; actual return means error happened
- @0 movem.l (sp)+, d0-d7/a0-a5 ; restore registers
- }
- }
-
- // -------------------------------------------------------------------------------
- #pragma mark General Control Routines
-
- local long doAInstall(u_long volatile pram, Byte const portnum)
- {
- long retcode;
- long index = (pram >> 8) & 0xFF;
- if (MESSAGES) DebugStr("\pAInstall");
- num_ports = 1;
- if (index >= num_ports) return(-1);
- // LWrtInsert: Flags is zero, number of retries to obtain an address is 8
- retcode = CallLAPMgr(LWrtInsert, &main, 0, 8, portnum);
- return(retcode);
- }
-
- local OSErr doAShutdown(Byte const portnum)
- {
- if (MESSAGES) DebugStr("\pAShutdown");
- CallLAPMgr(LWrtRemove, NULL, 0, 0, portnum);
- return(noErr);
- }
-
- local OSErr doAGetInfo(void *buffer, short length)
- {
- int i;
- ATlkInfo info;
- if (MESSAGES) DebugStr("\pAGetInfo");
- info.Version = 2; // version 2
- info.InfoLength = sizeof(ATlkInfo); // length of record
- info.LinkSpeed = 57600; // speed, in bits per second
- info.BandWidth = 1; // hop count for link
- info.Reserved[0] = 0; // clear to zero
- info.Reserved[1] = 0; // clear to zero (slot number? See TN NW13 p57)
- info.Reserved[2] = 0; // clear to zero
- info.Flags = 0; // not extended or half router
- info.LinkAdrLen = 6; // length of MAC address
- for (i=0; i<6; i++) info.LinkAddress[i] = 0;
- info.MaxNodes = 0;
-
- if (length > sizeof(ATlkInfo)) length = sizeof(ATlkInfo);
- BlockMoveData(&info, buffer, length);
- if (length >= sizeof(ATlkInfo)) return(noErr); else return(-1);
- }
-
- local OSErr doAOpen(Byte const portnum)
- {
- OSErr retcode;
- if (MESSAGES) DebugStr("\pAOpen");
- driveropen = TRUE;
- return(noErr);
- }
-
- local OSErr doAClose(Byte const portnum)
- {
- if (MESSAGES) DebugStr("\pAClose");
- driveropen = FALSE;
- return(noErr);
- }
-
- local OSErr AtlkControl(short const d0, long const d1, Byte const d4, long const a1)
- {
- switch(d0)
- {
- case AInstall : return(doAInstall(d1, d4));
- case AShutdown: return(doAShutdown(d4));
- case AGetInfo : return(doAGetInfo((void*)a1, d1));
- case AGetMCast: if (MESSAGES) DebugStr("\pAGetMCast"); return(-1);
- case ASetMCast: if (MESSAGES) DebugStr("\pASetMCast"); return(-1);
- case ADelMCast: if (MESSAGES) DebugStr("\pADelMCast"); return(-1);
- case AOpen : return(doAOpen(d4));
- case AClose : return(doAClose(d4));
- case AEnq : if (MESSAGES) DebugStr("\pAEnq"); return(-1);
- case ADelAddr : if (MESSAGES) DebugStr("\pADelAddr"); return(-1);
- default: DebugStr("\pInvalid AtlkControl call"); return(-1);
- }
- }
-