home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Snippets / Stuart's Tech Notes / Sample AppleTalk adev / atlk.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-29  |  10.1 KB  |  301 lines  |  [TEXT/KAHL]

  1. // Sample AppleTalk atlk resource
  2. // (C) October 1994-1995 Stuart Cheshire <cheshire@cs.stanford.edu>
  3. //
  4. // You need to contact Apple to get an adev id assigned.
  5. // This file must be compiled into a code resource of type 'atlk' with your id.
  6. // The Think C 7 project file provided will build an adev file containing
  7. // the adev resource, the atlk resource, and other required resources.
  8. // 
  9. // The main routine in assembly code here calls various C routines below:
  10. // Some of the parameters to the C routines are declared volatile to provide
  11. // call-by-value-return semantics, to allow the C code to easily return values
  12. // in registers without having to use even more nasty inline assembly code.
  13. // If your compiler doesn't honour volatile parameters you'll have to write
  14. // inline assembly code.
  15. //
  16. // You should also read the "Macintosh AppleTalk® Connections Programmer's Guide"
  17. // available from Apple.
  18.  
  19. #include <AppleTalk.h>
  20. #include "LAPEqu.h"
  21.  
  22. #include "StuTypes.h"
  23. #include "StuAppleTalk.h"
  24.  
  25. #include "adev.h"
  26. #include "atlk.h"
  27.  
  28. #define MESSAGES 0
  29.  
  30. local MPPglobals *ourMPPvars;
  31. local Boolean driveropen;
  32.  
  33. // -------------------------------------------------------------------------------
  34. #pragma mark Entry point
  35.  
  36. local OSErr AtlkControl(short const d0, long const d1, Byte const d4, long const a1);
  37. local OSErr doWrite(void *const completion, WDSElement *const wds,
  38.             MPPglobals *const MPPVars, Byte const addr, const short portcode);
  39. local OSErr doProbe(void *const completion, Byte *const portUse,
  40.             MPPglobals *const MPPVars, Byte const addr, const short portcode);
  41.  
  42. // Note: Special structure of code resource; do not change.
  43. // Write/Probe entry point at start of resource
  44. // Control routines entry point at offset 2 from start of resource
  45. export void main(void)
  46.     {
  47.     asm        {
  48.     @0        bra.s    @write            ; Branch immediately to the write routne
  49.     
  50.     ; CONTROL entry point
  51.             move.l    a4, -(sp)        ; Save A4
  52.             lea        @0, a4            ; set up global register
  53.             
  54.             move.l    a1, -(sp)        ; push parameters
  55.             move.b    d4, -(sp)
  56.             move.l    d1, -(sp)
  57.             move.w    d0, -(sp)
  58.             bsr        AtlkControl
  59.             lea        2(sp), sp        ; restore registers (except return value in d0)
  60.             move.l    (sp)+, d1
  61.             move.b    (sp)+, d4
  62.             move.l    (sp)+, a1
  63.  
  64.             move.l    (sp)+, a4        ; Restore A4 and return
  65.             rts
  66.     
  67.     ; ----------------------------------------------------------------------------
  68.             
  69.     ; WRITE/PROBE entry point
  70.     @write    move.l    a4, -(sp)        ; Save A4
  71.             lea        @0, a4            ; set up global register
  72.             
  73.             move.w    d3, -(sp)        ; port code
  74.             move.b    d2, -(sp)        ; address
  75.             move.l    a2, -(sp)        ; MPP globals
  76.             move.l    a1, -(sp)        ; WDS (for write) or port use byte (probe)
  77.             move.l    a0, -(sp)        ; Completion routine address
  78.             
  79.             tst.b    d0
  80.             bne.s    @probe
  81.             bsr        doWrite
  82.             bra        @done
  83.     @probe    bsr        doProbe
  84.  
  85.     @done    move.l    (sp)+, a0        ; Put the registers back
  86.             move.l    (sp)+, a1
  87.             move.l    (sp)+, a2
  88.             move.b    (sp)+, d2
  89.             move.w    (sp)+, d3
  90.  
  91.             move.l    (sp)+, a4        ; Restore A4
  92.             cmpi.w    #1, d0            ; if return code is 1
  93.             beq.s    @async            ; it means competion will be asyncronous
  94.             jsr        (a0)
  95.     @async    clr.w    d0
  96.             }
  97.     }
  98.  
  99. // -------------------------------------------------------------------------------
  100. #pragma mark Utility Routines
  101.  
  102. // Glue to call back to the LAP Manager
  103. #pragma parameter __D0 CallLAPMgr(__D0, __A0, __D1, __D2, __A1)
  104. local long CallLAPMgr(long CallCode, void *Pa0, long Pd1, long Pd2, long Pd4) =
  105.     {
  106.     0x2F04,                // MOVE.L    D4,-(A7)            ; preserve D4
  107.     0x2809,                // MOVE.L    A1,D4                ; put port number in d4
  108.     0x2278, 0x0B18,        // MOVEA.L   $0B18,A1            ; get address of LAP Manager
  109.     0x4EA9, 0x0002,        // JSR       $0002(A1)            ; and call it
  110.     0x281F                // MOVEA.L   (A7)+,D4            ; restore D4
  111.     };
  112.  
  113. // -------------------------------------------------------------------------------
  114. // Global variables
  115.  
  116. local u_short num_ports;
  117. local MPPglobals *ourMPPglobals;
  118.  
  119. // -------------------------------------------------------------------------------
  120. #pragma mark Sending Routines
  121.  
  122. // Note if we give a return code value 1 here, the glue returns with rts
  123. // Otherwise, it does the appropriate magic to do the immediate return via a0
  124. // Also note, portcode passed in d3 seems to be 0x28A + (port number * 0x10)
  125. local OSErr doWrite(void *const completion, WDSElement *const wds,
  126.     MPPglobals *const MPPVars, Byte const addr, short const portcode)
  127.     {
  128.     OSErr retcode = noErr;
  129.     // If the packet is sent asynchronously, return 1
  130.     // If the packet is sent synchronously, return noErr
  131.     // Otherwise, return an error code
  132.     
  133. #if DEBUG
  134.     char buffer[1024], *ptr = buffer+1;
  135.     WDSElement *w = wds;
  136.     while (w->entryLength)
  137.         {
  138.         BlockMoveData(w->entryPtr, ptr, w->entryLength);
  139.         ptr += w->entryLength;
  140.         w++;
  141.         }
  142.     asm { lea buffer, a0 }
  143.     asm { move.l ptr, d0 }
  144.     asm { sub.l a0, d0 }
  145.     DebugStr("\pPacket at a0+1 length+1 in d0; dm a0 d0");
  146. #endif
  147.     
  148.     return(retcode);
  149.     }
  150.  
  151. local OSErr doProbe(void *const completion, Byte *const portUse,
  152.     MPPglobals *const MPPVars, Byte const addr, short const portcode)
  153.     {
  154.     // Probe packet: To: FF; From: US; Protocol: ShortDDP; Length: 0002
  155.     static u_char probe[5] = { 0xFF, 0, 1, 00, 02 };
  156.     static WDSElement wds[2];
  157.     OSErr retcode = noErr;
  158.     ourMPPvars = MPPVars;
  159.     wds[0].entryLength = sizeof(probe);
  160.     wds[0].entryPtr    = (Ptr)probe;
  161.     return(doWrite(completion, wds, MPPVars, addr, portcode));
  162.     }
  163.  
  164. // -------------------------------------------------------------------------------
  165. #pragma mark Receiving Routines
  166.  
  167. // This assembly glue defines the routines for readpacket and readrest
  168. local void dispatch_table(void)
  169.     {
  170.     asm    {    bra.s    @RdPkt            ; readpacket entry point
  171.             
  172.             sub.w    d1, d3            ; readrest entry point: subtract packet size from request
  173.             bpl.s    @rr_1            ; OK: packet is smaller or equal to buffer size
  174.             add.w    d3, d1            ; Not OK: shorten packet to buffer size
  175.             bra.s    @rr_1
  176.     @rr_0    move.b    (a0)+, (a3)+    ; copy the data to the requested destination
  177.     @rr_1    dbra    d1, @rr_0
  178.             clr.l    d1                ; set Z flag to indicate no error
  179.     @finish    move.l    a1, a5            ; must now restore a5, as promised in IM II-326
  180.             rts
  181.             
  182.     @RdPkt    sub.w    d3, d1            ; Subtract requested count (d3) from bytes remaining (d1)
  183.             bpl.s    @rp_1            ; OK: bytes remaining is higher or same
  184.             moveq    #-1, d3            ; No: return error code
  185.             bra.s    @finish            ; Must restore A5 before exit if error (see IM II-328)
  186.     @rp_0    move.b    (a0)+, (a3)+    ; copy the data to the requested destination
  187.     @rp_1    dbra    d3, @rp_0
  188.             clr.l    d3                ; reset d3 to zero and set Z flag to indicate no error
  189.         }
  190.     }
  191.  
  192. local void DeliverPacket(u_char *packet, u_short length)
  193.     {
  194.     // Note: Be careful here: Remember that the C compiler is using registers too
  195.     // Spec of ReadPacket/ReadRest (TN NW13 p7) says:
  196.     // Registers D0, D2, and D3 can be used freely throughout the socket listener.
  197.     // A6, and D4 to D7 must be preserved.
  198.     // From entry to socket listener until ReadRest is called:
  199.     //  The A5 register can be used. Registers A0-A2, A4, and D1 must be preserved.
  200.     // From ReadRest until exit from socket listener:
  201.     //  The A5 register must be preserved. Registers A0-A3 and D0-D3 are free to use.
  202.     asm    {
  203.         movem.l    d0-d7/a0-a5, -(sp)                ; preserve registers
  204.         move.l    packet, a0                        ; put pointer to data in a0
  205.         move.l    a5, a1                            ; put a5 in a1, where we can find it later
  206.         move.l    ourMPPvars, a2                    ; set up a2 as required
  207.         lea        MPPglobals.destnode(a2), a3        ; initialize a3 to start of RHA
  208.         move.l    (a0)+, (a3)+                    ; copy first five bytes of packet into RHA
  209.         move.b    (a0)+, (a3)+
  210.         lea        dispatch_table, a4                ; set up a4 to point to dispatch table
  211.         clr.l    d1
  212.         move.w    length, d1                        ; set up d1 with length of AppleTalk packet
  213.         sub.l    #2, d1                            ; subtract the length bytes we just read
  214.         move.b    MPPglobals.ALAPproto(a2), d2    ; read protocol type into d2
  215.         
  216.         move.l    LAPMgrPtr,a5                    ; Now call the LAP manager
  217.         move.l    #LRdDispatch, d0
  218.         pea        @0
  219.         jsr        LAPMgrCall(a5)
  220.         lea        4(sp), sp                        ; actual return means error happened
  221.     @0    movem.l    (sp)+, d0-d7/a0-a5                ; restore registers
  222.         }
  223.     }
  224.  
  225. // -------------------------------------------------------------------------------
  226. #pragma mark General Control Routines
  227.  
  228. local long doAInstall(u_long volatile pram, Byte const portnum)
  229.     {
  230.     long retcode;
  231.     long index = (pram >> 8) & 0xFF;
  232.     if (MESSAGES) DebugStr("\pAInstall");
  233.     num_ports = 1;
  234.     if (index >= num_ports) return(-1);
  235.     // LWrtInsert: Flags is zero, number of retries to obtain an address is 8
  236.     retcode = CallLAPMgr(LWrtInsert, &main, 0, 8, portnum);
  237.     return(retcode);
  238.     }
  239.  
  240. local OSErr doAShutdown(Byte const portnum)
  241.     {
  242.     if (MESSAGES) DebugStr("\pAShutdown");
  243.     CallLAPMgr(LWrtRemove, NULL, 0, 0, portnum);
  244.     return(noErr);
  245.     }
  246.  
  247. local OSErr doAGetInfo(void *buffer, short length)
  248.     {
  249.     int i;
  250.     ATlkInfo info;
  251.     if (MESSAGES) DebugStr("\pAGetInfo");
  252.     info.Version     = 2;                    // version 2
  253.     info.InfoLength  = sizeof(ATlkInfo);    // length of record
  254.     info.LinkSpeed   = 57600;                // speed, in bits per second
  255.     info.BandWidth   = 1;                    // hop count for link
  256.     info.Reserved[0] = 0;                    // clear to zero
  257.     info.Reserved[1] = 0;                    // clear to zero (slot number? See TN NW13 p57)
  258.     info.Reserved[2] = 0;                    // clear to zero
  259.     info.Flags       = 0;                    // not extended or half router
  260.     info.LinkAdrLen  = 6;                    // length of MAC address
  261.     for (i=0; i<6; i++) info.LinkAddress[i] = 0;
  262.     info.MaxNodes    = 0;
  263.  
  264.     if (length > sizeof(ATlkInfo)) length = sizeof(ATlkInfo);
  265.     BlockMoveData(&info, buffer, length);
  266.     if (length >= sizeof(ATlkInfo)) return(noErr); else return(-1);
  267.     }
  268.  
  269. local OSErr doAOpen(Byte const portnum)
  270.     {
  271.     OSErr retcode;
  272.     if (MESSAGES) DebugStr("\pAOpen");
  273.     driveropen = TRUE;
  274.     return(noErr);
  275.     }
  276.  
  277. local OSErr doAClose(Byte const portnum)
  278.     {
  279.     if (MESSAGES) DebugStr("\pAClose");
  280.     driveropen = FALSE;
  281.     return(noErr);
  282.     }
  283.  
  284. local OSErr AtlkControl(short const d0, long const d1, Byte const d4, long const a1)
  285.     {
  286.     switch(d0)
  287.         {
  288.         case AInstall : return(doAInstall(d1, d4));
  289.         case AShutdown: return(doAShutdown(d4));
  290.         case AGetInfo : return(doAGetInfo((void*)a1, d1));
  291.         case AGetMCast: if (MESSAGES) DebugStr("\pAGetMCast"); return(-1);
  292.         case ASetMCast: if (MESSAGES) DebugStr("\pASetMCast"); return(-1);
  293.         case ADelMCast: if (MESSAGES) DebugStr("\pADelMCast"); return(-1);
  294.         case AOpen    : return(doAOpen(d4));
  295.         case AClose   : return(doAClose(d4));
  296.         case AEnq     : if (MESSAGES) DebugStr("\pAEnq"); return(-1);
  297.         case ADelAddr : if (MESSAGES) DebugStr("\pADelAddr"); return(-1);
  298.         default: DebugStr("\pInvalid AtlkControl call"); return(-1);
  299.         }
  300.     }
  301.