home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 515.lha / NewSer / newser.a < prev    next >
Text File  |  1991-06-08  |  66KB  |  2,665 lines

  1. *****************************************************************************
  2. * Program:  newser.asm - Copyright ©1990,91 by Dan Babcock
  3. * Function: A "serial.device" compatible driver for the Rockwell 65C52
  4. *           based on the 1.3 RKM driver example.
  5. *
  6. * Author:   Dan Babcock
  7. * History:  08/12/90 V0.50 Created
  8. *           09/06/90 V0.51 Cleaned up "eofdump" code.
  9. *           11/04/90 V0.52 Misc. minor changes
  10. *           11/25/90 V0.53 Changed path and name of include file
  11. *        03/25/91 V1.10 I (Mike Mossman) added code to support the
  12. *               ASDG SetCtrlLines command.
  13. *
  14. * [To all: Please don't forget to bump the revision numbers
  15. *          if you do *any* modifications at all.  -Jeff]
  16. *
  17. * This code is designed to be ROMable (but not position independent).
  18. *
  19. * Feel free to contact me:
  20. *
  21. * [School address]               [Permanent address]      People/Link:
  22. *  Dan Babcock                    Dan Babcock              DANBABCOCK
  23. *  Atherton Hall Room 63          P.O. Box 1532
  24. *  University Park, PA  16802     Southgate, MI  48195
  25. *  Voice: (814)-862-2931
  26. *
  27. * I am also reachable via internet. I read comp.sys.amiga.tech.
  28. *
  29. * General notes
  30. * =============
  31. * The macro "PUTDEBUG" is used to output debugging information via the
  32. * internal serial port at a low level. It may be used anywhere, including
  33. * critical sections, supervisor mode, and interrupt code. If debugging is
  34. * not desired, set the INFO_LEVEL equate to zero. Conversely, if debugging
  35. * is desired, set it to a high value (e.g. 100000)
  36. *
  37. * A consistent (for the most part) usage of registers was employed:
  38. *  A1 - pointer to an IORequest structure
  39. *  A3 - pointer to a unit structure (defined below)
  40. *  A4 - pointer to a serprefs structure (defined below)
  41. *  A5 - pointer to the hardware (one channel, that is)
  42. *  A6 - pointer to the device structure (defined below)
  43. *
  44. * Known difference(s) between this and serial.device are:
  45. *  1. Start/Stop do not send XON/XOFF characters to the outside world
  46. *     as implied in the autodoc (I don't think this is important).
  47. *  2. Reading is never performed in the caller's context.
  48. *  3. Newser does not currently send an XOFF or otherwise tell the outside
  49. *     world to "shut up" when the driver's input buffer fills; it simply
  50. *     reports a buffer overflow condition and continues as normal.
  51. *
  52. * Possible future enhancements:
  53. *  1. Read the default prefs from memory (set up previously) or a file
  54. *  2. Check to see whether units 3 & 4, if requested, actually exist
  55. *
  56. * Suggestions for additional enhancements are welcome.
  57. *****************************************************************************
  58.  
  59.  
  60. VERSION            EQU    1
  61. REVISION        EQU    1
  62. INFO_LEVEL      EQU     0
  63.  
  64.  
  65. ;This define is used to tell which commands should be handled
  66. ;immediately (on the caller's schedule).
  67. ;
  68. ;The immediate commands are Invalid, Reset, Stop, Start, Flush, Clear,
  69. ;Query, and SetParams
  70. ;
  71. ;Note that this method limits you to just 32 device specific commands,
  72. ;which may not be enough.
  73.  
  74. IMMEDIATES    EQU    %00000000000000010000101111110011
  75. ;                 --------========--------========
  76. ;                 FEDCBA9876543210FEDCBA9876543210
  77.  
  78.  
  79.         INCDIR "include:"
  80.  
  81.     INCLUDE    "exec/types.i"
  82.     INCLUDE "exec/funcdef.i"
  83.     INCLUDE "exec/exec.i"
  84.     INCLUDE "exec/exec_lib.i"
  85.     INCLUDE "exec/ables.i"
  86.     INCLUDE "exec/errors.i"
  87.     INCLUDE "exec/interrupts.i"
  88.     INCLUDE    "exec/libraries.i"
  89.     INCLUDE    "exec/lists.i"
  90.     INCLUDE    "exec/initializers.i"
  91.     INCLUDE    "exec/resident.i"
  92.     INCLUDE "devices/serial.i"
  93.     INCLUDE "devices/timer.i"
  94.     INCLUDE "hardware/custom.i"
  95.     INCLUDE "hardware/intbits.i"
  96.     INCLUDE "libraries/dos.i"
  97.     INCLUDE "libraries/dosextens.i"
  98.         INCLUDE "ioexp.i"
  99.     
  100.     
  101.     ; Things we define for external reference (for easier debuggging)
  102.     XDEF    LibStart
  103.     XDEF    RomTag
  104.     XDEF    LibName
  105.     XDEF    LibIDString
  106.     XDEF    LibInit
  107.     XDEF    LibOpen
  108.     XDEF    LibClose
  109.     XDEF    LibExpunge
  110.     XDEF    LibExtFunc
  111.     XDEF    LibBeginIO
  112.     XDEF    LibAbortIO
  113.     XDEF    LibEnd
  114.         XDEF    inittable
  115.     XDEF    functable
  116.     XDEF    datatable
  117.     XDEF    defaultprefs
  118.     XDEF    basetable
  119.     XDEF    baudtable
  120.     XDEF    cmdtable
  121.     XDEF    mdu_Init
  122.     XDEF    LibEnd
  123.     XDEF    LibStart
  124.     XDEF    mydebug
  125.     XDEF    InitTask
  126.     XDEF    InitDACIA
  127.     XDEF    SetUpUnit
  128.     XDEF    InitUnit
  129.         XDEF    LibBeginIO
  130.         XDEF    BeginIO_QueueMsg
  131.         XDEF    BeginIO_Immediate
  132.         XDEF    PerformIO
  133.         XDEF    BeginIO_End
  134.         XDEF    BeginIO_NoCmd
  135.         XDEF    queuewrt
  136.         XDEF    notread
  137.         XDEF    ReadTask_Begin
  138.         XDEF    ReadSigLoop
  139.         XDEF    ReadTask_MainLoop
  140.         XDEF    ReadTask_StartHere
  141.         XDEF    ReadTask_NextMessage
  142.         XDEF    Readignorecmd
  143.         XDEF    Readconttl
  144.  
  145.     SECTION    CODE
  146.  
  147.     ; Supposed start of executable code.  This is where execution
  148.     ; will start if anybody's silly enough to try and run the library
  149.     ; from the command line.  Just return the highest error code we
  150.     ; conveniently can to tell them they screwed up.
  151. LibStart:
  152.     moveq    #$7F,d0
  153.     rts
  154.  
  155.     ; Where the magic begins.  OpenLibrary actually looks through the
  156.     ; library file contents trying to find this table by locating the
  157.     ; magic RTC_MATCHWORD value followed by its own address.  This
  158.     ; table then tells OpenLibrary where to find other things it needs.
  159.     ; This needs to be close to the front of your library file to cut
  160.     ; down on the amount of searching OpenLibrary does; that's why
  161.     ; this object file should be first in the link list.
  162.     
  163. RomTag:    dc.w    RTC_MATCHWORD    ; Magic value to search for to find table
  164.     dc.l    RomTag        ; Address of matchword; the two together prevent accidental matches
  165.     dc.l    LibEnd        ; Address of end of library handler code
  166.     dc.b    RTF_AUTOINIT    ; Request system to automatically initialize our library
  167.     dc.b    VERSION        ; Version number of our library (defined below)
  168.     dc.b    NT_DEVICE    ; Node type = Device
  169.     dc.b    0        ; Node priority = 0 (normal)
  170.     dc.l    LibName        ; Name of this library file, for debugging info
  171.     dc.l    LibIDString    ; More debugging info
  172.     dc.l    inittable    ; Initialization table used by RTF_AUTOINIT
  173.  
  174. LibName:
  175.     dc.b    "newser.device",0
  176. Task1:    
  177.     dc.b    "NewserRead",0
  178. Task2:    
  179.     dc.b    "NewserWrite",0
  180. LibIDString:
  181.     dc.b    "NewSer 1.1S (21 Mar 1991)",13,10,0
  182. timername
  183.     dc.b    'timer.device',0
  184.     
  185.     ds.w    0
  186.  
  187. inittable:
  188.     dc.l    md_SIZE             ; Size of our library base struct
  189.     dc.l    functable            ; Where our function addresses are
  190.     dc.l    datatable           ; Initialization info for our library base struct
  191.     dc.l    LibInit                ; Library initialization routine address
  192.  
  193. functable:
  194.     dc.l    LibOpen            ; Addresses of all library functions
  195.     dc.l    LibClose        ; First 4 MUST be provided, in this order
  196.     dc.l    LibExpunge
  197.     dc.l    LibExtFunc
  198.     dc.l    LibBeginIO           ; The meat of the library.
  199.     dc.l    LibAbortIO    
  200.     dc.l    -1            
  201.                              
  202.                                  
  203.  
  204.     ; Things for the system to automatically initialize for us via RTF_AUTOINIT request
  205. datatable:
  206.     INITBYTE    LN_TYPE,NT_DEVICE
  207.     INITLONG    LN_NAME,LibName
  208.     INITBYTE    LIB_FLAGS,LIBF_SUMUSED | LIBF_CHANGED
  209.     INITWORD    LIB_VERSION,VERSION
  210.     INITWORD    LIB_REVISION,REVISION
  211.     INITLONG    LIB_IDSTRING,LibIDString
  212.     dc.l    0
  213.  
  214.  
  215. ;This routine gets called after the device has been allocated.  The device
  216. ;pointer is in D0.  The AmigaDOS segment list is in a0.  If it returns the
  217. ;device pointer, then the device will be linked into the device list.  If it
  218. ;returns NULL, then the device will be unloaded.
  219. ;
  220. ;This call is single-threaded by exec; please read the description for
  221. ;"Open" below.
  222. ;
  223. ; Register Usage
  224. ; ==============
  225. ; a3 -- Points to temporary RAM
  226. ; a4 -- Expansion library base
  227. ; a5 -- device pointer
  228. ; a6 -- Exec base
  229.  
  230. LibInit:
  231.     PUTDEBUG 100,<'Init: called'>
  232.     movem.l    d0-d7/a0-a6,-(sp)    ;Preserve ALL modified registers
  233.     movea.l    d0,a5               ;Device ptr
  234.     move.l    a6,md_SysLib(a5)    ;Save a pointer to exec
  235.     move.l    a0,md_SegList(a5)       ;Save pointer to our loaded code
  236.  
  237. ;Now fill in the prefs in MyDev with reasonable defaults. Jeff has suggested
  238. ;starting a process and reading them from a file.
  239.  
  240.     movea.l    a5,a6
  241.     bsr.b    SetDefaultPrefs
  242.     move.l    a5,d0            ;a5 set to 0 above if an error occured
  243.     PUTDEBUG 100,<'Init: finished'>
  244.     movem.l    (sp)+,d0-d7/a0-a6
  245.     rts
  246.  
  247. ;Enter with device ptr in a6.
  248.  
  249. SetDefaultPrefs
  250.     movem.l    d0/d1/a0/a1,-(sp)
  251.     lea    prefs_unit0(a6),a1
  252.     moveq    #MD_NUMUNITS-1,d1
  253. 1$
  254.     move.w    #prefs_SIZE-1,d0
  255.     lea    defaultprefs(pc),a0
  256. 2$
  257.     move.b    (a0)+,(a1)+
  258.     dbra    d0,2$
  259.     dbra    d1,1$
  260.     movem.l    (sp)+,d0/d1/a0/a1
  261.     rts
  262.  
  263. ;Here begins the system interface commands.  When the user calls OpenDevice/
  264. ;CloseDevice/RemDevice, this eventually gets translated into a call to the
  265. ;following routines (Open/Close/Expunge).  Exec has already put our device
  266. ;pointer in a6 for us.
  267. ;
  268. ;Open sets the IO_ERROR field on an error. If it was successful, we should
  269. ;also set up the IO_UNIT and LN_TYPE fields.  exec takes care of setting up
  270. ;IO_DEVICE.
  271. ;
  272. ;NOTE: We must also copy the current prefs for this unit into the user's
  273. ;extended iorequest fields.
  274. ;
  275. ; Register Usage
  276. ; ==============
  277. ; d0 -- unitnum
  278. ; d1 -- flags
  279. ; a1 -- iob
  280. ; a6 -- Device ptr
  281.  
  282. LibOpen:
  283.     addq.w    #1,LIB_OPENCNT(a6)      ;Fake an opener for duration of call
  284.     PUTDEBUG 100,<'Open: called'>
  285.     movem.l    d2/a2-a4,-(sp)
  286.     movea.l    a1,a2                   ;Save the iob
  287.     cmp.l    #MD_NUMUNITS,d0     ;See if the unit number is in range
  288.     bcc.w    Open_Range_Error    ;Unit number out of range (BHS)
  289.     move.l    d0,d2               ;Save unit number
  290.     lsl.l    #2,d0               ;See if the unit is already initialized
  291.     lea    md_Units(a6,d0.l),a4
  292.     move.l    (a4),d0
  293.     bne.b    Open_UnitOK
  294.                             ;Try to conjure up a unit
  295.     bsr.w    InitUnit            ;scratch:a3 unitnum:d2 devpoint:a6
  296.     move.l    (a4),d0             ;See if it initialized OK
  297.     beq.w    Open_Error
  298.     movea.l    d0,a3
  299.     bra.b    Open_UnitOK1
  300.  
  301. Open_UnitOK
  302.     movea.l    d0,a3        ;Unit pointer in a3
  303.     tst.b    Exclusive(a3)    ;Check for an exclusive access violation
  304.     beq.w    Open_Error
  305. Open_UnitOK1
  306.     btst    #SERB_SHARED,IO_FLAGS(a2)
  307.     seq    Exclusive(a3)
  308.     movea.l    mdu_prefs(a3),a4    ;Set the "7WIRE" flag
  309.  
  310.     bclr    #SERB_7WIRE,prefs_SERFLAGS(a4)
  311.     btst    #SERB_7WIRE,IO_SERFLAGS(a2)
  312.     beq.b    2$
  313.     bset    #SERB_7WIRE,prefs_SERFLAGS(a4)
  314.  
  315. 2$
  316.     movea.l    a2,a1    ;Copy the current internal prefs into the iorequest.
  317.     bsr    CopyPrefs
  318.     move.l    d0,IO_UNIT(a2)
  319.     addq.w    #1,LIB_OPENCNT(a6)  ;Mark us as having another opener
  320.     addq.w    #1,UNIT_OPENCNT(a3) ;Internal bookkeeping
  321.     bclr    #LIBB_DELEXP,md_Flags(a6) ;Prevent delayed expunges
  322.     moveq    #0,d0
  323.     move.b    d0,IO_ERROR(a2)
  324.     move.b    #NT_REPLYMSG,LN_TYPE(a2) ;Mark IORequest as "complete"
  325. Open_End
  326.     subq.w    #1,LIB_OPENCNT(a6) ;End of expunge protection
  327.     movem.l    (sp)+,d2/a2-a4
  328.     PUTDEBUG 100,<'Open: Finished!'>
  329.     rts
  330.  
  331. Open_Range_Error:
  332. Open_Error
  333.     moveq    #IOERR_OPENFAIL,d0
  334.     move.b    d0,IO_ERROR(a2)
  335.     move.l    d0,IO_DEVICE(a2)    ;Trash IO_DEVICE on open failure
  336.     PUTDEBUG 100,<'Open: failed'>
  337.     bra.b    Open_End
  338.  
  339. ;Copy prefs from our device struct to an IOrequest.  Enter with IORequest
  340. ;in a1 and unit pointer in a3.  All registers are preserved.
  341.  
  342. CopyPrefs
  343.     movem.l    d0/a1/a4,-(sp)
  344.     movea.l    mdu_prefs(a3),a4
  345.     lea    IO_CTLCHAR(a1),a1
  346.     move.w    #prefs_SIZE-1,d0
  347. 1$
  348.     move.b    (a4)+,(a1)+
  349.     dbra    d0,1$
  350.  
  351.     movem.l    (sp)+,d0/a1/a4
  352.     rts 
  353.  
  354. ;Copy prefs from an IOrequest to our device struct Enter with IORequest
  355. ;in a1 and unit pointer in a3.  All registers are preserved.
  356.  
  357. SetPrefs
  358.     movem.l    d0/a1/a4,-(sp)
  359.     movea.l    mdu_prefs(a3),a4
  360.     lea    IO_CTLCHAR(a1),a1
  361.     move.w    #prefs_SIZE-1,d0
  362. 1$
  363.     move.b    (a1)+,(a4)+
  364.     dbra    d0,1$
  365.  
  366.     movem.l    (sp)+,d0/a1/a4
  367.     rts 
  368.  
  369. ;There are two different things that might be returned from the Close
  370. ;routine.  If the device wishes to be unloaded, then Close must return
  371. ;the segment list (as given to Init).  Otherwise close MUST return NULL.
  372. ; ( device:a6, iob:a1 )
  373.  
  374. LibClose:
  375.     movem.l    a2-a3,-(sp)
  376.     PUTDEBUG 100,<'Close: called'>
  377.     movea.l    a1,a2
  378.     movea.l    IO_UNIT(a2),a3
  379.     moveq    #-1,d0
  380.     move.l    d0,IO_UNIT(a2)      ;We're closed...
  381.     move.l    d0,IO_DEVICE(a2)    ;Customers not welcome at this IORequest!
  382.     subq.w    #1,UNIT_OPENCNT(a3) ;See if the unit is still in use
  383.     bne.b    Close_Device
  384.     bsr    ExpungeUnit
  385.  
  386. Close_Device
  387.     moveq    #0,d0
  388.     subq.w    #1,LIB_OPENCNT(a6) ;Mark us as having one fewer openers
  389.     bne.b    Close_End     ;See if there is anyone left with us open
  390.     btst    #LIBB_DELEXP,md_Flags(a6) ;See if we have a delayed expunge pending
  391.     beq.b    Close_End
  392.     bsr    LibExpunge    ;Do the expunge
  393. Close_End
  394.     movem.l    (sp)+,a2-a3
  395.     PUTDEBUG 100,<'Close: Finished!'>
  396.     rts        ;MUST return either zero or the SegList!
  397.  
  398. ;Expunge is called by the memory allocator when the system is low on
  399. ;memory.
  400. ;
  401. ;There are two different things that might be returned from the Expunge
  402. ;routine.  If the device is no longer open then Expunge may return the
  403. ;segment list (as given to Init).  Otherwise Expunge may set the
  404. ;delayed expunge flag and return NULL.
  405. ;
  406. ;One other important note: because Expunge is called from the memory
  407. ;allocator, it may NEVER Wait() or otherwise take long time to complete.
  408. ;
  409. ; A6          - library base (scratch)
  410. ; D0-D1/A0-A1 - scratch
  411.  
  412. LibExpunge:
  413.     PUTDEBUG 100,<'Expunge: called'>
  414.     movem.l    d1/d2/a5/a6,-(sp)    ;Save ALL modified registers
  415.     movea.l    a6,a5
  416.     movea.l    md_SysLib(a5),a6
  417.     tst.w    LIB_OPENCNT(a5)    ;See if anyone has us open
  418.     beq.b    1$
  419.     bset    #LIBB_DELEXP,md_Flags(a5)    ;Set the delayed expunge flag
  420.     moveq    #0,d0
  421.     bra.b    Expunge_End
  422.  
  423. 1$
  424.     move.l    md_SegList(a5),d2 ;Store our seglist in d2
  425.     movea.l    a5,a1     ;Unlink from device list
  426.     mySYS    Remove     ;Remove first (before FreeMem)
  427.     movea.l    a5,a1     ;Devicebase
  428.     moveq    #0,d0
  429.     move.w    LIB_NEGSIZE(a5),d0
  430.     suba.l    d0,a1    ;Calculate base of functions
  431.     add.w    LIB_POSSIZE(a5),d0 ;Calculate size of functions + data area
  432.     mySYS    FreeMem
  433.     move.l    d2,d0    ;Set up our return value
  434.     
  435. Expunge_End
  436.     movem.l    (sp)+,d1/d2/a5/a6
  437.     rts
  438.  
  439. LibExtFunc:
  440.     PUTDEBUG 100,<'Null: called'>
  441.     moveq    #0,d0
  442.     rts        ;The "Null" function MUST return NULL.
  443.  
  444.  
  445. ;This is the main unit initialization routine. It allocates memory for
  446. ;the device structure, calls SetUpUnit, then calls InitTask.
  447.  
  448. ; ( d2:unit number, a3:scratch, a6:devptr )
  449.  
  450. InitUnit
  451.     PUTDEBUG 100,<'InitUnit: called'>
  452.     movem.l    d0/d1/a4/a2,-(sp)
  453.     move.l    d2,d1
  454.     mulu.w    #prefs_SIZE,d1
  455.     lea    prefs_unit0(a6),a4
  456.     adda.l    d1,a4
  457.  
  458. ;Now A4 is a ptr to the prefs for this unit
  459.  
  460.     move.l    #mdu_SIZE,d0 ;Allocate unit memory
  461.     move.l    #MEMF_PUBLIC!MEMF_CLEAR,d1
  462.     move.l    a6,-(sp)
  463.     movea.l    md_SysLib(a6),a6
  464.     mySYS    AllocMem
  465.     movea.l    (sp)+,a6
  466.     movea.l    d0,a3
  467.     tst.l    d0
  468.     bne    continitunit1
  469.  
  470. ;Couldn't init the unit (out of memory).
  471.  
  472. ReturnVoid
  473.     move.l    d2,d0    ;Unit number
  474.     lsl.l    #2,d0
  475.     clr.l    md_Units(a6,d0.l) ;Set unit table
  476.     movem.l    (sp)+,d0/d1/a4/a2
  477.     rts
  478.  
  479. BadSetup
  480.     bsr    KillTask
  481.     bra.b    ReturnVoid
  482.  
  483. continitunit1
  484.     moveq    #0,d0    ;Don't need to re-zero it
  485.     movea.l    a3,a2
  486.     lea    mdu_Init(pc),a1
  487.     move.l    a6,-(sp)
  488.     movea.l    md_SysLib(a6),a6
  489.     mySYS    InitStruct
  490.     movea.l    (sp)+,a6
  491.  
  492.     move.l    a5,-(sp)    ;Look up DACIA base address
  493.     lea    basetable(pc),a0
  494.     moveq    #0,d0
  495.     move.b    d2,d0
  496.     lsl.l    #2,d0
  497.     movea.l    0(a0,d0.w),a5 
  498.     move.l    a5,daciabase(a3)
  499.  
  500.     move.b    #$7f,IER(a5)     ;Disable DACIA interrupts
  501.  
  502.     bsr    SetUpUnit
  503.     movea.l    (sp)+,a5
  504.     tst.l    d0
  505.     bne.b    BadSetup
  506.  
  507.     bsr InitTask    ;Set up the two tasks for this unit
  508.     tst.l d0
  509.     beq.b BadSetup
  510.  
  511. ;Done with InitUnit - fill in the proper md_Unit field in the device struct
  512. ;and return.
  513.     move.l    d2,d0    ;Unit number
  514.     lsl.l    #2,d0
  515.     move.l    a3,md_Units(a6,d0.l) ;Set unit table
  516.     movem.l    (sp)+,d0/d1/a4/a2
  517.     PUTDEBUG 100,<'InitUnit: finished! End of silence.'>
  518.     rts
  519.  
  520. ;This routine does the following:
  521. ;
  522. ;1. Allocate read buffer memory
  523. ;2. Initialize all the special MyDevUnit fields (but NOT the signals -
  524. ;   they must be allocated in the task's context)
  525. ;3. Call InitDACIA [Initialize/set-up DACIA registers (for this unit).]
  526. ;4. Install an interrupt server.
  527. ;
  528. ;Returns failure code in d0 - zero if OK, -1 if out of memory, 1 if
  529. ;unable to open timer.device, 2 if invalid parm
  530. ;
  531. ;SetUpUnit(d2:unit number, a3:unit, a6:devptr)
  532. ;AND...ptr to prefs in A4
  533. ;uses d1,a0,a1,a2,a6
  534.  
  535. SetUpUnit
  536.     PUTDEBUG 100,<'SetUpUnit: called'>
  537.     movem.l    d1/a0/a1/a2,-(sp)
  538.     move.l    prefs_RBUFLEN(a4),d0
  539.     moveq    #64,d1
  540.     cmp.l    d1,d0
  541.     bhi.b    SUU
  542.     move.l    d1,d0
  543.     move.l    d0,prefs_RBUFLEN(a4)
  544. SUU
  545.     move.l    #MEMF_PUBLIC,d1
  546.     myEXEC    AllocMem
  547.     tst.l    d0
  548.     bne.b    continitunit
  549.     moveq    #-1,d0    ;Failed to allocate input buffer memory - exit.
  550.     movem.l    (sp)+,d1/a0/a1/a2
  551.     rts
  552.  
  553. ;Initialize all the special MyDevUnit fields (but NOT the signals -
  554. ;they must be allocated in the task's context)
  555.  
  556. continitunit
  557.     bsr    BufPtrSetup    ;Fill in head, tail, startbuf, and endbuf
  558.     move.l    a4,mdu_prefs(a3)
  559.     move.l    (SysBase).w,mdu_SysLib(a3) 
  560.     lea    timerport+MP_MSGLIST(a3),a0
  561.     NEWLIST    a0                  ;Init the unit's timer MsgPort's list
  562.     move.b    d2,mdu_UnitNum(a3)    ;Initialize unit number
  563.     move.l    a6,mdu_Device(a3)     ;Initialize device pointer
  564.     move.l    a3,mdu_is+IS_DATA(a3) ;Pass unit addr to interrupt server
  565.     move.b    #$FF,xstate(a3)
  566.     move.b    #$80,frstate(a3)
  567.  
  568.     lea    timername(pc),a0    ;Open the timer device.
  569.     moveq    #0,d0 ;UNIT_MICROHZ
  570.     lea    timeriorequest(a3),a1
  571.     moveq    #0,d1 ;no special flags
  572.     move.l    a6,-(sp)
  573.     movea.l    md_SysLib(a6),a6
  574.     mySYS    OpenDevice
  575.     movea.l    (sp)+,a6
  576.     tst.l    d0
  577.     bne    OpenTimerFailed
  578.  
  579. ;Initialize/set-up DACIA registers (for this unit).
  580. ;(according to the prefs pointed to by a4) 
  581.  
  582.     bsr    InitDACIA
  583.     tst.l    d0
  584.     bne    InitDACIAfailed 
  585.  
  586. ;Install an interrupt server.
  587.  
  588.     lea    mdu_is(a3),a1
  589.     moveq    #INTB_EXTER,d0    ;EXTER (level 6) interrupt (=13)
  590.     movea.l    md_SysLib(a6),a6
  591.  
  592.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  593.     move.l    a1,-(sp)
  594.     move.l    a3,-(sp)
  595.     PUTDEBUG 200,<'At AddIntServer, unit= %lx and mdu_is= %lx'>
  596.     addq.l    #8,sp
  597.     endc
  598.  
  599.     jsr    _LVOAddIntServer(a6) 
  600.     movea.l    mdu_Device(a3),a6
  601.     moveq    #0,d0 ;situation under control
  602.     movem.l    (sp)+,d1/a0/a1/a2
  603.     PUTDEBUG 100,<'SetUpUnit: Finished!'>
  604.     rts
  605.  
  606. InitDACIAfailed
  607.     moveq    #2,d0
  608.     bra.b    EndSetUpUnit
  609.  
  610. OpenTimerFailed
  611.     moveq    #1,d0
  612. EndSetUpUnit
  613.     move.l    d0,-(sp)
  614.     move.l    prefs_RBUFLEN(a4),d0
  615.     movea.l    startbuf(a3),a1
  616.     myEXEC    FreeMem
  617.     move.l    (sp)+,d0
  618.     movem.l    (sp)+,d1/a0/a1/a2
  619.     rts
  620.  
  621. ;*** end of SetUpUnit ***
  622.  
  623. ;Initialize/set-up DACIA registers (for this unit).
  624. ;(according to the prefs pointed to by a4) 
  625. ;d0.b will mirror CTR, d1.b will mirror FMR
  626. ;Returns error code in d0 - zero if successful.
  627. ;uses d1,d3,d5,a0
  628.  
  629. InitDACIA
  630.     PUTDEBUG 100,<'InitDACIA: Called.'>
  631.     movem.l    d1/d3/d5/a0,-(sp)
  632.  
  633. ;"During power-on initialization, all readable registers should be read to
  634. ; assure that the status registers are initialized."
  635.  
  636.     move.b    ISR(a5),d0
  637.     move.b    CSR(a5),d0
  638.     move.b    RDR(a5),d0
  639.  
  640.     move.b    frstate(a3),d0    ;Set DTR* and RTS* low (assert)
  641.     and.b    #$FC,d0     ;Clear bits zero and one
  642.     move.b    d0,frstate(a3)
  643.     move.b    d0,FMR(a5)
  644.  
  645.     moveq    #0,d0
  646.     bset    #6,d0    ;Always access ACR, never CDR
  647.     move.b    frstate(a3),d1
  648.   
  649.     move.l    prefs_BAUD(a4),d3 ;First, set proper baud rate.
  650.     swap    d3
  651.     tst.w    d3
  652.     bne    InvParm
  653.     swap    d3
  654.     lea    baudtable(pc),a0
  655.     moveq    #15,d5 
  656. baudloop
  657.     cmp.w    (a0)+,d3
  658.     dbeq    d5,baudloop
  659.     bne    InvParm
  660.     not.b    d5
  661.     and.b    #$0F,d5
  662.     or.b    d5,d0    
  663.  
  664.     ifne    INFO_LEVEL
  665.     clr.l    -(sp)
  666.     move.b    d0,3(sp)
  667.     PUTDEBUG 200,<'InitDACIA: Baud rate = %lx'>
  668.     addq.l    #4,sp
  669.     endc
  670.  
  671.     cmpi.b    #1,prefs_STOPBITS(a4) ;Next, set number of stop bits per character
  672.     beq.b    onestop
  673.     bset    #5,d0
  674. onestop
  675.     move.b    d0,CTR(a5)
  676.     move.b    prefs_READLEN(a4),d3 ;Set number of data bits per char
  677.     cmp.b    prefs_WRITELEN(a4),d3
  678.     bne    InvParm    ;We don't support different read & write char lengths
  679.     subq.b    #5,d3
  680.     bmi    InvParm
  681.     cmp.b    #3,d3
  682.     bhi    InvParm
  683.     lsl.b    #5,d3
  684.     or.b    d3,d1
  685.  
  686.     btst    #SEXTB_MSPON,prefs_EXTFLAGS+3(a4) ;Set parity
  687.     beq.b    EvenOdd
  688.     bset    #2,d1
  689.     btst    #SEXTB_MARK,prefs_EXTFLAGS+3(a4)
  690.     bne.b    UseMark
  691.     or.b    #24,d1    ;Use space
  692.     bra.b    NoParity
  693.  
  694. UseMark
  695.     or.b    #16,d1
  696.     bra.b    NoParity
  697.  
  698. EvenOdd
  699.     btst    #SERB_PARTY_ON,prefs_SERFLAGS(a4)
  700.     beq.b    NoParity
  701.     bset    #2,d1
  702.  
  703.     btst    #SERB_PARTY_ODD,prefs_SERFLAGS(a4)
  704.     bne.b    UseOdd
  705.     or.b    #8,d1
  706. UseOdd:
  707. NoParity
  708.     move.b    d1,frstate(a3)
  709.     move.b    d1,FMR(a5)
  710.     moveq    #0,d0
  711.     movem.l    (sp)+,d1/d3/d5/a0
  712.     PUTDEBUG 100,<'InitDACIA: Finished!'>
  713.     rts
  714.  
  715. InvParm
  716.     PUTDEBUG 100,<'InitDACIA: Invalid Parm!'>
  717.     moveq    #-1,d0
  718.     movem.l    (sp)+,d1/d3/d5/a0
  719.     rts
  720.  
  721. ;*** end of InitDACIA ***
  722.  
  723. ;(this is a subroutine for InitUnit)
  724. ;This routine sets up the two tasks (one for reading, one for writing).
  725. ;Returns zero in d0.l if an error occured else a ptr to the unit.
  726. ;
  727. ;uses d1-d4 and a0-a5
  728.  
  729. InitTask
  730.     PUTDEBUG 100,<'InitTask: called.'>
  731.     movem.l    d1-d4/a0-a5,-(sp)
  732.     lea    ReadTask_Begin(pc),a5 ;Set up the read task
  733.     lea    mdu_rstack(a3),a0
  734.     lea    mdu_rtcb(a3),a1
  735.     movea.l    a3,a2                 ;Read message port
  736.     bsr.b    InitTaskStruct
  737.  
  738.     lea    WriteTask_Begin(pc),a5 ;Set up the write task
  739.     lea    mdu_wstack(a3),a0
  740.     lea    mdu_wtcb(a3),a1
  741.     lea    mdu_wport(a3),a2
  742.     move.l    a3,TC_EXCEPTDATA(a1)
  743.     lea    breakexception(pc),a4
  744.     move.l    a4,TC_EXCEPTCODE(a1) 
  745.     bsr.b    InitTaskStruct
  746.  
  747.     move.l    a3,d0    ;Mark us as ready to go
  748.     PUTDEBUG 100,<'InitTask: ok'>
  749.  
  750. ;Return zero in d0.l if an error occured, else a ptr to the unit
  751.  
  752.     movem.l    (sp)+,d1-d4/a0-a5
  753.     rts
  754.  
  755. ;Start up the unit task.  We do a trick here --we set his message port to
  756. ;PA_IGNORE until the new task has a change to set it up.  We cannot go to
  757. ;sleep here: it would be very nasty if someone else tried to open the unit
  758. ;(exec's OpenDevice has done a Forbid() for us --we depend on this to become
  759. ;single threaded).
  760. ;
  761. ;Enter with:
  762. ;a0 - ptr to low end of stack
  763. ;a1 - ptr to tcb (task control block)
  764. ;a3 - unit pointer
  765. ;a5 - starting address of task
  766. ;a2 - ptr to a (uninitialized) message port
  767. ;
  768. ;uses a0-a3 and d0,d1
  769.  
  770. InitTaskStruct
  771.     movem.l    d0/d1/a0-a3,-(sp)
  772.     move.l    a0,TC_SPLOWER(a1)    ;Initialize the stack information
  773.     lea    MYPROCSTACKSIZE(a0),a0  ;High end of stack
  774.     move.l    a0,TC_SPUPPER(a1)
  775.     move.l    a3,-(a0)            ;Argument - unit ptr (send on stack)
  776.     move.l    a0,TC_SPREG(a1)
  777.     move.l    a1,MP_SIGTASK(a2)
  778.  
  779.     ifge    INFO_LEVEL-30
  780.     move.l    a1,-(sp)
  781.     move.l    a3,-(sp)
  782.     PUTDEBUG 100,<'InitUnit, unit= %lx, task=%lx'>
  783.     addq.l    #8,sp
  784.     endc
  785.  
  786.     lea    MP_MSGLIST(a2),a0
  787.     NEWLIST    a0          ;Init the unit's MsgPort's list
  788.     movea.l    a5,a2       ;Startup the task
  789.     lea    (-1).l,a3    ;generate address error
  790.                      ;if task ever "returns" (we RemTask() it
  791.                     ;to get rid of it...)
  792.     moveq    #0,d0
  793.     PUTDEBUG 100,<'About to add task'>
  794.     move.l    a6,-(sp)
  795.     movea.l    md_SysLib(a6),a6
  796.     mySYS    AddTask
  797.     movea.l    (sp)+,a6
  798.     movem.l    (sp)+,d0/d1/a0-a3
  799.     rts
  800.  
  801. ;Get rid of the unit's tasks.  We know this is safe because the unit has an
  802. ;open count of zero, so it is 'guaranteed' not in use.
  803. ;
  804. ;Kill the two tasks
  805. ; ( a3:unitptr, a6:deviceptr )
  806. ;
  807. ;uses a0,a1 and d0-d2
  808.  
  809. KillTask
  810.     movem.l    a0/a1/d0-d2,-(sp)
  811.     lea    mdu_rtcb(a3),a1
  812.     move.l    a6,-(sp)
  813.     movea.l    md_SysLib(a6),a6
  814.     mySYS    RemTask
  815.     movea.l    (sp)+,a6
  816.  
  817.     lea    mdu_wtcb(a3),a1
  818.     move.l    a6,-(sp)
  819.     movea.l    md_SysLib(a6),a6
  820.     mySYS    RemTask
  821.     movea.l    (sp)+,a6
  822.  
  823.     moveq    #0,d2
  824.     move.b    mdu_UnitNum(a3),d2      ;Save the unit number
  825.     bsr    FreeUnit            ;Free the unit structure
  826.     lsl.l    #2,d2
  827.     clr.l    md_Units(a6,d2.l)    ;Clear out the unit vector in the device
  828.     movem.l    (sp)+,a0/a1/d0-d2
  829.     rts
  830.  
  831. ; ( a3:unitptr, a6:deviceptr )
  832. ;uses a0,a1,d0,d1
  833.  
  834. FreeUnit
  835.     movem.l    a0/a1/d0/d1,-(sp)
  836.     movea.l    a3,a1
  837.     move.l    #mdu_SIZE,d0
  838.     move.l    a6,-(sp)
  839.     movea.l    md_SysLib(a6),a6
  840.     mySYS    FreeMem
  841.     movea.l    (sp)+,a6
  842.     movem.l    (sp)+,a0/a1/d0/d1
  843.     rts
  844.  
  845. ; ( a3:unitptr, a6:deviceptr )
  846. ;
  847. ;uses a0,a1,a5,d0-d2
  848.  
  849. ExpungeUnit
  850.     movem.l    a0/a1/a5/d0-d2,-(sp)
  851.     PUTDEBUG 100,<'ExpungeUnit: called'>
  852.  
  853.     movea.l    daciabase(a3),a5
  854.     move.b    #$7f,IER(a5)    ;shut off all interrupts
  855.     move.b    #$83,FMR(a5)    ;Deassert DTR* and RTS*
  856.  
  857.     bsr    FreeResources
  858.  
  859.     lea    mdu_rtcb(a3),a1
  860.     move.l    a6,-(sp)
  861.     movea.l    md_SysLib(a6),a6
  862.     mySYS    RemTask
  863.     movea.l    (sp)+,a6
  864.  
  865.     lea    mdu_wtcb(a3),a1
  866.     move.l    a6,-(sp)
  867.     movea.l    md_SysLib(a6),a6
  868.     mySYS    RemTask
  869.     movea.l    (sp)+,a6
  870.  
  871.     moveq    #0,d2
  872.     move.b    mdu_UnitNum(a3),d2 ;Save the unit number
  873.     bsr    FreeUnit    ;Free the unit structure.
  874.     lsl.l    #2,d2
  875.     clr.l    md_Units(a6,d2.l) ;Clear out the unit pointer in the device
  876.  
  877.     movem.l    (sp)+,a0/a1/a5/d0-d2
  878.     rts
  879.  
  880. ;This routines frees up resources specific to this driver (the other
  881. ;resources are taken care of by the skeleton).
  882. ;Be careful with this routine, so as not to pull the rug out from
  883. ;underneath the driver...
  884. ;
  885. ;If you can expunge you unit, and each unit has it's own interrupts,
  886. ;you must remember to remove its interrupt server
  887. ;
  888. ;Enter with unit ptr in a3 and device ptr in a6
  889. ;
  890. ;uses a0,a1,a4,d0,d1
  891.  
  892.  
  893. FreeResources
  894.     PUTDEBUG 100,<'FreeResources: called'>
  895.     movem.l    a0/a1/a4/d0/d1,-(sp)
  896.     lea    mdu_is(a3),a1    ;Point to interrupt structure
  897.     moveq    #INTB_EXTER,d0    ;Portia interrupt bit 13
  898.     move.l    a6,-(sp)
  899.     movea.l    md_SysLib(a6),a6
  900.     mySYS    RemIntServer    ;Now remove the interrupt server
  901.     movea.l    (sp)+,a6
  902.  
  903.     movea.l    startbuf(a3),a1    ;Free input buffer memory
  904.     movea.l    mdu_prefs(a3),a4
  905.     move.l    prefs_RBUFLEN(a4),d0
  906.     move.l    a6,-(sp)
  907.     movea.l    md_SysLib(a6),a6
  908.     mySYS    FreeMem
  909.     movea.l    (sp)+,a6
  910.  
  911.     lea    timeriorequest(a3),a1 ;Close timer device
  912.     move.l    a6,-(sp)
  913.     movea.l    md_SysLib(a6),a6
  914.     mySYS    CloseDevice
  915.     movea.l    (sp)+,a6
  916.     movem.l    (sp)+,a0/a1/a4/d0/d1
  917.     PUTDEBUG 100,<'FreeResources: finished!'>
  918.     rts
  919.  
  920.  
  921. ;BeginIO starts all incoming io.  The IO is either queued up for the
  922. ;unit task or processed immediately.
  923. ;
  924. ;BeginIO often is given the responsibility of making devices single
  925. ;threaded... so two tasks sending commands at the same time don't cause
  926. ;a problem.  Once this has been done, the command is dispatched via
  927. ;PerformIO.
  928. ;
  929. ;There are many ways to do the threading.  This example uses the
  930. ;UNITB_ACTIVE bit.  Be sure this is good enough for your device before
  931. ;using!  Any method is ok.  If immediate access can not be obtained, the
  932. ;request is queued for later processing.
  933. ;
  934. ;Some IO requests do not need single threading. These can be performed
  935. ;immediatley.
  936. ;
  937. ;IMPORTANT:
  938. ; The exec WaitIO() function uses the IORequest node type (LN_TYPE)
  939. ; as a flag.  If set to NT_MESSAGE, it assumes the request is
  940. ; still pending and will wait.  If set to NT_REPLYMSG, it assumes the
  941. ; request is finished.  It's the responsibility of the device driver
  942. ; to set the node type to NT_MESSAGE before returning to the user.
  943. ;
  944. ;Notes: This routine will look at io_command to determine which task
  945. ;to use. Break with QUEUEDBRK and Write requests go to the write
  946. ;task. Read requests (only) go to the read task. 
  947. ;Break requests without QUEUEDBRK initiate a write task exception.
  948. ;The actual break job is started, and finished, within that exception.
  949. ;At the end of the exception, the write task resumes whatever it was
  950. ;doing before the break.
  951. ;All other requests are performed immediately, i.e. within the caller's
  952. ;context.
  953. ;
  954. ;This routine uses a3 (and a0/a1/d0/d1, but those do not need to be
  955. ;preserved).
  956. ; ( iob: a1, device:a6 )
  957.  
  958. LibBeginIO
  959.     ifge    INFO_LEVEL-1
  960.     bchg.b    #1,($bfe001).l    ;Blink the power LED
  961.     endc
  962.  
  963.     ifge    INFO_LEVEL-3
  964.     clr.l    -(sp)
  965.     move.w    IO_COMMAND(a1),2(sp) ;Get entire word
  966.     PUTDEBUG 100,<'BeginIO  --  %ld'>
  967.     addq.l    #4,sp
  968.     endc
  969.  
  970.     move.l    a3,-(sp)
  971.     andi.b    #$f,IO_FLAGS(a1)
  972.     move.b    #NT_MESSAGE,LN_TYPE(a1) ;So WaitIO() is guaranteed to work
  973.     movea.l    IO_UNIT(a1),a3    ;Bookkeeping -> what unit to play with
  974.     move.w    IO_COMMAND(a1),d0
  975.  
  976. ;Do a range check & make sure bad requests are rejected
  977.  
  978.     cmp.w    #MYDEV_END,d0    ;Compare all 16 bits
  979.     bhi    BeginIO_NoCmd    ;no, reject it.  (bcc=bhs - unsigned)
  980.  
  981. ;Process all immediate commands no matter what
  982.  
  983.     move.l    #IMMEDIATES,d1
  984.     myDisable    a0    ;<-- Ick, nasty stuff, but needed here.
  985.     btst    d0,d1
  986.     bne    BeginIO_Immediate
  987.  
  988. ;See if the unit is STOPPED.  If so, queue the msg.
  989.  
  990.     btst    #MDUB_STOPPED,MDU_FLAGS(a3)
  991.     bne    BeginIO_QueueMsg
  992.  
  993. ;This is not an immediate command.  See if the device is busy.  If the device
  994. ;is not, do the command on the user schedule.  Else fire up the task.  This
  995. ;type of arbitration is essential for a device to reliably work with shared
  996. ;hardware.
  997. ;
  998. ;REMEMBER: Never Wait() on the user's schedule in BeginIO()!  The only
  999. ;exception is when the user has indicated it is ok by setting the "quick" bit.
  1000. ;
  1001. ;We need to queue the device.  mark us as needing task attention.  Clear the
  1002. ;quick flag
  1003. ;
  1004. ;Note: We handle read, write, and break requests seperately and differently.
  1005.  
  1006. BeginIO_QueueMsg
  1007.     bclr    #IOB_QUICK,IO_FLAGS(a1) ;We did NOT complete this quickly
  1008.     cmpi.w    #CMD_READ,IO_COMMAND(a1)
  1009.     bne.b    notread
  1010.  
  1011.     bset    #UNITB_INREADTASK,UNIT_FLAGS(a3)
  1012.     myEnable    a0
  1013.  
  1014.     ifge    INFO_LEVEL-250
  1015.     move.l    a1,-(sp)
  1016.     move.l    a3,-(sp)
  1017.     PUTDEBUG 100,<'PutMsg: Port=%lx Message=%lx'>
  1018.     addq.l    #8,sp
  1019.     endc
  1020.  
  1021.     movea.l    a3,a0
  1022.     move.l    a6,-(sp)
  1023.     movea.l    md_SysLib(a6),a6
  1024.     mySYS    PutMsg    ;Port=a0, Message=a1
  1025.     movea.l    (sp)+,a6
  1026.     bra    BeginIO_End    ;Return to caller before completing
  1027.  
  1028.  
  1029. notread
  1030.     cmpi.w    #CMD_WRITE,IO_COMMAND(a1)
  1031.     bne.b    handlebreak
  1032.  
  1033. queuewrt
  1034.     bset    #UNITB_INWRITETASK,UNIT_FLAGS(a3)
  1035.     myEnable    a0
  1036.     lea    mdu_wport(a3),a0
  1037.  
  1038.  
  1039.     ifge    INFO_LEVEL-250
  1040.     move.l    a1,-(sp)
  1041.     move.l    a0,-(sp)
  1042.     PUTDEBUG 100,<'PutMsg: Port=%lx Message=%lx'>
  1043.     addq.l    #8,sp
  1044.     endc
  1045.  
  1046.     move.l    a6,-(sp)
  1047.     movea.l    md_SysLib(a6),a6
  1048.     mySYS    PutMsg    ;Port=a0, Message=a1
  1049.     movea.l    (sp)+,a6
  1050.     bra    BeginIO_End    ;Return to caller before completing
  1051.  
  1052. handlebreak
  1053.     btst    #SERB_QUEUEDBRK,IO_SERFLAGS(a1)
  1054.     bne.b    queuewrt    ;Handle just like a write request
  1055.  
  1056. ;This is the tricky case. We initiate the break immediately.  To do this we
  1057. ;cleverly (?) use the under-documented power of task exceptions.
  1058.  
  1059.     btst    #UNITB_INBREAK,UNIT_FLAGS(a3)
  1060.     bne    breakout
  1061.     bset    #UNITB_BREAKACTIVE,UNIT_FLAGS(a3)
  1062.     myForbid
  1063.     bset    #ioflagsB_Active,IO_FLAGS(a1)
  1064.     move.l    a1,breakiorequest(a3)
  1065.     myPermit
  1066.     move.l    breaksig(a3),d0
  1067.     lea    mdu_wtcb(a3),a1
  1068.     myEXEC    Signal
  1069.     myEnable    a0
  1070.     bra.b    BeginIO_End 
  1071.  
  1072. ;Do it on the schedule of the calling process
  1073.  
  1074. BeginIO_Immediate
  1075.     myEnable    a0
  1076.     bsr    PerformIO
  1077.  
  1078. BeginIO_End
  1079.     PUTDEBUG 100,<'BeginIO_End'>
  1080.     movea.l    (sp)+,a3
  1081.     rts
  1082.  
  1083. BeginIO_NoCmd
  1084.     PUTDEBUG 100,<'BeginIO_NoCmd!'>
  1085.     move.b    #IOERR_NOCMD,IO_ERROR(a1)
  1086.     bra.b    BeginIO_End
  1087.  
  1088. breakout
  1089.     myEnable    a0
  1090.     bsr    TermIO
  1091.     bra    BeginIO_End
  1092.  
  1093. ;PerformIO actually dispatches an io request.  It might be called from the
  1094. ;task, or directly from BeginIO (thus on the callers's schedule)
  1095. ;
  1096. ;It expects a3 to already have the unit pointer in it.  a6 has the device
  1097. ;pointer (as always).  a1 has the io request.  Bounds checking has already
  1098. ;been done on the I/O Request.
  1099. ;
  1100. ;This routine itself uses d0,a0,a4,a5. The command it calls may choose
  1101. ;to use any or all registers.
  1102. ; ( iob:a1, unitptr:a3, devptr:a6 )
  1103.  
  1104. PerformIO
  1105.     ifge    INFO_LEVEL-150
  1106.     clr.l    -(sp)
  1107.     move.w    IO_COMMAND(a1),2(sp)  ;Get entire word
  1108.     PUTDEBUG 100,<'PerformIO -- %ld'>
  1109.     addq.l    #4,sp
  1110.     endc
  1111.  
  1112.     movem.l    d0/a0/a4/a5,-(sp)
  1113.     movea.l    mdu_prefs(a3),a4
  1114.     movea.l    daciabase(a3),a5
  1115.     moveq    #0,d0
  1116.     move.b    d0,IO_ERROR(a1)     ; No error so far
  1117.     move.b    IO_COMMAND+1(a1),d0 ;Look only at low byte
  1118.     lsl.w    #2,d0                ; Multiply by 4 to get table offset
  1119.     lea    cmdtable(pc),a0
  1120.     movea.l    0(a0,d0.w),a0
  1121.     move.l  a0,d0
  1122.     cmpi.l  #$ffffffff,d0
  1123.     bne     ImmCont
  1124.     PUTDEBUG 200,<'PerformIO_NoCmd!'>
  1125.     move.b    #IOERR_NOCMD,IO_ERROR(a1)
  1126.     movem.l    (sp)+,d0/a0/a4/a5
  1127.     rts 
  1128.  
  1129.  
  1130. ImmCont
  1131.     movem.l    d0-d7/a0-a6,-(sp)
  1132.     jsr    (a0)    ;iob:a1  unit:a3  devprt:a6
  1133.     movem.l    (sp)+,d0-d7/a0-a6
  1134.     bsr.b    TermIO
  1135.     movem.l    (sp)+,d0/a0/a4/a5
  1136.     PUTDEBUG 100,<'PerformIO -- Finished!'>
  1137.     rts
  1138.  
  1139.  
  1140.  
  1141. ;PerformIO
  1142. ;    ifge    INFO_LEVEL-150
  1143. ;    clr.l    -(sp)
  1144. ;    move.w    IO_COMMAND(a1),2(sp)  ;Get entire word
  1145. ;    PUTDEBUG 150,<'PerformIO -- %ld'>
  1146. ;    addq.l    #4,sp
  1147. ;    endc
  1148.  
  1149. ;    movem.l    d0/a0/a4/a5,-(sp)
  1150. ;    movea.l    mdu_prefs(a3),a4
  1151. ;    movea.l    daciabase(a3),a5
  1152. ;    moveq    #0,d0
  1153. ;    move.b    d0,IO_ERROR(a1)     ; No error so far
  1154. ;    move.b    IO_COMMAND+1(a1),d0 ;Look only at low byte
  1155. ;    lsl.w    #2,d0            ; Multiply by 4 to get table offset
  1156. ;    lea    cmdtable(pc),a0
  1157. ;    movea.l    0(a0,d0.w),a0
  1158.  
  1159. ;    movem.l    d0-d7/a0-a6,-(sp)
  1160. ;    jsr    (a0)            ;iob:a1  unit:a3  devprt:a6
  1161. ;    movem.l    (sp)+,d0-d7/a0-a6
  1162. ;    bsr.b    TermIO
  1163. ;    movem.l    (sp)+,d0/a0/a4/a5
  1164. ;    PUTDEBUG 15,<'PerformIO -- Finished!'>
  1165. ;    rts
  1166.  
  1167.  
  1168. ;TermIO sends the IO request back to the user.  It knows not to mark
  1169. ;the device as inactive if this was an immediate request or if the
  1170. ;request was started from the server task.
  1171. ;
  1172. ; ( iob:a1, unitptr:a3 )
  1173. ;uses d0/d1/a0/a1
  1174.  
  1175. TermIO
  1176.     movem.l    d0/d1/a0/a1,-(sp)
  1177.     PUTDEBUG 100,<'TermIO'>
  1178.     move.w    IO_COMMAND(a1),d0
  1179.     move.l    #IMMEDIATES,d1
  1180.     btst    d0,d1
  1181.     bne.b    TermIO_Immediate    ;IO was immediate, don't do task stuff...
  1182.  
  1183.     cmpi.w    #CMD_READ,IO_COMMAND(a1)
  1184.     bne.b    wrtterm
  1185.  
  1186. ;We may need to turn the active bit off.
  1187.  
  1188.     btst    #UNITB_INREADTASK,UNIT_FLAGS(a3)
  1189.     bne.b    TermIO_Immediate    ;IO came from task, don't clear ACTIVE...
  1190.  
  1191. ;The task does not have more work to do
  1192.  
  1193.     bclr    #UNITB_READACTIVE,UNIT_FLAGS(a3)
  1194.     bra.b    TermIO_Immediate
  1195.  
  1196. ;We may need to turn the active bit off.
  1197.  
  1198. wrtterm
  1199.     btst    #UNITB_INWRITETASK,UNIT_FLAGS(a3)
  1200.     bne.b    TermIO_Immediate    ;IO came from task, don't clear ACTIVE...
  1201.  
  1202. ;The task does not have more work to do
  1203.  
  1204.     bclr    #UNITB_WRITEACTIVE,UNIT_FLAGS(a3)
  1205.  
  1206.  
  1207. ;If the quick bit is still set then we don't need to reply
  1208. ;- msg - just return to the user.
  1209.  
  1210. TermIO_Immediate
  1211.     btst    #IOB_QUICK,IO_FLAGS(a1)
  1212.     bne.b    TermIO_End
  1213.     myEXEC    ReplyMsg    ;a1-message
  1214.                     ;ReplyMsg sets the LN_TYPE to NT_REPLYMSG
  1215. TermIO_End
  1216.     movem.l    (sp)+,d0/d1/a0/a1
  1217.     rts
  1218.  
  1219. ;Here begins the functions that implement the device commands
  1220. ;all functions are called with:
  1221. ;  a1 -- a pointer to the io request block
  1222. ;  a3 -- a pointer to the unit
  1223. ;  a4 -- a pointer to prefs
  1224. ;  a5 -- a pointer to the unit hardware
  1225. ;  a6 -- a pointer to the device
  1226. ;
  1227. ;Commands that conflict with 68000 instructions have a "My" prepended to them.
  1228.  
  1229. ;Read: The handshaking lines don't serve any purpose when reading (except
  1230. ;perhaps to say "shut up" if an exceptional condition occurs).
  1231. ;
  1232. ;d5 is used to count the number of bytes transferred
  1233.  
  1234. Read
  1235.     moveq    #0,d5
  1236.     move.l    IO_LENGTH(a1),d6
  1237.     movea.l    IO_DATA(a1),a2
  1238.     move.l    readsig(a3),d4
  1239.     add.l    readabortsig(a3),d4
  1240.  
  1241.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  1242.     move.l    d6,-(sp)
  1243.     PUTDEBUG 100,<'Read entered -- %ld bytes requested.'>
  1244.     addq.l    #4,sp
  1245.     endc
  1246.  
  1247.     bra.b    ReadEntry
  1248.  
  1249. readloop
  1250.     move.l    d4,d0
  1251.     myEXEC    Wait    ;Wait for one or more bytes to come in
  1252.     and.l    readabortsig(a3),d0
  1253.     bne    readabort
  1254. NoErrorAtAll
  1255.     PUTDEBUG 100,<'Read: One or more bytes came in.'>
  1256.  
  1257. ReadEntry
  1258.     bsr    GetBytesInReadBuf
  1259.  
  1260.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  1261.     move.l    d0,-(sp)
  1262.     PUTDEBUG 100,<'Read: In fact, %ld bytes came in.'>
  1263.     addq.l    #4,sp
  1264.     endc
  1265.  
  1266.     tst.l    d0
  1267.     beq    readloop
  1268.     cmp.l    d0,d6
  1269.     bls.b    AllDone     ;Branch if d6 <= d0
  1270.     sub.l    d0,d6
  1271.     bsr    DumpReadBuf    ;Get all the bytes we can
  1272.     beq    readloop  
  1273.     bra.b    endread     ;Go if TermArray caused early exit
  1274.  
  1275. ;The number of bytes in the read buffer equals or exceeds the number of
  1276. ;bytes the user wants.
  1277.  
  1278. AllDone
  1279.     PUTDEBUG 100,<'Read: AllDone'>
  1280.     move.l    d6,d0
  1281.     bsr    DumpReadBuf    ;Dump d0 bytes of the read buffer into the user's buffer
  1282. endread
  1283.     PUTDEBUG 100,<'Read: Finished!'>
  1284.     bclr    #MDUB_V,MDU_FLAGS(a3)
  1285.     beq.b    NoOverflow
  1286.     move.b    #SerErr_BufOverflow,IO_ERROR(a1)
  1287. NoOverflow
  1288.     move.l    d5,IO_ACTUAL(a1)
  1289.     rts        ;Done with read
  1290.  
  1291. ;Something exceptional happened.  An informative error code should be
  1292. ;returned.  first, check for error conditions...  Note that the serial.device
  1293. ;standard does not provide a way to inform the caller of simultaneous error
  1294. ;conditions.
  1295.  
  1296. readabort
  1297.     PUTDEBUG 100,<'readabort: Something exceptional happened.'>
  1298.     myDisable
  1299.     move.b    ISRcopy(a3),d2
  1300.     move.b    CSRcopy(a3),d3
  1301.     myEnable
  1302.     btst    #ISRB_PAR,d2
  1303.     beq.b    notpar
  1304.  
  1305.     move.b    #SerErr_ParityErr,IO_ERROR(a1) ;parity error
  1306.     bra    endread
  1307.  
  1308. notpar
  1309.     btst    #1,d2    ;Check for frame err, overrun, & break
  1310.     beq    endread    ;We infer that an abort has been issued
  1311.  
  1312.     btst    #CSRB_FE,d3    ;Probe further...
  1313.     beq.b    noframe
  1314.  
  1315.     move.b    #SerErr_LineErr,IO_ERROR(a1) ;Framing Error
  1316.     bra    endread
  1317.  
  1318. noframe
  1319.     btst    #CSRB_RBRK,d3
  1320.     beq    NoErrorAtAll
  1321.  
  1322. ;Note that we ignore receive overrun errors. Since there is no error
  1323. ;code for it, I assume this is what serial.device does too.
  1324.  
  1325.     move.b    #SerErr_DetectedBreak,IO_ERROR(a1) ;Break
  1326.     bra    endread 
  1327.  
  1328. ;d5 is used to count the number of bytes transferred
  1329.  
  1330. Write
  1331.     moveq    #0,d5
  1332.     move.l    IO_LENGTH(a1),d6
  1333.  
  1334.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  1335.     move.l    d6,-(sp)
  1336.     PUTDEBUG 100,<'Write entered -- %ld bytes requested.'>
  1337.     addq.l    #4,sp
  1338.     endc
  1339.  
  1340.     movea.l    IO_DATA(a1),a2
  1341.     move.l    tdresig(a3),d4
  1342.     add.l    writeabortsig(a3),d4
  1343.     btst    #SERB_7WIRE,prefs_SERFLAGS(a4)
  1344.     bne.b    write.hand
  1345.    
  1346. ;Safety check: if CTS* is not asserted, return with an error code. This
  1347. ;usually occurs when the port is not connected to anything.
  1348. ;Note: This is just a hack - something more robust will be done later
  1349. ;(hopefully).
  1350.  
  1351. ;Enter with the number of bytes to transmit in d6
  1352. ;Enter with a pointer to the user's data in a2
  1353.  
  1354. write.nohand
  1355.     btst    #CSRB_CTSL,CSR(a5)
  1356.     bne.b    not_connected
  1357.  
  1358.     bsr.b    transmit
  1359.     subq.l    #1,d6
  1360.     bne.b    write.nohand 
  1361. endwrite
  1362.     move.l    d5,IO_ACTUAL(a1)
  1363.     rts
  1364.  
  1365. not_connected:
  1366.     move.b    #SerErr_LineErr,IO_ERROR(a1)
  1367.     bra.b    endwrite
  1368.  
  1369. ;Enter with the number of bytes to transmit in d6
  1370. ;Enter with a pointer to the user's data in a2
  1371.  
  1372. ;The handshaking protocol implemented here is based on the flowchart
  1373. ;on page 5-66 of "An Introduction to Microcomputers" by Adam Osborne.
  1374.  
  1375. write.hand:
  1376. write.hand.loop
  1377.     btst    #CSRB_DSRL,CSR(a5)    ;Test DSR*
  1378.     beq.b    writehandcont        ;If low, proceed
  1379.     move.l    dsrsig(a3),d0
  1380.     add.l    writeabortsig(a3),d0
  1381.     myEXEC    Wait
  1382.     and.l    writeabortsig(a3),d0
  1383.     bne.b    aborthand
  1384.     bra.b    write.hand.loop
  1385.  
  1386. ;The 65C52 halts any transmission until CTS* is asserted, so no code
  1387. ;is involved. This can also be a curse if you don't desire handshaking.
  1388.  
  1389. writehandcont
  1390.     bsr.b    transmit    ;Transmit a byte
  1391.     subq.l    #1,d6
  1392.     bne.b    write.hand.loop
  1393. aborthand
  1394.     bra.b    endwrite
  1395.  
  1396. ;*** Subroutine for the write routines ***
  1397. ;
  1398. ;Returns 1 in d6 if aborted.
  1399.  
  1400. transmit
  1401.     btst    #ISRB_TDRE,ISR(a5) ;test TDRE
  1402.     bne    oktosend    ;If set, we can load up the transmit reg immediately
  1403.     PUTDEBUG 100,<'Transmit: Entered.'>
  1404.     ori.b    #WRITEINTMASK,IERstate(a3) 
  1405.     move.b    #WRITEINT,IER(a5)
  1406.     move.l    d4,d0
  1407.     myEXEC    Wait    ;Wait for TDRE to be set
  1408.     and.l    writeabortsig(a3),d0
  1409.     bne    aborttransmit
  1410.     PUTDEBUG 100,<'Transmit: TDRE signal received.'>
  1411.     bra    transmit    ;Just to be sure
  1412.  
  1413. oktosend
  1414.     btst    #SERB_XDISABLED,prefs_SERFLAGS(a4) ;Handle xoff, if requested
  1415.     bne.b doit
  1416. txs
  1417.     tst.b xstate(a3)
  1418.     bne.b doit
  1419.  
  1420.     PUTDEBUG 100,<'Transmit: Waiting for XON!'>
  1421.     move.l xonsig(a3),d0
  1422.     add.l writeabortsig(a3),d0
  1423.     myEXEC    Wait    ;Wait for an x-on signal before sending
  1424.     and.l writeabortsig(a3),d0
  1425.     bne.b aborttransmit
  1426.     bra.b txs
  1427.  
  1428. doit
  1429.     PUTDEBUG 100,<'Transmit: Received XON!'>
  1430.     tst.l    d6
  1431.     bmi.b    termzero
  1432. doit1
  1433.     move.b    (a2)+,TDR(a5)
  1434.     addq.l    #1,d5
  1435.     rts
  1436.  
  1437. termzero
  1438.     tst.b    (a2)
  1439.     bne.b    doit1
  1440. aborttransmit
  1441.     moveq    #1,d6
  1442.     rts
  1443.  
  1444. ;*** end of write routines ***
  1445.  
  1446. ;*** Subroutines for the read routine ***
  1447. ;
  1448. ;Return with the number of bytes in the read buffer in d0
  1449.  
  1450. GetBytesInReadBuf
  1451.     move.l    d1,-(sp)
  1452.     myDisable
  1453.     move.l    head(a3),d1
  1454.     move.l    tail(a3),d0
  1455.     sub.l    d1,d0
  1456.     bcc.b    ok.getbytes
  1457.     add.l    prefs_RBUFLEN(a4),d0
  1458. ok.getbytes
  1459.     myEnable
  1460.     move.l    (sp)+,d1
  1461.     rts
  1462.  
  1463.  
  1464. ;Enter with number of bytes to read in d0
  1465. ;Enter with a pointer to a dump buffer in a2
  1466. ;the pointer in a2 is updated to reflect the current position
  1467. ;
  1468. ;This routine uses as scratch: a0,a6,d0,d3,d6,d7
  1469. ;and updates the following: d5,a2
  1470. ;Returns with zero flag set if all is OK, or zero cleared if a TermArray
  1471. ;match was found.
  1472.  
  1473. DumpReadBuf
  1474.     myDisable
  1475.     movea.l    head(a3),a0
  1476.     move.l    a0,-(sp)
  1477.     adda.l    d0,a0
  1478.     cmpa.l    endbuf(a3),a0
  1479.     bls.b    notend.drb
  1480.     suba.l    prefs_RBUFLEN(a4),a0
  1481. notend.drb
  1482.     move.l    a0,head(a3)
  1483.     myEnable
  1484.     movea.l    (sp)+,a0
  1485.  
  1486. ;Note that only the buffer pointers are protected. The main copy loop
  1487. ;(below) could, however, return somewhat incoherent data if the buffer
  1488. ;happens to overflow.
  1489.  
  1490.     btst    #SERB_EOFMODE,IO_SERFLAGS(a1)
  1491.     bne    eofdump 
  1492.  
  1493. drb.loop
  1494.     move.b    (a0)+,d6
  1495.     bsr.b    xcode
  1496.     move.b    d6,(a2)+
  1497.     addq.l    #1,d5
  1498.     cmpa.l    endbuf(a3),a0
  1499.     bls.b    notend.drb2
  1500.     movea.l    startbuf(a3),a0
  1501. notend.drb2
  1502.     subq.l    #1,d0
  1503.     bne.b    drb.loop 
  1504.     rts
  1505.  
  1506.  
  1507. ;Check for xon/xoff
  1508.  
  1509. xcode
  1510.     ifne    INFO_LEVEL
  1511.     move.l    prefs_CTLCHAR(a4),-(sp)
  1512.     PUTDEBUG 100,<'XCODE: prefs_CTLCHAR = %lx'>
  1513.     addq.l    #4,sp
  1514.     endc
  1515.  
  1516.     ifne    INFO_LEVEL
  1517.     clr.l    -(sp)
  1518.     move.b    d6,3(sp)
  1519.     PUTDEBUG 100,<'XCODE: Current char = %lx'>
  1520.     addq.l    #4,sp
  1521.     endc
  1522.  
  1523.     cmp.b    prefs_CTLCHAR(a4),d6    ;Xon check
  1524.     beq.b    setxon
  1525.     cmp.b    prefs_CTLCHAR+1(a4),d6    ;Xoff check
  1526.     beq.b    setxoff
  1527.     rts
  1528.  
  1529. setxon
  1530.     PUTDEBUG 100,<'XCODE: XON!'>
  1531.     tst.b    xstate(a3)
  1532.     bne.b    sxoq    ;If already on, don't signal!
  1533.     st    xstate(a3)
  1534.     movem.l    d0/d1/a0/a1/a6,-(sp)
  1535.     move.l    xonsig(a3),d0
  1536.     lea    mdu_wtcb(a3),a1
  1537.     movea.l    (SysBase).w,a6
  1538.     jsr    _LVOSignal(a6)
  1539.     movem.l    (sp)+,d0/d1/a0/a1/a6
  1540. sxoq
  1541.     rts
  1542.  
  1543. setxoff
  1544.     PUTDEBUG 100,<'XCODE: XOFF!'>
  1545.     clr.b    xstate(a3)
  1546.     rts
  1547.  
  1548. eofdump:
  1549. eofdumploop:
  1550.     moveq    #7,d7
  1551.     lea    prefs_TERMARRAY(a4),a6
  1552.     move.b    (a0)+,d6
  1553.     bsr    xcode
  1554. cmploop
  1555.     cmp.b    (a6)+,d6
  1556.     dbcc    d7,cmploop
  1557.     beq.b    termread    
  1558.     move.b    d6,(a2)+
  1559.     addq.l    #1,d5
  1560.     cmpa.l    endbuf(a3),a0
  1561.     bls.b    notend.drb1
  1562.     movea.l    startbuf(a3),a0
  1563. notend.drb1:   
  1564.     subq.l    #1,d0
  1565.     bne.b    eofdumploop 
  1566.     rts
  1567.  
  1568. termread
  1569.     moveq    #-1,d0
  1570.     rts
  1571.  
  1572. ;This routine handles queued breaks. Non-queued breaks are handled by an
  1573. ;exception (which uses similar but not identical code).
  1574.  
  1575. Break
  1576.     PUTDEBUG 100,<'Break: called'>
  1577.     bset    #UNITB_INBREAK,UNIT_FLAGS(a3)
  1578.     move.b    #2,ACR(a5) ;start break
  1579.     lea    timeriorequest(a3),a1
  1580.     move.w    #TR_ADDREQUEST,IO_COMMAND(a1)
  1581.     clr.l    TV_SECS(a1)
  1582.     move.l    prefs_BRKTIME(a4),d0
  1583.     ori.b    #$FF,d0    ;To avoid the V33/V34 bug
  1584.  
  1585.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  1586.     move.l    d0,-(sp)
  1587.     PUTDEBUG 100,<'Break: TV_MICRO=%ld'>
  1588.     addq.l    #4,sp
  1589.     endc
  1590.  
  1591.     move.l    d0,TV_MICRO(a1)
  1592.     movea.l    MN_REPLYPORT(a1),a0
  1593.     move.b    MP_SIGBIT(a0),d2
  1594.     myEXEC    SendIO
  1595.     moveq    #0,d0
  1596.     bset    d2,d0
  1597.     add.l    writeabortsig(a3),d0
  1598.  
  1599.     PUTDEBUG 100,<'Break: Waiting...'>
  1600.  
  1601.     myEXEC    Wait
  1602.     and.l    writeabortsig(a3),d0
  1603.     beq.b    breakOK1
  1604.  
  1605.     PUTDEBUG 100,<'Break: Aborted!'>
  1606.  
  1607.     myEXEC    AbortIO    ;The break was aborted. Clean up.
  1608.     myEXEC    WaitIO 
  1609.  
  1610. breakOK1
  1611.     move.b    #0,ACR(a5) ;stop the break
  1612.     bclr    #UNITB_INBREAK,UNIT_FLAGS(a3)
  1613.  
  1614.     PUTDEBUG 100,<'Break: Finished!'>
  1615.     rts
  1616.  
  1617. ;AbortIO() is a REQUEST to "hurry up" processing of an IORequest.
  1618. ;If the IORequest was already complete, nothing happens (if an IORequest
  1619. ;is quick or LN_TYPE=NT_REPLYMSG, the IORequest is complete).
  1620. ;The message must be replied with ReplyMsg(), as normal.
  1621. ;
  1622. ;Note that AbortIO is called directly, not via BeginIO/PerformIO.
  1623. ;The only other direct functions are Open, Close, Expunge, and of course
  1624. ;BeginIO.
  1625. ;
  1626. ; ( iob: a1, device:a6 )
  1627. ;returns an error code in d0 - zero if successful.
  1628. ;If sucessful, AbortIO returns IOERR_ABORTED in IO_ERROR and sets bit
  1629. ;5 of IO_FLAGS.
  1630. ;
  1631. ;This routine uses d0/d1/a0, but they do not need to be saved.
  1632.  
  1633. LibAbortIO
  1634.     PUTDEBUG 100,<'AbortIO: called'>
  1635.     myForbid
  1636.     move.b    #IOERR_ABORTED,IO_ERROR(a1) ;We always say we succeed(ed)
  1637.     bset    #5,IO_FLAGS(a1)
  1638.     cmpi.b    #NT_REPLYMSG,LN_TYPE(a1)    ;Already complete?
  1639.     beq.b    complete
  1640.  
  1641. ;Check to see whether or not the IORequest is being processed 
  1642.  
  1643.     btst    #ioflagsB_Active,IO_FLAGS(a1)
  1644.     bne.b    inprogress
  1645.     bset    #ioflagsB_Ignore,IO_FLAGS(a1)
  1646.  
  1647. complete
  1648.     myPermit
  1649.     moveq    #0,d0
  1650.     PUTDEBUG 100,<'AbortIO: Finished!'>
  1651.     rts
  1652.  
  1653. inprogress
  1654.     movea.l    IO_UNIT(a1),a3    ;IO is in progress - abort it.
  1655.     cmpi.w    #CMD_READ,IO_COMMAND(a1)
  1656.     bne    ip1
  1657.     move.l    readabortsig(a3),d0
  1658.     lea    mdu_rtcb(a3),a1
  1659. ip0
  1660.     myEXEC    Signal
  1661.     bra.b    complete
  1662.  
  1663. ip1
  1664.     cmpi.w    #CMD_WRITE,IO_COMMAND(a1)
  1665.     bne.b    ip2
  1666. ip3
  1667.     move.l    writeabortsig(a3),d0
  1668.     lea    mdu_wtcb(a3),a1
  1669.     bra.b    ip0
  1670.  
  1671. ;The break command is handled here.
  1672. ;We use the same abort signal (as write), so handle just as with write.
  1673.  
  1674. ip2
  1675.     bra.b ip3
  1676.  
  1677. Invalid
  1678.     move.b  #IOERR_NOCMD,IO_ERROR(a1)
  1679.     rts
  1680.  
  1681. ;Clear invalidates all internal buffers.
  1682. ;
  1683. ; a1 -- a pointer to the io request block
  1684. ; a3 -- a pointer to the unit
  1685. ; a4 -- a pointer to prefs
  1686. ; a5 -- a pointer to the unit hardware
  1687. ; a6 -- a pointer to the device
  1688.  
  1689. MyClear
  1690.     myDisable
  1691.     move.l    startbuf(a3),d0
  1692.     move.l    d0,head(a3)
  1693.     move.l    d0,tail(a3)
  1694.     myEnable
  1695.     rts
  1696.  
  1697. ; a1 -- a pointer to the io request block
  1698. ; a3 -- a pointer to the unit
  1699. ; a4 -- a pointer to prefs
  1700. ; a5 -- a pointer to the unit hardware
  1701. ; a6 -- a pointer to the device
  1702.  
  1703. MyReset
  1704.     PUTDEBUG 100,<'MyReset: called'>
  1705.     myForbid
  1706.     move.b    IERstate(a3),d7
  1707.     clr.b    IERstate(a3)
  1708.     move.b    #$7f,IER(a5)    ;Disable ACIA interrupts
  1709.     bsr    Flush       ;Flush pending requests
  1710.  
  1711. ;Abort current IO, if any IO is indeed occuring
  1712.  
  1713.     move.l    a1,-(sp)
  1714.     btst    #UNITB_BREAKACTIVE,UNIT_FLAGS(a3)
  1715.     beq    NoBreakActive
  1716.     movea.l    breakiorequest(a3),a1
  1717.     bsr    LibAbortIO
  1718.  
  1719. NoBreakActive
  1720.     btst    #UNITB_WRITEACTIVE,UNIT_FLAGS(a3)
  1721.     beq    WriteNotActive
  1722.     movea.l    WriteRequestPtr(a3),a1
  1723.     bsr    LibAbortIO
  1724.  
  1725. WriteNotActive
  1726.     btst    #UNITB_READACTIVE,UNIT_FLAGS(a3)
  1727.     beq    NothingActive
  1728.     movea.l    ReadRequestPtr(a3),a1
  1729.     bsr    LibAbortIO
  1730.  
  1731. NothingActive
  1732.     movea.l    (sp)+,a1 
  1733.     bsr    SetDefaultPrefs
  1734.     bsr    CopyPrefs  
  1735.     bsr    FreeResources
  1736.     bsr    SetUpUnit
  1737.  
  1738.     tst.l    d0          ;Check for a possible error condition
  1739.     bmi.b    OutOfMem
  1740.     subq.l    #1,d0
  1741.     beq.b    TimerError
  1742.     subq.l    #1,d0
  1743.     beq.b    ParamError
  1744.  
  1745.     move.b    d7,IERstate(a3)    ;Enable DACIA interrupts again
  1746.     bset    #7,d7
  1747.     move.b    d7,IER(a5)
  1748.     myPermit
  1749.     clr.l    IO_ACTUAL(a1)
  1750.     PUTDEBUG 100,<'MyReset: Finished!'>
  1751.     rts
  1752.  
  1753. ParamError
  1754.     move.b    #SerErr_InvParam,IO_ERROR(a1)
  1755.     bra.b    MyResetFailed
  1756.  
  1757. TimerError
  1758.     move.b    #SerErr_TimerErr,IO_ERROR(a1)
  1759.     bra.b    MyResetFailed
  1760.  
  1761. OutOfMem
  1762.     move.b    #SerErr_BufErr,IO_ERROR(a1)
  1763. MyResetFailed
  1764.     myPermit
  1765.     clr.l    IO_ACTUAL(a1)
  1766.     PUTDEBUG 100,<'MyReset: Error!'>
  1767.     rts
  1768.  
  1769. ; a1 -- a pointer to the io request block
  1770. ; a3 -- a pointer to the unit
  1771. ; a4 -- a pointer to prefs
  1772. ; a5 -- a pointer to the unit hardware
  1773. ; a6 -- a pointer to the device
  1774. ;
  1775. ;Return number of chars in buffer in IO_ACTUAL
  1776. ;Fill in IO_STATUS
  1777.  
  1778. Query
  1779.     PUTDEBUG 100,<'Query: called.'>
  1780.     bsr    GetBytesInReadBuf
  1781.     move.l    d0,IO_ACTUAL(a1)
  1782.  
  1783.     ifne    INFO_LEVEL  ;If any debugging enabled at all
  1784.     move.l    d0,-(sp)
  1785.     PUTDEBUG 100,<'Query: %ld bytes in buf.'>
  1786.     move.l    (sp)+,d0
  1787.     endc
  1788.  
  1789.     moveq    #0,d0 ;d0 will mirror IO_STATUS
  1790.     move.b    CSR(a5),d1
  1791.     btst    #0,d1
  1792.     beq.b    Q1
  1793.     bset    #6,d0
  1794. Q1
  1795.     btst    #1,d0
  1796.     beq.b    Q2
  1797.     bset    #7,d0
  1798. Q2
  1799.     btst    #3,d1
  1800.     beq.b    Q3
  1801.     bset    #3,d0
  1802. Q3
  1803.     btst    #4,d1
  1804.     beq.b    Q4
  1805.     bset    #5,d0
  1806. Q4
  1807.     btst    #5,d1
  1808.     beq.b    Q5
  1809.     bset    #4,d0
  1810. Q5
  1811.     btst    #UNITB_BREAKACTIVE,UNIT_FLAGS(a3)
  1812.     beq.b    NB
  1813.     bset    #9,d0
  1814. NB
  1815.     btst    #UNITB_INBREAK,UNIT_FLAGS(a3)
  1816.     beq.b    NB1
  1817.     bset    #9,d0
  1818. NB1
  1819.     btst    #2,d1
  1820.     beq.b    NRB
  1821.     bset    #10,d0
  1822. NRB
  1823.     tst.b    xstate(a3)
  1824.     bne.b    xIsOn
  1825.     bset    #11,d0
  1826. xIsOn
  1827.     move.w    d0,IO_STATUS(a1)
  1828.     rts
  1829.  
  1830. ; a1 -- a pointer to the io request block
  1831. ; a3 -- a pointer to the unit
  1832. ; a4 -- a pointer to prefs
  1833. ; a5 -- a pointer to the unit hardware
  1834. ; a6 -- a pointer to the device
  1835.  
  1836. SetParams:
  1837.     bclr    #SERB_XDISABLED,prefs_SERFLAGS(a4)
  1838.     btst    #SERB_XDISABLED,IO_SERFLAGS(a1) ;Set the XDISABLED thing
  1839.     beq.b    SetP1
  1840.     bset    #SERB_XDISABLED,prefs_SERFLAGS(a4)
  1841. SetP1:
  1842.     beq.b    SetP2
  1843.     st    xstate(a3)
  1844.  
  1845. ;Now check to see whether the device is busy, i.e. any current or pending requests.
  1846.  
  1847. SetP2
  1848.     myForbid
  1849.     move.b    UNIT_FLAGS(a3),d0
  1850.     and.b    #$3c,d0 ;anything going on at the moment?
  1851.     bne    DevBusy
  1852.     lea    $14(a3),a0    ;Read port - anything there?
  1853.     movea.l    (a0),a2
  1854.     tst.l    (a2)
  1855.     bne    DevBusy
  1856.     lea    mdu_wport+$14(a3),a0 ;Write port - anything there?
  1857.     movea.l    (a0),a2
  1858.     tst.l    (a2)
  1859.     bne    DevBusy
  1860.  
  1861. ;Ok, the device is not busy. Set all params.
  1862.  
  1863.     bsr    SetPrefs    ;First copy the data
  1864.  
  1865. ;Note that this is for compatability only; it does not speed up this driver.
  1866.  
  1867.     btst    #SERB_RAD_BOOGIE,IO_SERFLAGS(a1) ;Check for RAD_BOOGIE
  1868.     beq.b    SkipBoogie
  1869.     bclr    #SEXTB_MSPON,prefs_EXTFLAGS+3(a4)
  1870.     bclr    #SERB_PARTY_ON,prefs_SERFLAGS(a4)
  1871.     bset    #SERB_XDISABLED,prefs_SERFLAGS(a4)
  1872.     move.b    #8,prefs_READLEN(a4)
  1873.     move.b    #8,prefs_WRITELEN(a4)
  1874.  
  1875. SkipBoogie
  1876.     bsr    InitDACIA    ;Then set up the chip 
  1877.     tst.l    d0
  1878.     bne    PInvP
  1879.  
  1880. ;* Deallocate the old read buffer and allocate a new one. *
  1881.  
  1882.     myDisable
  1883.     move.l    a1,-(sp)    ;Free input buffer memory
  1884.     movea.l    startbuf(a3),a1
  1885.     movea.l    mdu_prefs(a3),a4
  1886.     move.l    prefs_RBUFLEN(a4),d0
  1887.     move.l    a6,-(sp)
  1888.     movea.l    md_SysLib(a6),a6
  1889.     mySYS    FreeMem
  1890.     movea.l    (sp)+,a6
  1891.  
  1892.     move.l    prefs_RBUFLEN(a4),d0 ;Allocate buffer mem
  1893.     moveq    #64,d1
  1894.     cmp.l    d1,d0
  1895.     bhi.b    SPmem
  1896.     move.l    d1,d0
  1897.     move.l    d0,prefs_RBUFLEN(a4)
  1898. SPmem
  1899.     move.l    #MEMF_PUBLIC,d1
  1900.     move.l    a6,-(sp)
  1901.     movea.l    md_SysLib(a6),a6
  1902.     mySYS    AllocMem
  1903.     movea.l    (sp)+,a6
  1904.     movea.l    (sp)+,a1
  1905.     tst.l    d0
  1906.     bne.b    SPMemOK
  1907.  
  1908.     move.b    #SerErr_BufErr,IO_ERROR(a1)
  1909.     moveq    #64,d0
  1910.     move.l    d0,prefs_RBUFLEN(a4)
  1911.     lea    AltBuf(a3),a0
  1912.     move.l    a0,d0
  1913. SPMemOK
  1914.     bsr.b    BufPtrSetup
  1915.     myEnable
  1916. SPLx
  1917.     myPermit
  1918.     rts
  1919.  
  1920. PInvP
  1921.     move.b    #SerErr_InvParam,IO_ERROR(a1)
  1922.     bra.b    SPLx
  1923.  
  1924. BufPtrSetup
  1925.     move.l    d0,head(a3)
  1926.     move.l    d0,tail(a3)
  1927.     move.l    d0,startbuf(a3)
  1928.     add.l    prefs_RBUFLEN(a4),d0
  1929.     subq.l    #1,d0
  1930.     move.l    d0,endbuf(a3)
  1931.     rts
  1932.  
  1933. DevBusy
  1934.     myPermit
  1935.     move.b    #SerErr_DevBusy,IO_ERROR(a1)
  1936.     rts
  1937.  
  1938.  
  1939. ; This is the code that I added to support the ASDG command SetCtrlLines.
  1940. ; This will change the DTR or the RTS lines without external software
  1941. ; playing directly with the hardware. This (seems to me) to be a better
  1942. ; idea then what you have to do on the serial.device. BBS type programs
  1943. ; need this type of support. Mike Mossman ( March 25, 1991)
  1944.  
  1945. ; a1 -- a pointer to the io request block
  1946. ; a3 -- a pointer to the unit
  1947. ; a4 -- a pointer to prefs
  1948. ; a5 -- a pointer to the unit hardware
  1949. ; a6 -- a pointer to the device
  1950.  
  1951. SetCtrlLines
  1952.            move.l    IO_OFFSET(a1),d0 ;Get the mask into d0
  1953.         move.l    IO_LENGTH(a1),d1 ;Get the bits for Setting/Clearing into d1
  1954.         and.l   d0,d1            ;And the two, to get the bits that need to be changed
  1955.     not.l   d1               ;not them for 6552 logic
  1956.     ori.b   #%11111100,d1    ;set the hi bit for FR access
  1957.     move.b    frstate(a3),d0     ;Get current state
  1958.     bset.l  #0,d0
  1959.     bset.l  #1,d0
  1960.     bset.l  #7,d0    
  1961.     and.b   d1,d0           ;Set DTR and RTS as requested (a low is assert)
  1962.     move.b    d0,frstate(a3)  ;Save the bit setting in the unit
  1963.     move.b    d0,FMR(a5)    ;Actually set the bits
  1964.         rts
  1965.  
  1966.  
  1967.  
  1968. ;The Stop command stop all future io requests from being processed until a
  1969. ;Start command is received. The Stop command is NOT stackable: e.g. no matter
  1970. ;how many stops have been issued, it only takes one Start to restart
  1971. ;processing.
  1972.  
  1973. MyStop
  1974.     PUTDEBUG 100,<'MyStop: called'>
  1975.     bset    #MDUB_STOPPED,MDU_FLAGS(a3)
  1976.     rts
  1977.  
  1978. Start
  1979.     PUTDEBUG 100,<'Start: called'>
  1980.     bsr.b    InternalStart
  1981.     rts
  1982.  
  1983. ;[A3=unit A6=device]
  1984.  
  1985. InternalStart
  1986.     PUTDEBUG 100,<'InternalStart: called'>
  1987.     movea.l    a1,a2
  1988.     ;Turn processing back on
  1989.     bclr    #MDUB_STOPPED,MDU_FLAGS(a3)
  1990.  
  1991. ;Kick the tasks to start them moving
  1992.  
  1993.     move.b    MP_SIGBIT(a3),d1    ;First the read task...
  1994.     moveq    #0,d0
  1995.     bset    d1,d0    ;Prepared signal mask
  1996.     movea.l    MP_SIGTASK(a3),a1 ;FIXED: marco-task to signal
  1997.     move.l    a6,-(sp)
  1998.     movea.l    md_SysLib(a6),a6
  1999.     mySYS    Signal    ;FIXED: marco-a6 not a3
  2000.     movea.l    (sp)+,a6
  2001.  
  2002.     movea.l    a2,a1    ;Then the write task
  2003.     lea    mdu_wport(a3),a0
  2004.     move.b    MP_SIGBIT(a0),d1
  2005.     moveq    #0,d0
  2006.     bset    d1,d0    ;Prepared signal mask
  2007.     movea.l    MP_SIGTASK(a0),a1 ;FIXED: marco-task to signal
  2008.     move.l    a6,-(sp)
  2009.     movea.l    md_SysLib(a6),a6
  2010.     mySYS    Signal    ;FIXED: marco-a6 not a3
  2011.     movea.l    (sp)+,a6
  2012.     movea.l    a2,a1
  2013.     PUTDEBUG 100,<'InternalStart: Finished!'>
  2014.     rts
  2015.  
  2016. ;Flush pulls all I/O requests off the queue and sends them back.  We must be
  2017. ;careful not to destroy work in progress, and also that we do not let some io
  2018. ;requests slip by.
  2019. ;
  2020. ;Some funny magic goes on with the STOPPED bit in here.  Stop is defined as
  2021. ;not being reentrant.  We therefore save the old state of the bit and then
  2022. ;restore it later.  This keeps us from needing to DISABLE in flush.  It also
  2023. ;fails miserably if someone does a start in the middle of a flush. (A
  2024. ;semaphore might help...)
  2025.  
  2026.  
  2027. Flush
  2028.     PUTDEBUG 100,<'Flush: called'>
  2029.     movem.l    d2/a1/a6,-(sp)
  2030.     movea.l    md_SysLib(a6),a6
  2031.     bset    #MDUB_STOPPED,MDU_FLAGS(a3)
  2032.     sne    d2
  2033.  
  2034. ReadFlush_Loop
  2035.     movea.l    a3,a0
  2036.     mySYS    GetMsg    ;Steal messages from task's port
  2037.     tst.l    d0
  2038.     beq.b    WriteFlush_Loop
  2039.  
  2040.     movea.l    d0,a1
  2041.     move.b    #IOERR_ABORTED,IO_ERROR(a1)
  2042.     mySYS    ReplyMsg
  2043.     bra.b    ReadFlush_Loop
  2044.  
  2045. WriteFlush_Loop
  2046.     lea    mdu_wport(a3),a0
  2047.     mySYS    GetMsg    ;Steal messages from task's port
  2048.     tst.l    d0
  2049.     beq.b    Flush_End
  2050.  
  2051.     movea.l    d0,a1
  2052.     move.b    #IOERR_ABORTED,IO_ERROR(a1)
  2053.     mySYS    ReplyMsg
  2054.     bra.b    WriteFlush_Loop
  2055.  
  2056. Flush_End
  2057.     move.l    d2,d0
  2058.     movem.l    (sp)+,d2/a1/a6
  2059.     tst.b    d0
  2060.     bne.b    1$
  2061.     bsr    InternalStart
  2062. 1$
  2063.     PUTDEBUG 100,<'Flush: Finished!'>
  2064.     rts
  2065.  
  2066. ;Here begins the task related routines
  2067. ;
  2068. ;A Task is provided so that queued requests may be processed at
  2069. ;a later time.  This is not very justifiable for a ram disk, but
  2070. ;is very useful for "real" hardware devices.  Take care with
  2071. ;your arbitration of shared hardware with all the multitasking
  2072. ;programs that might call you at once.
  2073. ;
  2074. ; Register Usage
  2075. ; ==============
  2076. ; a3 -- unit pointer
  2077. ; a6 -- syslib pointer
  2078. ; a5 -- device pointer
  2079. ; a4 -- task (NOT process) pointer
  2080. ; d7 -- wait mask
  2081. ;----------------------------------------------------------------------
  2082. ;
  2083. ;Note: Signals must be allocated within this (the task's) context!
  2084. ;The task is responsible for enabling the right DACIA interrupts...AFTER
  2085. ;it has done its setup (like allocating signals).
  2086. ;
  2087. ;NOTE: We actually have two tasks, each with their own separate
  2088. ;      code (but shared data). First comes the read task...:
  2089.  
  2090.  
  2091.     cnop    0,4     ;Long word align
  2092.  
  2093. ReadTask_Begin
  2094.     PUTDEBUG 200,<'ReadTask_Begin'>
  2095.     movea.l    (SysBase).w,a6
  2096.  
  2097. ;Grab the arguments passed down from our parent
  2098.  
  2099.     movea.l    4(sp),a3        ;Unit pointer
  2100.     movea.l    mdu_Device(a3),a5    ;Point to device structure
  2101.  
  2102.     lea    readsig(a3),a2
  2103.     moveq    #1,d6            ;Number of signals to allocate-1
  2104. ReadSigLoop
  2105.     moveq    #-1,d0    ;-1 is any signal at all
  2106.     mySYS    AllocSignal        ;Allocate signals for I/O interrupts
  2107.     moveq    #0,d7            ;Convert bit number signal mask
  2108.     bset    d0,d7
  2109.     move.l    d7,(a2)+        ;Save in unit structure
  2110.     dbra    d6,ReadSigLoop
  2111.  
  2112.     moveq    #-1,d0            ;-1 is any signal at all
  2113.     mySYS    AllocSignal        ;Allocate a signal
  2114.     move.b    d0,MP_SIGBIT(a3)
  2115.     move.b    #PA_SIGNAL,MP_FLAGS(a3) ;Make message port "live"
  2116.  
  2117. ;Change the bit number into a mask, and save in d7
  2118.  
  2119.     moveq    #0,d7    ;Clear D7
  2120.     bset    d0,d7
  2121.  
  2122.     ifge    INFO_LEVEL-40
  2123.     move.l    $114(a6),-(sp)
  2124.     move.l    a5,-(sp)
  2125.     move.l    a3,-(sp)
  2126.     move.l    d0,-(sp)
  2127.     PUTDEBUG 200,<'ReadTask -- Signal=%ld, Unit=%lx Device=%lx Task=%lx'>
  2128.     adda.l    #4*4,sp
  2129.     endc
  2130.  
  2131. ;Enable read-related ACIA interrupts
  2132.  
  2133.     move.l    a5,-(sp)
  2134.     movea.l    daciabase(a3),a5
  2135.     ori.b    #READINTMASK,IERstate(a3)
  2136.     move.b    #READINT,IER(a5)
  2137.     movea.l    (sp)+,a5
  2138.     bra.b    ReadTask_StartHere
  2139.  
  2140. ;OK, kids, we are done with initialization.  We now can start the main loop
  2141. ;of the driver.  It goes like this.  Because we had the port marked PA_IGNORE
  2142. ;for a while (in InitUnit) we jump to the getmsg code on entry.  (The first
  2143. ;message will probably be posted BEFORE our task gets a chance to run).
  2144. ;  wait for a message
  2145. ;  lock the device
  2146. ;  get a message.  If no message, unlock device and loop
  2147. ;  dispatch the message
  2148. ;  loop back to get a message
  2149.  
  2150. ;No more messages.  Back ourselves out.
  2151.  
  2152.                  
  2153. ReadTask_Unlock
  2154.          andi.b    #$ff&(~(UNITF_READACTIVE!UNITF_INREADTASK)),UNIT_FLAGS(a3)
  2155.  
  2156. ;Main loop: wait for a new message
  2157.  
  2158. ReadTask_MainLoop
  2159.     PUTDEBUG 200,<'ReadTask ++Sleep'>
  2160.     move.l    d7,d0
  2161.     mySYS    Wait
  2162.     ifge    INFO_LEVEL-5
  2163.     bchg.b    #1,($bfe001).l          ;Blink the power LED
  2164.     endc
  2165.  
  2166. ReadTask_StartHere
  2167.     PUTDEBUG 200,<'ReadTask ++Wakeup'>
  2168.     btst    #MDUB_STOPPED,MDU_FLAGS(a3) ;See if we are stopped
  2169.     bne    ReadTask_MainLoop    ;Device is stopped, ignore messages
  2170.     bset    #UNITB_READACTIVE,UNIT_FLAGS(a3) ;Lock the device
  2171.     bne    ReadTask_MainLoop    ;Device in use (immediate command?)
  2172.  
  2173. ReadTask_NextMessage:
  2174.     movea.l    a3,a0
  2175.     mySYS    GetMsg            ;Get the next request
  2176.     PUTDEBUG 200,<'ReadTask GotMsg'>
  2177.     tst.l    d0
  2178.     beq    ReadTask_Unlock     ; no message?
  2179.  
  2180.     movea.l    d0,a1            ;Do this request
  2181.     exg    a5,a6            ;Put device ptr in right place
  2182.  
  2183.     myForbid
  2184.     btst    #ioflagsB_Ignore,IO_FLAGS(a1)
  2185.     bne.b    Readignorecmd
  2186.     bset    #ioflagsB_Active,IO_FLAGS(a1)
  2187.     move.l    a1,ReadRequestPtr(a3)
  2188.     myPermit
  2189.     bsr    PerformIO    ;Do it!
  2190.     PUTDEBUG 200,<'Read Did PerformIO'>
  2191.     bclr    #ioflagsB_Active,IO_FLAGS(a1)
  2192.  
  2193. ;No longer active - abort has stopped sending signals. Now we can
  2194. ;(and should) clear the abort signal.
  2195.  
  2196.     moveq    #0,d0
  2197.     move.l    readabortsig(a3),d1
  2198.     myEXEC    SetSignal
  2199.     bra.b    Readconttl
  2200.  
  2201. Readignorecmd
  2202.     myPermit
  2203.     clr.l    IO_ACTUAL(a1)
  2204.     bsr    TermIO
  2205.     PUTDEBUG 200,<'Read Did TermIO'>
  2206. Readconttl
  2207.     exg    a5,a6        ;Get ExecBase back in a6
  2208.     bra    ReadTask_NextMessage
  2209.  
  2210. ;**** End of read task code ****
  2211.  
  2212. ;**** Beginning of write task code ****
  2213.  
  2214.     cnop    0,4    ;Long word align
  2215.  
  2216. ; Register Usage
  2217. ; ==============
  2218. ; a3 -- unit pointer
  2219. ; a6 -- syslib pointer
  2220. ; a5 -- device pointer
  2221. ; a4 -- task (NOT process) pointer
  2222. ; d7 -- wait mask
  2223.  
  2224. WriteTask_Begin
  2225.     PUTDEBUG 100,<'WriteTask_Begin'>
  2226.     movea.l    (SysBase).w,a6
  2227.  
  2228. ;Grab the arguments passed down from our parent
  2229.  
  2230.     movea.l    4(sp),a3    ;Unit pointer
  2231.     movea.l    mdu_Device(a3),a5    ;Point to device structure
  2232.     lea    tdresig(a3),a2
  2233.     moveq    #4,d6        ;Number of signals to allocate-1
  2234. WriteSigLoop
  2235.     moveq    #-1,d0            ;-1 is any signal at all
  2236.     mySYS    AllocSignal    ;Allocate signals for I/O interrupts
  2237.     moveq    #0,d7        ;Convert bit number signal mask
  2238.     bset    d0,d7
  2239.     move.l    d7,(a2)+    ;Save in unit structure
  2240.     dbra    d6,WriteSigLoop
  2241.  
  2242.     move.l    breaksig(a3),d0
  2243.     move.l    d0,d1
  2244.     mySYS    SetExcept    ;Make breaksig an exception-causing signal
  2245.  
  2246. ;Allocate a signal for the timer message port
  2247.  
  2248.     moveq    #-1,d0        ;-1 is any signal at all
  2249.     mySYS    AllocSignal
  2250.     lea    timerport(a3),a2
  2251.     move.b    d0,MP_SIGBIT(a2)
  2252.     move.l    a2,timeriorequest+MN_REPLYPORT(a3)
  2253.     suba.l    a1,a1
  2254.     mySYS    FindTask
  2255.     move.l    d0,MP_SIGTASK(a2)    
  2256.     move.b    #PA_SIGNAL,MP_FLAGS(a2) ;Make message port "live"
  2257.  
  2258. ;Allocate a signal for the cmd message port
  2259.  
  2260.     moveq    #-1,d0    ;-1 is any signal at all
  2261.     mySYS    AllocSignal
  2262.     move.b    d0,mdu_wport+MP_SIGBIT(a3)
  2263.     move.b    #PA_SIGNAL,mdu_wport+MP_FLAGS(a3) ;Make message port "live"
  2264.  
  2265. ;Change the bit number into a mask, and save in d7
  2266.  
  2267.     moveq    #0,d7    ;Clear D7
  2268.     bset    d0,d7
  2269.  
  2270.     ifge    INFO_LEVEL-40
  2271.     move.l    ThisTask(a6),-(sp)
  2272.     move.l    a5,-(sp)
  2273.     move.l    a3,-(sp)
  2274.     move.l    d0,-(sp)
  2275.     PUTDEBUG 100,<'WriteTask -- Signal=%ld, Unit=%lx Device=%lx Task=%lx'>
  2276.     adda.l    #4*4,sp
  2277.     endc
  2278.  
  2279. ;Enable write-related ACIA interrupts
  2280.  
  2281.     move.l    a5,-(sp)
  2282.     movea.l    daciabase(a3),a5
  2283.     ori.b    #HANDINTMASK,IERstate(a3)
  2284.     move.b    #HANDINT,IER(a5)
  2285.     movea.l    (sp)+,a5
  2286.     bra.b    WriteTask_StartHere
  2287.  
  2288. ;No more messages.  Back ourselves out.
  2289.  
  2290. WriteTask_Unlock
  2291.     andi.b    #$ff&(~(UNITF_WRITEACTIVE!UNITF_INWRITETASK)),UNIT_FLAGS(a3)
  2292.  
  2293. ;Main loop: wait for a new message
  2294.  
  2295. WriteTask_MainLoop
  2296.     PUTDEBUG 100,<'WriteTask ++Sleep'>
  2297.     move.l  d7,d0
  2298.     mySYS    Wait
  2299.     
  2300.     
  2301.     ifge INFO_LEVEL-5
  2302.     bchg.b    #1,($bfe001).l  ;Blink the power LED
  2303.     endc
  2304.  
  2305. WriteTask_StartHere
  2306.     PUTDEBUG 100,<'WriteTask ++Wakeup'>
  2307.     btst    #MDUB_STOPPED,MDU_FLAGS(a3) ;See if we are stopped
  2308.     bne     WriteTask_MainLoop    ;Device is stopped, ignore messages
  2309.     bset    #UNITB_WRITEACTIVE,UNIT_FLAGS(a3) ;Lock the device
  2310.     bne     WriteTask_MainLoop    ;Device in use (immediate command?)
  2311.  
  2312. WriteTask_NextMessage:
  2313.     lea    mdu_wport(a3),a0
  2314.     mySYS    GetMsg            ;Get the next request
  2315.     PUTDEBUG 100,<'WriteTask GotMsg'>
  2316.     tst.l    d0
  2317.     beq    WriteTask_Unlock    ;No message?
  2318.     movea.l    d0,a1            ;Do this request
  2319.     exg    a5,a6            ;Put device ptr in right place
  2320.  
  2321.     myForbid
  2322.     btst    #ioflagsB_Ignore,IO_FLAGS(a1)
  2323.     bne.b    Writeignorecmd
  2324.     bset    #ioflagsB_Active,IO_FLAGS(a1)
  2325.     move.l    a1,WriteRequestPtr(a3)
  2326.     myPermit
  2327.     bsr    PerformIO    ;Do it!
  2328.     bclr    #ioflagsB_Active,IO_FLAGS(a1)
  2329.  
  2330. ;No longer active - abort has stopped sending signals. Now we can
  2331. ;(and should) clear the abort signal.
  2332.  
  2333.     moveq    #0,d0
  2334.     move.l    writeabortsig(a3),d1
  2335.     myEXEC    SetSignal
  2336.     bra.b    Writeconttl
  2337.  
  2338. Writeignorecmd
  2339.     myPermit
  2340.     clr.l    IO_ACTUAL(a1)
  2341.     bsr    TermIO
  2342. Writeconttl
  2343.     exg    a5,a6            ; get syslib back in a6
  2344.     bra    WriteTask_NextMessage
  2345.  
  2346. ;***** end of write task code *****
  2347.  
  2348. ;Exception Handler (performs a break command)
  2349. ;Note that this code acts as a handler for the write task only; the
  2350. ;read task has no such handler.
  2351. ;
  2352. ;unit ptr in a1, execbase in a6
  2353. ;All registers are saved/restored by Exec
  2354. ;Note: Not all the usual newser register conventions are used here
  2355.  
  2356. breakexception
  2357.     PUTDEBUG 100,<'BreakException: called'>
  2358.     move.l    d0,-(sp)    ;Save exception bits
  2359.     movea.l    a1,a3
  2360.     movea.l    a1,a2
  2361.     btst    #UNITB_BREAKACTIVE,UNIT_FLAGS(a3) ;Sanity check
  2362.     beq    endbreakex
  2363.     movea.l    daciabase(a3),a5
  2364.     move.b    #2,ACR(a5) ;start break
  2365.     lea    timeriorequest(a3),a1
  2366.     move.w    #TR_ADDREQUEST,IO_COMMAND(a1)
  2367.     movea.l    mdu_prefs(a3),a4
  2368.     clr.l    TV_SECS(a1)
  2369.     move.l    prefs_BRKTIME(a4),d0
  2370.     ori.b    #$FF,d0    ;To avoid the V33/V34 bug
  2371.     move.l    d0,TV_MICRO(a1)
  2372.  
  2373.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  2374.     move.l    d0,-(sp)
  2375.     PUTDEBUG 100,<'BreakException: TV_MICRO=%ld'>
  2376.     addq.l    #4,sp
  2377.     endc
  2378.  
  2379.     movea.l    MN_REPLYPORT(a1),a0
  2380.     move.b    MP_SIGBIT(a0),d2
  2381.     jsr    _LVOSendIO(a6)
  2382.  
  2383.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  2384.     clr.l    -(sp)
  2385.     move.b    d2,3(sp)
  2386.     PUTDEBUG 100,<'BreakException: Waiting for signal #%ld'>
  2387.     addq.l    #4,sp
  2388.     endc
  2389.  
  2390. ;Take note - waiting within an exception is tricky!
  2391.  
  2392.     suba.l    a1,a1
  2393.     jsr    _LVOFindTask(a6)
  2394.     movea.l    d0,a4            ;ThisTask
  2395.     moveq    #0,d0
  2396.     bset    d2,d0
  2397.     add.l    writeabortsig(a3),d0
  2398.     move.l    TC_SIGWAIT(a4),d3 ;Save this -- very important!!!
  2399.     jsr    _LVOWait(a6)
  2400.     move.l    d3,TC_SIGWAIT(a4) ;Restore -- very important!!!
  2401.     and.l    writeabortsig(a3),d0
  2402.     beq.b    breakOK
  2403.  
  2404.     PUTDEBUG 100,<'BreakException: Aborted!'>
  2405.  
  2406.     lea    timeriorequest(a3),a1 ;The break was aborted. Clean up.
  2407.     jsr    _LVOAbortIO(a6)
  2408.  
  2409.     lea    timeriorequest(a3),a1
  2410.     jsr    _LVOWaitIO(a6)
  2411.  
  2412. breakOK
  2413.     move.b    #0,ACR(a5)
  2414.     movea.l    breakiorequest(a3),a1
  2415.     clr.b    IO_ERROR(a1)
  2416.     btst    #IOB_QUICK,IO_FLAGS(a1)
  2417.     bne.b    endbreakex
  2418.     jsr    _LVOReplyMsg(a6) 
  2419. endbreakex
  2420.     move.l    (sp)+,d0 ;restore exception bits
  2421.     PUTDEBUG 100,<'BreakException: Finished!'>
  2422.     rts
  2423.  
  2424. ;Initialize the device
  2425.  
  2426. mdu_Init                ;Initialize read task message port/tcb
  2427.     INITBYTE MP_FLAGS,PA_IGNORE ;Unit starts with a message port
  2428.     INITBYTE LN_TYPE,NT_MSGPORT
  2429.     INITLONG LN_NAME,Task1
  2430.     INITLONG mdu_rtcb+LN_NAME,Task1
  2431.     INITBYTE mdu_rtcb+LN_TYPE,NT_TASK
  2432.     INITBYTE  mdu_rtcb+LN_PRI,5
  2433.  
  2434. ;Initialize write task message port/tcb
  2435.  
  2436.     INITBYTE mdu_wport+MP_FLAGS,PA_IGNORE ;Unit starts with a message port
  2437.     INITBYTE mdu_wport+LN_TYPE,NT_MSGPORT
  2438.     INITLONG mdu_wport+LN_NAME,Task2
  2439.     INITLONG mdu_wtcb+LN_NAME,Task2
  2440.     INITBYTE mdu_wtcb+LN_TYPE,NT_TASK
  2441.     INITBYTE mdu_wtcb+LN_PRI,126
  2442.  
  2443. ;Initialize interrupt structure (except for is_data of course).
  2444.  
  2445.     INITBYTE  mdu_is+LN_TYPE,NT_INTERRUPT
  2446.     INITBYTE  mdu_is+LN_PRI,-127    ;Int priority 11
  2447.     INITLONG  mdu_is+IS_CODE,int    ;Interrupt routine addr
  2448.     INITLONG  mdu_is+LN_NAME,LibName
  2449.  
  2450. ;Initialize timer message port
  2451.  
  2452.     INITBYTE timerport+MP_FLAGS,PA_IGNORE ;Unit starts with a message port
  2453.     INITBYTE timerport+LN_TYPE,NT_MSGPORT
  2454.     INITLONG timerport+LN_NAME,LibName
  2455.  
  2456.     dc.w    0
  2457.  
  2458. ;******************** Interrupt code *********************************
  2459.  
  2460. ;Notes:
  2461. ;
  2462. ;Guru's Guide #1: Interrupts is helpful.
  2463. ;------ ----- --- ----------
  2464. ;
  2465. ;NOTE: I am using one interrupt server for each unit. I think it's
  2466. ;simpler then using one each for the read and write tasks.
  2467. ;
  2468. ;This is the interrupt server code. It serves four purposes:
  2469. ;1. Read in a byte if available, store it, and signal the read task
  2470. ;2. Check for TDRE-empty condition and signal write task
  2471. ;3. Check for a DSR* transition and signal write task IF handshake is wanted
  2472. ;4. Check for an exceptional condition and signal read task
  2473. ;
  2474. ;Enter with data pointer in a1 (unit pointer)
  2475. ;d0, d1, a0, a1, a5, and a6 are scratch
  2476. ;
  2477. ;Returns Z bit clear if the interrupt was not caused by the dacia,
  2478. ;otherwise return with the Z bit set.
  2479.  
  2480. int
  2481.     move.l    a3,-(sp)
  2482.     move.w    d7,-(sp)
  2483.     movea.l    a1,a3
  2484.     movea.l    daciabase(a3),a5
  2485.     move.b    ISR(a5),d7    ;This clears CTST, DCDT, and DSRT ints
  2486.     and.b    IERstate(a3),d7    ;Quick check (note that this masking is very
  2487.                     ;important)
  2488.     bne.b    serveint    ;Yes, service the dacia
  2489.     move.w    (sp)+,d7    ;Not for us
  2490.     movea.l    (sp)+,a3
  2491.     PUTDEBUG 200,<'Int: Not for us!'>
  2492.     moveq    #0,d0
  2493.     rts  
  2494.  
  2495. serveint
  2496.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  2497.     clr.l    -(a7)
  2498.     move.b    d7,3(a7)
  2499.     PUTDEBUG 200,<'Int: Entered with ISR=%lx'>
  2500.     addq.l    #4,sp
  2501.     endc
  2502.  
  2503. ;Read error condition?
  2504. ;(We must check this first because a read of the RDR clears the error flags.)
  2505.  
  2506.     move.b    d7,d0
  2507.     and.b    #6,d0
  2508.     beq.b    contint    ;No errors
  2509.  
  2510.     PUTDEBUG 200,<'Int: Read error condition.'>
  2511.  
  2512. ;An exceptional condition occured - signal the read task
  2513.  
  2514.     move.b    d7,ISRcopy(a3)    ;Useful info
  2515.     move.b    CSR(a5),CSRcopy(a3) ;More useful info
  2516.     move.l    readabortsig(a3),d0
  2517.     lea    mdu_rtcb(a3),a1
  2518.     movea.l    mdu_SysLib(a3),a6
  2519.     jsr    _LVOSignal(a6)
  2520.  
  2521.     move.b    RDR(a5),d0    ;This forces a clear of the error bits
  2522.     bra    rdrfempty
  2523.  
  2524. contint
  2525.     btst    #ISRB_RDRF,d7    ;Test Receive Data Buffer Full
  2526.     beq.b    rdrfempty
  2527.  
  2528.     PUTDEBUG 200,<'Int: Read.'>
  2529.  
  2530.  
  2531. ;Store the byte in the circular buffer.  Note that this code *can't* be
  2532. ;interrupted, so we're safe (that's because CIA B, which we're plugging into,
  2533. ;is connected to INT6*).
  2534.  
  2535.     movea.l    tail(a3),a0    ;Read and store
  2536.     move.b    RDR(a5),(a0)+
  2537.     cmpa.l    endbuf(a3),a0
  2538.     bls.b    notend    ;endbuf >= tail
  2539.     movea.l    startbuf(a3),a0    ;Wrap around
  2540. notend
  2541.     move.l    a0,tail(a3) 
  2542.     move.l    head(a3),d0
  2543.     cmpa.l    d0,a0
  2544.     bne.b    nocross
  2545.     bset    #MDUB_V,MDU_FLAGS(a3) ;set buf overflow flag
  2546.     addq.l    #1,d0
  2547.     move.l    d0,head(a3)
  2548.     cmp.l    endbuf(a3),d0
  2549.     bls.b    nocross
  2550.     move.l    startbuf(a3),head(a3)  
  2551. nocross
  2552.     movea.l    mdu_SysLib(a3),a6
  2553.     move.l    readsig(a3),d0
  2554.     lea    mdu_rtcb(a3),a1
  2555.     jsr    _LVOSignal(a6)    ;Signal the read task
  2556.  
  2557. rdrfempty
  2558.     btst    #ISRB_TDRE,d7    ;Check TDRE
  2559.     beq.b    notdre
  2560.  
  2561.     PUTDEBUG 200,<'Int: Write signal.'>
  2562.     andi.b    #WRITEOFFMASK,IERstate(a3)
  2563.     move.b    #WRITEOFF,IER(a5)
  2564.     move.l    tdresig(a3),d0
  2565.     lea    mdu_wtcb(a3),a1
  2566.     movea.l    mdu_SysLib(a3),a6
  2567.     jsr    _LVOSignal(a6)    ;Signal the write task
  2568.  
  2569. ;see if handshaking ("7 wire") is enabled
  2570.  
  2571. notdre
  2572.     movea.l    mdu_prefs(a3),a6
  2573.     btst    #SERB_XDISABLED,prefs_SERFLAGS(a6)
  2574.     bne.b    nohand
  2575.  
  2576.     btst    #ISRB_DSRT,d7    ;Check for DSR* transition
  2577.     beq.b    nohand
  2578.  
  2579.     PUTDEBUG 200,<'Int: DSR transition.'>
  2580.  
  2581.     move.l    dsrsig(a3),d0
  2582.     lea    mdu_wtcb(a3),a1
  2583.     movea.l    mdu_SysLib(a3),a6
  2584.     jsr    _LVOSignal(a6)    ;Signal the write task
  2585.  
  2586. nohand:
  2587. termchain
  2588.     PUTDEBUG 200,<'Int: Finished!'>
  2589.     move.w    (sp)+,d7
  2590.     movea.l    (sp)+,a3
  2591.     moveq    #1,d0    ;Terminate the chain
  2592.     rts
  2593.  
  2594.  
  2595. defaultprefs
  2596.     dc.l    SER_DEFAULT_CTLCHAR     ;prefs_CTLCHAR
  2597.     dc.l    16*1024             ;prefs_RBUFLEN
  2598.     dc.l    0                    ;prefs_EXTFLAGS
  2599.     dc.l    1200                ;prefs_BAUD
  2600.     dc.l    250000              ;prefs_BRKTIME
  2601.     dc.l    0                    ;prefs_TERMARRAY
  2602.     dc.l    0                   ;prefs_TERMARRAY
  2603.     dc.b    8                    ;prefs_READLEN
  2604.     dc.b    8                   ;prefs_WRITELEN
  2605.     dc.b    1                    ;prefs_STOPBITS
  2606.     dc.b    $88                 ;prefs_SERFLAGS
  2607.  
  2608. ;Table of DACIA base addresses for the 4 units
  2609.  
  2610. basetable
  2611.     dc.l    ACIA_Base
  2612.     dc.l    ACIA_Base+UNIT2
  2613.     dc.l    ACIA_Base+ACIA1
  2614.     dc.l    ACIA_Base+ACIA1+UNIT2
  2615.  
  2616. ;List of supported baud rates 
  2617.  
  2618. baudtable
  2619.     dc.w    50
  2620.     dc.w    110
  2621.     dc.w    135
  2622.     dc.w    150
  2623.     dc.w    300
  2624.     dc.w    600
  2625.     dc.w    1200
  2626.     dc.w    1800
  2627.     dc.w    2400
  2628.     dc.w    3600
  2629.     dc.w    4800
  2630.     dc.w    7200
  2631.     dc.w    9600
  2632.     dc.w    19200
  2633.     dc.w    38400
  2634.     dc.w    31250    ;MIDI (external clock)
  2635.  
  2636.  
  2637. cmdtable
  2638.     dc.l   Invalid        ;$00000001  ;0  CMD_INVALID
  2639.     dc.l   MyReset        ;$00000002  ;1  CMD_RESET
  2640.     dc.l   Read         ;$00000004  ;2  CMD_READ
  2641.     dc.l   Write         ;$00000008  ;3  CMD_WRITE
  2642.     dc.l   Invalid        ;$00000010  ;4  CMD_UPDATE (update has no meaning here)
  2643.     dc.l   MyClear        ;$00000020  ;5  CMD_CLEAR
  2644.     dc.l   MyStop        ;$00000040  ;6  CMD_STOP
  2645.     dc.l   Start         ;$00000080  ;7  CMD_START
  2646.     dc.l   Flush         ;$00000100  ;8  CMD_FLUSH
  2647.     dc.l   Query        ;$00000200  ;9  SDCMD_QUERY
  2648.     dc.l   Break        ;$00000400  ;10 SDCMD_BREAK
  2649.     dc.l   SetParams    ;$00000800  ;11 SDCMD_SETPARAMS
  2650.     dc.l   $FFFFFFFF    ;$00001000  ;12 NULL
  2651.     dc.l   $FFFFFFFF    ;$00002000  ;13 NULL
  2652.     dc.l   $FFFFFFFF    ;$00004000  ;14 NULL
  2653.     dc.l   $FFFFFFFF    ;$00008000  ;15 NULL
  2654.     dc.l   SetCtrlLines ;$00010000  ;16 SIOCMD_SETCTRLLINES
  2655. cmdtable_end:
  2656.  
  2657.     ISDEBUG    'newser'    ;This name for debugging use
  2658.          
  2659.      dc.l  0
  2660.     
  2661. LibEnd:
  2662.     END
  2663.  
  2664.  
  2665.