home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 550b.lha / newser_v2.10 / newser.asm < prev    next >
Assembly Source File  |  1991-09-08  |  69KB  |  2,839 lines

  1. *****************************************************************************
  2. * Program:  newser.asm - Copyright © 1990, 1991 by Dan Babcock
  3. *
  4. * Permission is given for PERSONAL use of this code. Commercial
  5. * use is of course forbidden. (Without prior permission etc.)
  6. *
  7. * Function: A "serial.device" compatible driver for the Rockwell 65C52
  8. *
  9. * Author:   Dan Babcock
  10. * History:  08/12/90 V0.50 Created
  11. *           09/06/90 V0.51 Cleaned up "eofdump" code.
  12. *           11/04/90 V0.52 Misc. minor changes
  13. *                          [release 1]
  14. *           03/03/91 V1.10 Fixed some bugs, speeded up, & added prefs hook
  15. *           03/08/91 V1.11 Bug fixes
  16. *                          [release 2]
  17. *           04/18/91 V1.12 Small changes (very small)
  18. *           06/20/91 V2.00 Bug fixes, code clean-up, faster
  19. *                          [release 3]
  20. *           06/27/91 V2.10 Added ASDG-style DTR/RTS control extension
  21. *                          (See "SetControlLines" for documentaion)
  22. *                          Added special time-out to write routine to
  23. *                          avoid theoretical (and possibly real) problem
  24. *                          Fixed bug in Break routine
  25. *                          [release 4]
  26. *
  27. * Feel free to contact me:
  28. *
  29. * [School address]               [Permanent address]      People/Link:
  30. *  Subject to                     Dan Babcock              DANBABCOCK
  31. *  change so not                  P.O. Box 1532              Bix:
  32. *  given here                     Southgate, MI  48195     danbabcock
  33. *                                 U.S.A.
  34. * I am also reachable via internet. I read comp.sys.amiga.programming.
  35. *
  36. * General notes
  37. * =============
  38. * The macro "PUTDEBUG" is used to output debugging information via the
  39. * internal serial port at a low level. It may be used anywhere, including
  40. * critical sections, supervisor mode, and interrupt code. If debugging is
  41. * not desired, set the INFO_LEVEL equate to zero. Conversely, if debugging
  42. * is desired, set it to a high value (e.g. 100000)
  43. *
  44. * A consistent (for the most part) usage of registers was employed:
  45. *  A1 - pointer to an IORequest structure
  46. *  A3 - pointer to a unit structure (defined below)
  47. *  A4 - pointer to a serprefs structure (defined below)
  48. *  A5 - pointer to the hardware (one channel, that is)
  49. *  A6 - pointer to the device structure (defined below)
  50. *
  51. * Known differences between this and serial.device are:
  52. *  1. Start/Stop do not send XON/XOFF characters to the outside world
  53. *     as implied in the autodoc. (I doubt anyone uses Start and Stop...)
  54. *  2. Newser does not currently send an XOFF or otherwise tell the outside
  55. *     world to "shut up" when the driver's input buffer fills.
  56. *     Since the buffer is 64K, it is very unlikely to ever fill.
  57. *  Both of those capabilities can be added external to the driver if you
  58. *  have a custom application that requires them.
  59. *****************************************************************************
  60.  
  61.     MC68010
  62.     super    ;suppress warnings about supervisor mode
  63.     exeobj
  64.     objfile    'devs:newser.device'
  65.     macfile    'newser.i'
  66.  
  67. ;Set INFO_LEVEL to a high number (e.g. 100000) for full debugging output
  68. ;over the internal serial port.
  69. INFO_LEVEL    equ    000000
  70.  
  71. EXEC    macro
  72.     move.l    a1,-(sp)
  73.     move.l    a6,-(sp)
  74.     movea.l    (4).w,a6
  75.     jsr    (_LVO\1,a6)
  76.     movea.l    (sp)+,a6
  77.     movea.l    (sp)+,a1
  78.     endm
  79.  
  80. ;*************************** Structures *************************
  81.  
  82. serprefs    clrso
  83. prefs_CTLCHAR    so.l    1    ;Control char's (order = xON,xOFF,rsvd,rsvd)
  84. prefs_RBUFLEN    so.l    1    ;Length in bytes of serial port's read buffer
  85. prefs_EXTFLAGS    so.l    1    ;Additional serial flags
  86. prefs_BAUD    so.l    1    ;Baud rate requested (true baud)
  87. prefs_BRKTIME    so.l    1    ;Duration of break signal in MICROseconds
  88. prefs_TERMARRAY    so.b    TERMARRAY_SIZE    ;Termination character array
  89. prefs_READLEN    so.b    1    ;Bits per read char (bit count)
  90. prefs_WRITELEN    so.b    1    ;Bits per write char (bit count)
  91. prefs_STOPBITS    so.b    1    ;Stopbits for read (count)
  92. prefs_SERFLAGS    so.b    1    ;See SERFLAGS bit definitions
  93. serprefs_sizeof    soval
  94.  
  95. MyDev    setso    LIB_SIZE
  96. md_Flags    so.b    1
  97. md_Pad1    so.b    1
  98. md_SysLib    so.l    1
  99. md_SegList    so.l    1
  100. md_Units    so.b    MD_NUMUNITS*4
  101. VectorBase    so.l    1
  102. MyPreviousAutoVec:    so.l    1
  103. ScoreBoard    so.w    1
  104. Chip1present    so.w    1
  105. Chip2present    so.w    1
  106. prefs_unit0    so.b    serprefs_sizeof    ;The reason why prefs are in this
  107. prefs_unit1    so.b    serprefs_sizeof    ;structure instead of the unit structure
  108. prefs_unit2    so.b    serprefs_sizeof    ;is that the pref settings should be saved
  109. prefs_unit3    so.b    serprefs_sizeof    ;across CloseDevice calls (which usually
  110. MyDev_Sizeof    soval            ;causes the unit to be dumped).
  111.  
  112. MyDevUnit    setso    UNIT_SIZE    ;Odd # longwords
  113. mdu_wport    so.b    MP_SIZE    ;MsgPort for write task
  114. MDU_FLAGS    so.b    1
  115. IERstate    so.b    1    ;Current state of IER used as a mask
  116. mdu_UnitNum    so.b    1
  117. frstate    so.b    1    ;This var mirrors a write-only register
  118. mdu_SysLib    so.l    1    ;Copy of location 4
  119. mdu_Device    so.l    1    ;Ptr to main device struct
  120. mdu_rstack    so.b    MYPROCSTACKSIZE    ;For read task
  121. mdu_wstack    so.b    MYPROCSTACKSIZE    ;For write task
  122. mdu_rtcb    so.b    TC_SIZE    ;Task Control Block (TCB) for read task
  123. mdu_wtcb    so.b    TC_SIZE    ;Task Control Block (TCB) for write task
  124. timerport    so.b    MP_SIZE
  125. timeriorequest    so.b    IOTV_SIZE
  126.  
  127. ;The -sig longwords must be contiguous!!!
  128. readsig    so.l    1    ;Read task signals
  129. readabortsig    so.l    1
  130.  
  131. tdresig    so.l    1    ;Write block finished
  132. writeabortsig    so.l    1
  133. xonsig    so.l    1    ;Comes from read task, and indicates xon received
  134.  
  135. HeadLong    so.w    1    ;Ptr to start of circular buffer (logical)
  136. Head    so.w    1
  137. TailLong    so.w    1    ;Ptr to end of circular buffer (logical)
  138. Tail    so.w    1
  139. StartBuf    so.l    1    ;Ptr to physical start of input buffer
  140. ReadRequestPtr    so.l    1
  141. WriteRequestPtr    so.l    1
  142. xstate    so.b    1    ;Zero if 'x-off' received, else $FF
  143. ISRcopy    so.b    1    ;Used for read error diagnosis
  144. CSRcopy    so.b    1    ;Used for read error diagnosis
  145. Exclusive    so.b    1    ;True if someone has exclusive access to this unit
  146. daciabase    so.l    1
  147. mdu_prefs    so.l    1    ;Ptr to prefs for this unit (in MyDev)
  148. WriteCount    so.l    1
  149. WriteBufferPtr    so.l    1
  150. MyDevUnit_Sizeof    soval
  151.  
  152. ;Note that we have a single unit structure used by both the read and write
  153. ;tasks (and the interrupt routine).
  154.  
  155. * UNIT_FLAG definitions:
  156.  
  157.     BITDEF    UNIT,BREAKSENT,2    ;break sent flag for Query
  158.     BITDEF    UNIT,READIMMEDIATE,3
  159.     BITDEF    UNIT,NEEDCHAR,4
  160.  
  161. * Bit definitions for MDU_FLAGS
  162.  
  163.     BITDEF    MDU,STOPPED,2    ;State bit for unit stopped
  164.     BITDEF    MDU,V,3    ;Buffer overflow flag - set in int routine if an overflow occurs
  165.     BITDEF    MDU,WaitingForChar,4
  166.     BITDEF    MDU,CharAvailable,5
  167.  
  168. * Bit definitions for ioflags
  169.  
  170.     BITDEF    ioflags,Ignore,4    ;Ignore this IO request
  171.  
  172. * Equates & bit defs for IERstate
  173.  
  174. READINT    equ    $87
  175. READINTMASK    equ    $7
  176.  
  177. WRITEINT    equ    $C0
  178. WRITEINTMASK    equ    $40
  179.  
  180. MYIDENT    macro
  181.     cstr    'newser.device V2.10 (June 27, 1991)',13,10
  182.     even
  183.     endm
  184.  
  185. ;The first executable location.  This should return an error in case someone
  186. ;tried to run us as a program (instead of loading us as a device).
  187.  
  188. FirstAddress:
  189.     moveq    #-1,d0
  190.     rts
  191.  
  192. ;A romtag structure.  After your driver is brought in from disk, the
  193. ;disk image will be scanned for this structure to discover magic constants
  194. ;about you (such as where to start running you from...).
  195.  
  196. initDDescrip:
  197.     dw    RTC_MATCHWORD    ;UWORD    RT_MATCHWORD (Magic cookie)
  198.     dl    initDDescrip    ;APTR    RT_MATCHTAG  (Back pointer)
  199.     dl    EndCode    ;APTR    RT_ENDSKIP   (To end of this hunk)
  200.     db    RTF_AUTOINIT    ;UBYTE    RT_FLAGS     (magic-see "Init")
  201.     db    VERSION    ;UBYTE    RT_VERSION
  202.     db    NT_DEVICE    ;UBYTE    RT_TYPE      (must be correct)
  203.     db    MYPRI    ;BYTE    RT_PRI
  204.     dl    myName    ;APTR    RT_NAME      (exec name)
  205.     dl    idString    ;APTR    RT_IDSTRING  (text string)
  206.     dl    Init    ;APTR    RT_INIT
  207.  
  208.     db    'newser.device - Copyright (c) 1990, 1991 by Dan Babcock. '
  209.     db    'Contact me on People/Link, Bix, or Usenet!'
  210.     even
  211.  
  212. ;nasty data area (makes this version non-ROMable)
  213.  
  214. OldVec:    dc.l    0
  215. Unit0:    dc.l    0
  216. Unit1:    dc.l    0
  217. _Unit2:    dc.l    0    ;_ used because of conflict with chip reg addr sym
  218. Unit3:    dc.l    0
  219.  
  220.  
  221. ;*********************** Tables (constant) **********************
  222.  
  223. ;Note!! Some of these values are depended on in the InitRoutine prefs
  224. ;code...i.e. they may not be changed arbitrarily!
  225.  
  226. defaultprefs:
  227.     dl    SER_DEFAULT_CTLCHAR ;prefs_CTLCHAR
  228.     dl    64*1024    ;prefs_RBUFLEN
  229.     dl    0    ;prefs_EXTFLAGS
  230.     dl    9600    ;prefs_BAUD
  231.     dl    250000    ;prefs_BRKTIME
  232.     dl    0    ;prefs_TERMARRAY
  233.     dl    0    ;prefs_TERMARRAY
  234.     db    8    ;prefs_READLEN
  235.     db    8    ;prefs_WRITELEN
  236.     db    1    ;prefs_STOPBITS
  237. ;Note: RAD_BOOGIE must NOT be set here
  238.     db    $88    ;prefs_SERFLAGS
  239.  
  240. ;Table of DACIA base addresses for the 4 units
  241.  
  242. basetable:
  243.     dl    ACIA_Base
  244.     dl    ACIA_Base+UNIT2
  245.     dl    ACIA_Base+ACIA1
  246.     dl    ACIA_Base+ACIA1+UNIT2
  247.  
  248. ;List of supported baud rates 
  249.  
  250. baudtable:
  251.     dw    50
  252.     dw    110
  253.     dw    135
  254.     dw    150
  255.     dw    300
  256.     dw    600
  257.     dw    1200
  258.     dw    1800
  259.     dw    2400
  260.     dw    3600
  261.     dw    4800
  262.     dw    7200
  263.     dw    9600
  264.     dw    19200
  265.     dw    38400
  266.     dw    31250    ;MIDI (external clock)
  267.  
  268. timername:
  269.     cstr    'timer.device'
  270.  
  271.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  272. subSysName:
  273.     cstr    'newser'    ;This name for debugging use
  274.     endc
  275.  
  276. myName:    MYDEVNAME    ;This is the name that the device will have
  277.  
  278. ;This is an identifier tag to help in supporting the device
  279. ;format is 'name version.revision (dd MON yyyy)',<cr>,<lf>,<null>
  280.  
  281. idString:    MYIDENT
  282.  
  283. ;The romtag specified that we were "RTF_AUTOINIT".  This means that the
  284. ;RT_INIT structure member points to one of these tables below.  If the
  285. ;AUTOINIT bit was not set then RT_INIT would point to a routine to run.
  286.  
  287. Init:    dl    MyDev_Sizeof    ;data space size
  288.     dl    FuncTable    ;pointer to function initializers
  289.     dl    DataTable    ;pointer to data initializers
  290.     dl    InitRoutine    ;routine to run
  291.  
  292. FuncTable:
  293.     dw    -1    ;this indicates that the following are offsets,
  294.             ;rather than absolute addresses
  295.     dw    Open-FuncTable    ;standard system routines
  296.     dw    _Close-FuncTable
  297.     dw    Expunge-FuncTable
  298.     dw    Null-FuncTable    ;Reserved for future use!
  299.     dw    BeginIO-FuncTable    ;my device definitions
  300.     dw    AbortIO-FuncTable
  301.     dw    -1    ;function table end marker
  302.  
  303. ;The data table initializes static data structures. The format is
  304. ;specified in exec/InitStruct routine's manual pages.  The
  305. ;INITBYTE/INITWORD/INITLONG macros are in the file "exec/initializers.i".
  306. ;The first argument is the offset from the device base for this
  307. ;byte/word/long. The second argument is the value to put in that cell.
  308. ;The table is null terminated
  309.  
  310. DataTable:
  311.     INITBYTE    LN_TYPE,NT_DEVICE    ;Must be LN_TYPE!
  312.     INITLONG    LN_NAME,myName
  313.     INITBYTE    LIB_FLAGS,LIBF_SUMUSED+LIBF_CHANGED
  314.     INITWORD    LIB_VERSION,VERSION
  315.     INITWORD    LIB_REVISION,REVISION
  316.     INITLONG    LIB_IDSTRING,idString
  317.     dw     0    ;terminate list
  318.  
  319. ;This routine gets called after the device has been allocated.  The device
  320. ;pointer is in D0.  The AmigaDOS segment list is in a0.  If it returns the
  321. ;device pointer, then the device will be linked into the device list.  If it
  322. ;returns NULL, then the device will be unloaded.
  323. ;
  324. ;This call is single-threaded by exec; please read the description for
  325. ;"Open" below.
  326. ;
  327. ; Register Usage
  328. ; ==============
  329. ; a3 -- Points to temporary RAM
  330. ; a4 -- Expansion library base
  331. ; a5 -- device pointer
  332. ; a6 -- Exec base
  333.  
  334. InitRoutine:
  335.     PUTDEBUG    5,<'%s/Init: called'>
  336.     movem.l    d1-d7/a0-a6,-(sp)    ;Preserve ALL modified registers
  337.  
  338.     movea.l    d0,a5
  339.     move.l    a6,(md_SysLib,a5)    ;Save a pointer to exec
  340.     move.l    a0,(md_SegList,a5) ;Save pointer to our loaded code
  341.  
  342. ;Check for presence/absence of the 2 serial chips
  343.     moveq    #0,d0
  344.     moveq    #0,d1
  345.     move.l    #ACIA_Base,a4
  346.     move.b    #$83,(FMR,a4)
  347.     move.b    (CSR,a4),d2
  348.     and.b    #3,d2
  349.     cmp.b    #3,d2
  350.     bne.b    .Chip2
  351.     move.b    #$80,(FMR,a4)
  352.     move.b    (CSR,a4),d2
  353.     and.b    #3,d2
  354.     bne.b    .Chip2
  355.     moveq    #-1,d0
  356. .Chip2:
  357.     move.l    #ACIA_Base+ACIA1,a4
  358.     move.b    #$83,(FMR,a4)
  359.     move.b    (CSR,a4),d2
  360.     and.b    #3,d2
  361.     cmp.b    #3,d2
  362.     bne.b    .Done
  363.     move.b    #$80,(FMR,a4)
  364.     move.b    (CSR,a4),d2
  365.     and.b    #3,d2
  366.     bne.b    .Done
  367.     moveq    #-1,d1
  368.  
  369. .Done:
  370.     move.w    d0,(Chip1present,a5)
  371.     move.w    d1,(Chip2present,a5)
  372.  
  373. ;Take over level 6 autovector (nasty, but justified)
  374.     clr.l    (VectorBase,a5)
  375.     tst.w    (AttnFlags,a6)
  376.     beq.b    .skipvbr
  377.  
  378.     SYS    SuperState
  379.     movec    vbr,a2
  380.     bsr    MyUserState
  381.  
  382.     move.l    a2,(VectorBase,a5)
  383. .skipvbr:
  384.     move.l    (VectorBase,a5),a0
  385.     move.l    ($78,a0),(OldVec)
  386.     move.l    #Int0000,($78,a0)
  387.     move.l    #Int0000,(MyPreviousAutoVec,a5)
  388.     move.l    a5,a6
  389.     bsr    SetDefaultPrefs
  390.     move.l    (4).w,a6
  391.  
  392. ;Try to find the prefs in memory
  393.     lea    (MagicPortName,pc),a1
  394.     SYS    FindPort
  395.     tst.l    d0
  396.     beq    .EndInit    ;use hard-coded defaults
  397.     move.l    d0,a0
  398.     lea    (MP_SIZE,a0),a3
  399.     move.l    a5,a6
  400.     lea    (prefs_unit0,a6),a2
  401.  
  402.     moveq    #3,d7    ;4 units
  403.     moveq    #0,d5
  404.  
  405. .OuterLoop:
  406.     move.l    d5,d6
  407.     lsl.w    #3,d6    ;Convert unit # to index
  408.     move.l    a3,a1
  409.     lea    (a1,d6.w),a1    ;UnitPrefs for this unit
  410. .PrefsLoop:
  411.     moveq    #0,d0
  412.     move.w    #512,d0
  413.     moveq    #0,d1
  414.     move.w    (up_BufSize,a1),d1 ;0-7
  415.     lsl.l    d1,d0
  416.     move.l    d0,(prefs_RBUFLEN,a2)
  417.  
  418.     lea    (baudtable,pc),a0
  419.     move.w    (up_BaudRate,a1),d0 ;0-15
  420.     add.w    d0,d0
  421.     moveq    #0,d1
  422.     move.w    (a0,d0.w),d1
  423.     move.l    d1,(prefs_BAUD,a2)
  424.  
  425.     moveq    #5,d1    ;5 bit word
  426.     move.b    (up_WordLen,a1),d0
  427.     beq.b    .WordLen    ;up_WordLen=0
  428.     addq.b    #1,d1    ;6 bit word
  429.     subq.b    #1,d0
  430.     beq.b    .WordLen    ;up_WordLen=1
  431.     addq.b    #1,d1    ;7 bit word
  432.     subq.b    #1,d0
  433.     beq.b    .WordLen    ;up_WordLen=2
  434.     addq.b    #1,d1    ;8 bit word
  435. .WordLen:
  436.     move.b    d1,(prefs_READLEN,a2)
  437.     move.b    d1,(prefs_WRITELEN,a2)
  438.  
  439.     move.b    (up_StopBits,a1),d0 ;0-1
  440.     addq.b    #1,d0
  441.     move.b    d0,(prefs_STOPBITS,a2)
  442.  
  443.     move.b    (up_Parity,a1),d0
  444.     cmp.b    #4,d0    ;none?
  445.     beq.b    .SkipParity
  446.     bset    #SERB_PARTY_ON,(prefs_SERFLAGS,a2)
  447.     cmp.b    #2,d0
  448.     bcc.b    .MarkSpace
  449.     bclr    #SERB_PARTY_ODD,(prefs_SERFLAGS,a2)    ;set to even
  450.     tst.b    d0
  451.     bne.b    .SkipParity
  452.     bset    #SERB_PARTY_ODD,(prefs_SERFLAGS,a2)    ;set to odd
  453.     bra.b    .SkipParity
  454. .MarkSpace:
  455.     bset    #SEXTB_MSPON,(3+prefs_EXTFLAGS,a2)
  456.     bclr    #SEXTB_MARK,(3+prefs_EXTFLAGS,a2)    ;set to space
  457.     cmp.b    #3,d0
  458.     beq.b    .SkipParity
  459.     bset    #SEXTB_MARK,(3+prefs_EXTFLAGS,a2)
  460.  
  461. .SkipParity:
  462.     move.b    (up_Shake,a1),d0
  463.     cmp.b    #2,d0
  464.     beq.b    .SkipShake
  465.     cmp.b    #1,d0
  466.     bne.b    .SkipXon
  467.     bclr    #SERB_XDISABLED,(prefs_SERFLAGS,a2)
  468.     bra.b    .SkipShake
  469. .SkipXon:
  470.     bset    #SERB_7WIRE,(prefs_SERFLAGS,a2)
  471. .SkipShake:
  472.     addq.l    #1,d5
  473.     add.w    #serprefs_sizeof,a2
  474.     dbra    d7,.OuterLoop
  475.  
  476. .EndInit:
  477.     move.l    a5,d0    ;no error (zero indicates error)
  478.             ;MUST return device ptr
  479.     PUTDEBUG    5,<'%s/Init: finished'>
  480.     movem.l    (sp)+,d1-d7/a0-a6
  481.     rts
  482.  
  483. MagicPortName:    dc.b    'newser_prefs',0
  484.     even
  485.  
  486. MyUserState:
  487. ;(The one in 1.2/1.3 ROM is buggy)
  488. ;Enter with ExecBase in A6 and SSP in D0
  489.     move.l    (sp)+,d1
  490.     move.l    sp,usp
  491.     movea.l    d0,sp
  492.     movea.l    a5,a0
  493.     lea    (.L1,pc),a5
  494.     jmp    (_LVOSupervisor,a6)
  495. .L1:    movea.l    a0,a5
  496.     move.l    d1,(2,sp)    ;store return address in stack frame
  497.     andi.w    #$DFFF,(sp)    ;clear supervisor bit
  498.     rte
  499.  
  500. ;Enter with device ptr in a6.
  501.  
  502. SetDefaultPrefs:
  503.     movem.l    d0/d1/a0/a1,-(sp)
  504.     lea    (prefs_unit0,a6),a1
  505.     moveq    #MD_NUMUNITS-1,d1
  506. 1$    move.w    #serprefs_sizeof-1,d0
  507.     lea    (defaultprefs,pc),a0
  508. 2$    move.b    (a0)+,(a1)+
  509.     dbra    d0,2$
  510.     dbra    d1,1$
  511.     movem.l    (sp)+,d0/d1/a0/a1
  512.     rts
  513.  
  514. NewVector:
  515. ;Enter with device ptr in a6
  516. ;exit with d0=0 if OK, else error!
  517.  
  518. ;uses d0,a0,a1
  519.  
  520.     movem.l    a0/a1,-(sp)
  521.     move.l    (VectorBase,a6),a1
  522.     move.l    (MyPreviousAutoVec,a6),d0
  523.     cmp.l    ($78,a1),d0
  524.     bne.b    .Error
  525.  
  526.     moveq    #0,d0
  527.     move.b    (ScoreBoard,a6),d0
  528.     lsl.l    #2,d0
  529.     lea    (IntRoutines,pc),a0
  530.     move.l    (a0,d0.w),(MyPreviousAutoVec,a6)
  531.     move.l    (a0,d0.w),($78,a1)
  532.     moveq    #0,d0
  533. .End:
  534.     movem.l    (sp)+,a0/a1
  535.     rts
  536. .Error:
  537.     moveq    #1,d0
  538.     bra.b    .End
  539.  
  540. ;Here begins the system interface commands.  When the user calls OpenDevice/
  541. ;CloseDevice/RemDevice, this eventually gets translated into a call to the
  542. ;following routines (Open/Close/Expunge).  Exec has already put our device
  543. ;pointer in a6 for us.
  544. ;
  545. ;Open sets the IO_ERROR field on an error. If it was successful, we should
  546. ;also set up the IO_UNIT and LN_TYPE fields.  exec takes care of setting up
  547. ;IO_DEVICE.
  548. ;
  549. ;NOTE: We must also copy the current prefs for this unit into the user's
  550. ;extended iorequest fields.
  551. ;
  552. ; Register Usage
  553. ; ==============
  554. ; d0 -- unitnum
  555. ; d1 -- flags
  556. ; a1 -- iob
  557. ; a6 -- Device ptr
  558.  
  559. Open:
  560.     addq.w    #1,(LIB_OPENCNT,a6) ;Fake an opener for duration of call
  561.     PUTDEBUG    20,<'%s/Open: called'>
  562.     movem.l    d2/a2-a4,-(sp)
  563.     movea.l    a1,a2    ;Save the iob
  564.     cmp.l    #MD_NUMUNITS,d0    ;See if the unit number is in range
  565.     bcc    Open_Range_Error    ;Unit number out of range (BHS)
  566.  
  567. ;Check to see if the corresponding chip is installed
  568.     lea    (Chip1present,a6),a4
  569.     tst.b    (a4,d0.w)
  570.     beq    Open_Range_Error
  571.  
  572.     move.l    d0,d2    ;Save unit number
  573.     lsl.l    #2,d0    ;See if the unit is already initialized
  574.     lea    (md_Units,a6,d0.l),a4
  575.     move.l    (a4),d0
  576.     bne.b    Open_UnitOK
  577.                 ;Try to conjure up a unit
  578.     bsr    InitUnit    ;scratch:a3 unitnum:d2 devpoint:a6
  579.     move.l    (a4),d0    ;See if it initialized OK
  580.     beq.w    Open_Error
  581.     movea.l    d0,a3
  582.     bra.b    Open_UnitOK1
  583.  
  584. Open_UnitOK:
  585.     movea.l    d0,a3    ;Unit pointer in a3
  586.     tst.b    (Exclusive,a3)    ;Check for an exclusive access violation
  587.     beq    Open_Error
  588. Open_UnitOK1:
  589.     btst    #SERB_SHARED,(IO_FLAGS,a2)
  590.     seq    (Exclusive,a3)
  591.     movea.l    (mdu_prefs,a3),a4    ;Set the "7WIRE" flag
  592.  
  593.     bclr    #SERB_7WIRE,(prefs_SERFLAGS,a4)
  594.     btst    #SERB_7WIRE,(IO_SERFLAGS,a2)
  595.     beq.b    2$
  596.     bset    #SERB_7WIRE,(prefs_SERFLAGS,a4)
  597.  
  598. 2$:    movea.l    a2,a1    ;Copy the current internal prefs into the iorequest.
  599.     bsr    CopyPrefs
  600.     move.l    d0,(IO_UNIT,a2)
  601.     addq.w    #1,(LIB_OPENCNT,a6)  ;Mark us as having another opener
  602.     addq.w    #1,(UNIT_OPENCNT,a3) ;Internal bookkeeping
  603.     bclr    #LIBB_DELEXP,(md_Flags,a6) ;Prevent delayed expunges
  604.     clr.b    (IO_ERROR,a2)    ;no error
  605.     move.b    #NT_REPLYMSG,(LN_TYPE,a2) ;Mark IORequest as "complete"
  606. Open_End:
  607.     subq.w    #1,(LIB_OPENCNT,a6) ;End of expunge protection
  608.     movem.l    (sp)+,d2/a2-a4
  609.     PUTDEBUG 30,<'%s/Open: Finished!'>
  610.     rts
  611.  
  612. Open_Range_Error:
  613. Open_Error:
  614.     moveq    #IOERR_OPENFAIL,d0
  615.     move.b    d0,(IO_ERROR,a2)
  616.     move.l    d0,(IO_DEVICE,a2)    ;Trash IO_DEVICE on open failure
  617.     PUTDEBUG    2,<'%s/Open: failed'>
  618.     bra.b    Open_End
  619.  
  620. ;Copy prefs from our device struct to an IOrequest.  Enter with IORequest
  621. ;in a1 and unit pointer in a3.  All registers are preserved.
  622.  
  623. CopyPrefs:
  624.     movem.l    d0/a1/a4,-(sp)
  625.     movea.l    (mdu_prefs,a3),a4
  626.     lea    (IO_CTLCHAR,a1),a1
  627.     move.w    #serprefs_sizeof-1,d0
  628. 1$:    move.b    (a4)+,(a1)+
  629.     dbra    d0,1$
  630.     movem.l    (sp)+,d0/a1/a4
  631.     rts 
  632.  
  633. ;Copy prefs from an IOrequest to our device struct Enter with IORequest
  634. ;in a1 and unit pointer in a3.  All registers are preserved.
  635.  
  636. SetPrefs:
  637.     movem.l    d0/a1/a4,-(sp)
  638.     movea.l    (mdu_prefs,a3),a4
  639.     lea    (IO_CTLCHAR,a1),a1
  640.     move.w    #serprefs_sizeof-1,d0
  641. 1$:    move.b    (a1)+,(a4)+
  642.     dbra    d0,1$
  643.     movem.l    (sp)+,d0/a1/a4
  644.     rts 
  645.  
  646. ;There are two different things that might be returned from the Close
  647. ;routine.  If the device wishes to be unloaded, then Close must return
  648. ;the segment list (as given to Init).  Otherwise close MUST return NULL.
  649. ; ( device:a6, iob:a1 )
  650.  
  651. _Close:
  652.     movem.l    a2-a3,-(sp)
  653.     PUTDEBUG    20,<'%s/Close: called'>
  654.     movea.l    a1,a2
  655.     movea.l    (IO_UNIT,a2),a3
  656.     moveq    #-1,d0
  657.     move.l    d0,(IO_UNIT,a2)      ;We're closed...
  658.     move.l    d0,(IO_DEVICE,a2)    ;Customers not welcome at this IORequest!
  659.     subq.w    #1,(UNIT_OPENCNT,a3) ;See if the unit is still in use
  660.     bne.b    Close_Device
  661.     bsr    ExpungeUnit
  662.  
  663. Close_Device:
  664.     moveq    #0,d0
  665.     subq.w    #1,(LIB_OPENCNT,a6) ;Mark us as having one fewer openers
  666.     bne.b    Close_End     ;See if there is anyone left with us open
  667.     btst    #LIBB_DELEXP,(md_Flags,a6) ;See if we have a delayed expunge pending
  668.     beq.b    Close_End
  669.     bsr    Expunge    ;Do the expunge
  670. Close_End:
  671.     movem.l    (sp)+,a2-a3
  672.     PUTDEBUG    20,<'%s/Close: Finished!'>
  673.     rts        ;MUST return either zero or the SegList!
  674.  
  675. ;Expunge is called by the memory allocator when the system is low on
  676. ;memory.
  677. ;
  678. ;There are two different things that might be returned from the Expunge
  679. ;routine.  If the device is no longer open then Expunge may return the
  680. ;segment list (as given to Init).  Otherwise Expunge may set the
  681. ;delayed expunge flag and return NULL.
  682. ;
  683. ;One other important note: because Expunge is called from the memory
  684. ;allocator, it may NEVER Wait() or otherwise take long time to complete.
  685. ;
  686. ; A6          - library base (scratch)
  687. ; D0-D1/A0-A1 - scratch
  688.  
  689. Expunge:
  690.     PUTDEBUG    10,<'%s/Expunge: called'>
  691.     movem.l    d1/d2/a5/a6,-(sp)    ;Save ALL modified registers
  692.     movea.l    a6,a5
  693.     movea.l    (md_SysLib,a5),a6
  694.     tst.w    (LIB_OPENCNT,a5)    ;See if anyone has us open
  695.     beq.b    1$
  696.     bset    #LIBB_DELEXP,(md_Flags,a5)    ;Set the delayed expunge flag
  697.     moveq    #0,d0
  698.     bra.b    Expunge_End
  699. 1$:
  700.  
  701. ;Important: If it's not possible to restore the old autovector, then don't
  702. ;expunge!!
  703. ;Restore old autovector if possible
  704.     move.l    (MyPreviousAutoVec,a5),a0
  705.     move.l    (VectorBase,a5),a1
  706.     cmp.l    ($78,a1),a0
  707.     beq.b    .ok
  708.     moveq    #0,d0
  709.     bra.b    Expunge_End
  710. .ok:
  711.     move.l    (OldVec,pc),($78,a1)
  712.  
  713.     move.l    (md_SegList,a5),d2 ;Store our seglist in d2
  714.     movea.l    a5,a1     ;Unlink from device list
  715.     SYS    Remove     ;Remove first (before FreeMem)
  716.  
  717.     movea.l    a5,a1     ;Devicebase
  718.     moveq    #0,d0
  719.     move.w    (LIB_NEGSIZE,a5),d0
  720.     suba.l    d0,a1    ;Calculate base of functions
  721.     add.w    (LIB_POSSIZE,a5),d0 ;Calculate size of functions + data area
  722.     SYS    FreeMem
  723.     move.l    d2,d0    ;Set up our return value
  724. Expunge_End:
  725.     movem.l    (sp)+,d1/d2/a5/a6
  726.     rts
  727.  
  728. Null:    moveq    #0,d0    ;The "Null" function MUST return zero.
  729.     rts
  730.  
  731. ;This is the main unit initialization routine. It allocates memory for
  732. ;the device structure, calls SetUpUnit, then calls InitTask.
  733.  
  734. ; ( d2:unit number, a3:scratch, a6:devptr )
  735.  
  736. InitUnit:
  737.     PUTDEBUG    30,<'%s/InitUnit: called'>
  738.     movem.l    d0/d1/a4/a2,-(sp)
  739.     move.l    d2,d1
  740.     mulu.w    #serprefs_sizeof,d1
  741.     lea    (prefs_unit0,a6),a4
  742.     adda.l    d1,a4
  743.  
  744. ;Now A4 is a ptr to the prefs for this unit
  745.  
  746.     move.l    #MyDevUnit_Sizeof,d0 ;Allocate unit memory
  747.     move.l    #MEMF_PUBLIC!MEMF_CLEAR,d1
  748.     move.l    a6,-(sp)
  749.     movea.l    (md_SysLib,a6),a6
  750.     SYS    AllocMem
  751.     movea.l    (sp)+,a6
  752.     movea.l    d0,a3
  753.     tst.l    d0
  754.     bne    continitunit1
  755.  
  756. ;Couldn't init the unit (out of memory).
  757.  
  758. ReturnVoid:
  759.     move.l    d2,d0    ;Unit number
  760.     lsl.l    #2,d0
  761.     clr.l    (md_Units,a6,d0.l) ;Set unit table
  762.     movem.l    (sp)+,d0/d1/a4/a2
  763.     rts
  764.  
  765. BadSetup:
  766.     bsr    KillTask
  767.     bra.b    ReturnVoid
  768.  
  769. continitunit1:
  770.     moveq    #0,d0    ;Don't need to re-zero it
  771.     movea.l    a3,a2
  772.     lea    (mdu_Init,pc),a1
  773.     move.l    a6,-(sp)
  774.     movea.l    (md_SysLib,a6),a6
  775.     SYS    InitStruct
  776.     movea.l    (sp)+,a6
  777.  
  778.     move.l    a5,-(sp)    ;Look up DACIA base address
  779.     lea    (basetable,pc),a0
  780.     moveq    #0,d0
  781.     move.b    d2,d0
  782.     lsl.l    #2,d0
  783.     movea.l    (0,a0,d0.w),a5 
  784.     move.l    a5,(daciabase,a3)
  785.  
  786.     move.b    #$7f,(IER,a5)     ;Disable DACIA interrupts
  787.  
  788.     bset    d2,(ScoreBoard,a6)
  789.     bsr    SetUpUnit
  790.     movea.l    (sp)+,a5
  791.     tst.l    d0
  792.     bne.b    BadSetup
  793.  
  794.     bsr    InitTask    ;Set up the two tasks for this unit
  795.     tst.l    d0
  796.     beq.b    BadSetup
  797.  
  798. ;Done with InitUnit - fill in the proper md_Unit field in the device struct
  799. ;and return.
  800.     move.l    d2,d0    ;Unit number
  801.     lsl.l    #2,d0
  802.     move.l    a3,(md_Units,a6,d0.l) ;Set unit table
  803.     lea    (Unit0,pc),a2
  804.     move.l    a3,(a2,d0.l)
  805.     movem.l    (sp)+,d0/d1/a4/a2
  806.     PUTDEBUG    30,<'%s/InitUnit: finished! End of silence.'>
  807.     rts
  808.  
  809. ;This routine does the following:
  810. ;
  811. ;1. Allocate read buffer memory
  812. ;2. Initialize all the special MyDevUnit fields (but NOT the signals -
  813. ;   they must be allocated in the task's context)
  814. ;3. Call InitDACIA [Initialize/set-up DACIA registers (for this unit).]
  815. ;4. Install an interrupt server.
  816. ;
  817. ;Returns failure code in d0 - zero if OK, -1 if out of memory, 1 if
  818. ;unable to open timer.device, 2 if invalid parm
  819. ;
  820. ;SetUpUnit(d2:unit number, a3:unit, a6:devptr)
  821. ;AND...ptr to prefs in A4
  822. ;uses d1,a0,a1,a2,a6
  823.  
  824. SetUpUnit:
  825.     PUTDEBUG    30,<'%s/SetUpUnit: called'>
  826.     movem.l    d1/a0/a1/a2,-(sp)
  827.  
  828.     move.l    #65536,d0    ;buffer size
  829.     move.l    d0,(prefs_RBUFLEN,a4)
  830.  
  831.     move.l    #MEMF_PUBLIC,d1
  832.     EXEC    AllocMem
  833.     tst.l    d0
  834.     bne.b    continitunit
  835.     moveq    #-1,d0    ;Failed to allocate input buffer memory - exit.
  836.     movem.l    (sp)+,d1/a0/a1/a2
  837.     rts
  838.  
  839. ;Initialize all the special MyDevUnit fields (but NOT the signals -
  840. ;they must be allocated in the task's context)
  841.  
  842. continitunit:
  843.     move.l    d0,(StartBuf,a3)
  844.     clr.l    (HeadLong,a3)
  845.     clr.l    (TailLong,a3)
  846.  
  847.     move.l    a4,(mdu_prefs,a3)
  848.     move.l    (SysBase).w,(mdu_SysLib,a3) 
  849.     lea    (timerport+MP_MSGLIST,a3),a0
  850.     NEWLIST    a0         ;Init the unit's timer MsgPort's list
  851.     move.b    d2,(mdu_UnitNum,a3)    ;Initialize unit number
  852.     move.l    a6,(mdu_Device,a3)     ;Initialize device pointer
  853.     move.b    #$FF,(xstate,a3)
  854.     move.b    #$80,(frstate,a3)
  855.     bset    #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
  856.  
  857.     lea    (timername,pc),a0    ;Open the timer device.
  858.     moveq    #UNIT_MICROHZ,d0
  859.     lea    (timeriorequest,a3),a1
  860.     moveq    #0,d1 ;no special flags
  861.     move.l    a6,-(sp)
  862.     movea.l    (md_SysLib,a6),a6
  863.     SYS    OpenDevice
  864.     movea.l    (sp)+,a6
  865.     tst.l    d0
  866.     bne    OpenTimerFailed
  867.  
  868. ;Initialize/set-up DACIA registers (for this unit).
  869. ;(according to the prefs pointed to by a4) 
  870.  
  871.     bsr    InitDACIA
  872.     tst.l    d0
  873.     bne    InitDACIAfailed 
  874.  
  875. ;Install an interrupt server.
  876.  
  877.     bsr    NewVector
  878.     tst.l    d0
  879.     bne.b    EndSetUpUnit
  880.  
  881.     moveq    #0,d0 ;situation under control
  882.     movem.l    (sp)+,d1/a0/a1/a2
  883.     PUTDEBUG    30,<'%s/SetUpUnit: Finished!'>
  884.     rts
  885.  
  886. InitDACIAfailed:
  887.     moveq    #2,d0
  888.     bra.b    EndSetUpUnit
  889.  
  890. OpenTimerFailed:
  891.     moveq    #1,d0
  892. EndSetUpUnit:
  893.     move.l    d0,-(sp)
  894.     move.l    (prefs_RBUFLEN,a4),d0
  895.     movea.l    (StartBuf,a3),a1
  896.     EXEC    FreeMem
  897.     move.l    (sp)+,d0
  898.     movem.l    (sp)+,d1/a0/a1/a2
  899.     rts
  900.  
  901. ;****** end of SetUpUnit ******
  902.  
  903. ;Initialize/set-up DACIA registers (for this unit).
  904. ;(according to the prefs pointed to by a4) 
  905. ;d0.b will mirror CTR, d1.b will mirror FMR
  906. ;Returns error code in d0 - zero if successful.
  907. ;uses d1,d3,d5,a0
  908.  
  909. InitDACIA:
  910.     PUTDEBUG    30,<'%s/InitDACIA: Called.'>
  911.     movem.l    d1/d3/d5/a0,-(sp)
  912.  
  913. ;"During power-on initialization, all readable registers should be read to
  914. ; assure that the status registers are initialized."
  915.  
  916.     move.b    (ISR,a5),d0
  917.     move.b    (CSR,a5),d0
  918.     move.b    (RDR,a5),d0
  919.  
  920.     move.b    (frstate,a3),d0    ;Set DTR* and RTS* low (assert)
  921.     and.b    #$FC,d0    ;Clear bits zero and one
  922.     move.b    d0,(frstate,a3)
  923.     move.b    d0,(FMR,a5)
  924.  
  925.     moveq    #0,d0
  926.     bset    #6,d0    ;Always access ACR, never CDR
  927.     move.b    (frstate,a3),d1
  928.   
  929.     move.l    (prefs_BAUD,a4),d3 ;First, set proper baud rate.
  930.  
  931.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  932.     move.l    d3,-(sp)
  933.     PUTDEBUG    150,<'%s/InitDACIA: %ldbps requested.'>
  934.     addq.l    #4,sp
  935.     endc
  936.  
  937.     swap    d3
  938.     tst.w    d3
  939.     bne    InvParm
  940.     swap    d3
  941.  
  942. ;Test for (and allow) zero baud -- this makes Handshake happy
  943. ;(Not a bug in Handshake.)  Old RKMs mentioned this behavior, but the
  944. ;latest RKMs do not. Argh!
  945.  
  946.     tst.l    d3
  947.     beq.b    SkipBAUD
  948.  
  949.     lea    (baudtable,pc),a0
  950.     moveq    #15,d5 
  951. baudloop:    cmp.w    (a0)+,d3
  952.     dbeq    d5,baudloop
  953.     bne    InvParm
  954.     not.b    d5
  955.     and.b    #$0F,d5
  956.     or.b    d5,d0    
  957.  
  958.     ifne    INFO_LEVEL
  959.     clr.l    -(sp)
  960.     move.b    d0,(3,sp)
  961.     PUTDEBUG    30,<'%s/InitDACIA: Baud rate = %lx'>
  962.     addq.l    #4,sp
  963.     endc
  964.  
  965. SkipBAUD:
  966.     cmpi.b    #1,(prefs_STOPBITS,a4) ;Next, set number of stop bits per character
  967.     beq.b    onestop
  968.     bset    #5,d0
  969. onestop:
  970.     move.b    d0,(CTR,a5)
  971.  
  972. ;set data bits per character
  973.     move.b    (prefs_READLEN,a4),d3
  974.     cmp.b    (prefs_WRITELEN,a4),d3
  975.     bne    InvParm    ;We don't support different read & write char lengths
  976.     subq.b    #5,d3
  977.     bmi    InvParm
  978.     cmp.b    #3,d3
  979.     bhi    InvParm
  980.     lsl.b    #5,d3
  981.     and.b    #$80,d1    ;bug fix (clear before OR)
  982.     or.b    d3,d1
  983.  
  984.     btst    #SEXTB_MSPON,(prefs_EXTFLAGS+3,a4) ;Set parity
  985.     beq.b    EvenOdd
  986.     bset    #2,d1
  987.     btst    #SEXTB_MARK,(prefs_EXTFLAGS+3,a4)
  988.     bne.b    UseMark
  989.     or.b    #24,d1    ;Use space
  990.     bra.b    NoParity
  991.  
  992. UseMark:    or.b    #16,d1
  993.     bra.b    NoParity
  994.  
  995. EvenOdd:    btst    #SERB_PARTY_ON,(prefs_SERFLAGS,a4)
  996.     beq.b    NoParity
  997.     bset    #2,d1
  998.  
  999.     btst    #SERB_PARTY_ODD,(prefs_SERFLAGS,a4)
  1000.     bne.b    UseOdd
  1001.     or.b    #8,d1
  1002. UseOdd:
  1003. NoParity:
  1004.  
  1005.     ifne    INFO_LEVEL
  1006.     clr.l    -(sp)
  1007.     move.b    d1,(3,sp)
  1008.     PUTDEBUG    30,<'%s/InitDACIA: FMR = %lx'>
  1009.     addq.l    #4,sp
  1010.     endc
  1011.  
  1012.     move.b    d1,(frstate,a3)
  1013.     move.b    d1,(FMR,a5)
  1014.     moveq    #0,d0
  1015.     movem.l    (sp)+,d1/d3/d5/a0
  1016.     PUTDEBUG    30,<'%s/InitDACIA: Finished!'>
  1017.     rts
  1018.  
  1019. InvParm:    PUTDEBUG    30,<'%s/InitDACIA: Invalid Parm!'>
  1020.     moveq    #-1,d0
  1021.     movem.l    (sp)+,d1/d3/d5/a0
  1022.     rts
  1023.  
  1024. ;****** end of InitDACIA ******
  1025.  
  1026. ;(this is a subroutine for InitUnit)
  1027. ;This routine sets up the two tasks (one for reading, one for writing).
  1028. ;Returns zero in d0.l if an error occured else a ptr to the unit.
  1029. ;
  1030. ;uses d1-d4 and a0-a5
  1031.  
  1032. InitTask:
  1033.     PUTDEBUG    30,<'%s/InitTask: called.'>
  1034.     movem.l    d1-d4/a0-a5,-(sp)
  1035.     lea    (ReadTask_Begin,pc),a5 ;Set up the read task
  1036.     lea    (mdu_rstack,a3),a0
  1037.     lea    (mdu_rtcb,a3),a1
  1038.     movea.l    a3,a2    ;Read message port
  1039.     bsr.b    InitTaskStruct
  1040.  
  1041.     lea    (WriteTask_Begin,pc),a5 ;Set up the write task
  1042.     lea    (mdu_wstack,a3),a0
  1043.     lea    (mdu_wtcb,a3),a1
  1044.     lea    (mdu_wport,a3),a2
  1045.     bsr.b    InitTaskStruct
  1046.  
  1047.     move.l    a3,d0    ;Mark us as ready to go
  1048.     PUTDEBUG    30,<'%s/InitTask: ok'>
  1049.  
  1050. ;Return zero in d0.l if an error occured, else a ptr to the unit
  1051.  
  1052.     movem.l    (sp)+,d1-d4/a0-a5
  1053.     rts
  1054.  
  1055. ;Start up the unit task.  We do a trick here --we set his message port to
  1056. ;PA_IGNORE until the new task has a change to set it up.  We cannot go to
  1057. ;sleep here: it would be very nasty if someone else tried to open the unit
  1058. ;(exec's OpenDevice has done a Forbid() for us --we depend on this to become
  1059. ;single threaded).
  1060. ;
  1061. ;Enter with:
  1062. ;a0 - ptr to low end of stack
  1063. ;a1 - ptr to tcb (task control block)
  1064. ;a3 - unit pointer
  1065. ;a5 - starting address of task
  1066. ;a2 - ptr to a (uninitialized) message port
  1067. ;
  1068. ;uses a0-a3 and d0,d1
  1069.  
  1070. InitTaskStruct:
  1071.     movem.l    d0/d1/a0-a3,-(sp)
  1072.     move.l    a0,(TC_SPLOWER,a1)    ;Initialize the stack information
  1073.     lea    (MYPROCSTACKSIZE,a0),a0 ;High end of stack
  1074.     move.l    a0,(TC_SPUPPER,a1)
  1075.     move.l    a3,-(a0)    ;Argument - unit ptr (send on stack)
  1076.     move.l    a0,(TC_SPREG,a1)
  1077.     move.l    a1,(MP_SIGTASK,a2)
  1078.  
  1079.     ifge    INFO_LEVEL-30
  1080.     move.l    a1,-(sp)
  1081.     move.l    a3,-(sp)
  1082.     PUTDEBUG    30,<'%s/InitUnit, unit= %lx, task=%lx'>
  1083.     addq.l    #8,sp
  1084.     endc
  1085.  
  1086.     lea    (MP_MSGLIST,a2),a0
  1087.     NEWLIST    a0    ;Init the unit's MsgPort's list
  1088.     movea.l    a5,a2    ;Startup the task
  1089.     move.w    #-1,a3    ;generate address error
  1090.             ;if task ever "returns" (we RemTask() it
  1091.             ;to get rid of it...)
  1092.     moveq    #0,d0
  1093.     PUTDEBUG    30,<'%s/About to add task'>
  1094.     move.l    a6,-(sp)
  1095.     movea.l    (md_SysLib,a6),a6
  1096.     SYS    AddTask
  1097.     movea.l    (sp)+,a6
  1098.     movem.l    (sp)+,d0/d1/a0-a3
  1099.     rts
  1100.  
  1101. ;Get rid of the unit's tasks.  We know this is safe because the unit has an
  1102. ;open count of zero, so it is 'guaranteed' not in use.
  1103. ;
  1104. ;Kill the two tasks
  1105. ; ( a3:unitptr, a6:deviceptr )
  1106. ;
  1107. ;uses a0,a1 and d0-d2
  1108.  
  1109. KillTask:
  1110.     movem.l    a0/a1/d0-d2,-(sp)
  1111.     lea    (mdu_rtcb,a3),a1
  1112.     move.l    a6,-(sp)
  1113.     movea.l    (md_SysLib,a6),a6
  1114.     SYS    RemTask
  1115.     movea.l    (sp)+,a6
  1116.  
  1117.     lea    (mdu_wtcb,a3),a1
  1118.     move.l    a6,-(sp)
  1119.     movea.l    (md_SysLib,a6),a6
  1120.     SYS    RemTask
  1121.     movea.l    (sp)+,a6
  1122.  
  1123.     moveq    #0,d2
  1124.     move.b    (mdu_UnitNum,a3),d2 ;Save the unit number
  1125.     bsr    FreeUnit    ;Free the unit structure
  1126.     lsl.l    #2,d2
  1127.     clr.l    (md_Units,a6,d2.l)    ;Clear out the unit vector in the device
  1128.     movem.l    (sp)+,a0/a1/d0-d2
  1129.     rts
  1130.  
  1131. ; ( a3:unitptr, a6:deviceptr )
  1132. ;uses a0,a1,d0,d1
  1133.  
  1134. FreeUnit:
  1135.     movem.l    a0/a1/d0/d1,-(sp)
  1136.     movea.l    a3,a1
  1137.     move.l    #MyDevUnit_Sizeof,d0
  1138.     move.l    a6,-(sp)
  1139.     movea.l    (md_SysLib,a6),a6
  1140.     SYS    FreeMem
  1141.     movea.l    (sp)+,a6
  1142.     movem.l    (sp)+,a0/a1/d0/d1
  1143.     rts
  1144.  
  1145. ; ( a3:unitptr, a6:deviceptr )
  1146. ;
  1147. ;uses a0,a1,a5,d0-d2
  1148.  
  1149. ExpungeUnit:
  1150.     movem.l    a0/a1/a5/d0-d2,-(sp)
  1151.     PUTDEBUG    10,<'%s/ExpungeUnit: called'>
  1152.  
  1153.     movea.l    (daciabase,a3),a5
  1154.     move.b    #$7f,(IER,a5)    ;shut off all interrupts
  1155.     move.b    #$83,(FMR,a5)    ;Deassert DTR* and RTS*
  1156.  
  1157.     bsr    FreeResources
  1158.  
  1159.     lea    (mdu_rtcb,a3),a1
  1160.     move.l    a6,-(sp)
  1161.     movea.l    (md_SysLib,a6),a6
  1162.     SYS    RemTask
  1163.     movea.l    (sp)+,a6
  1164.  
  1165.     lea    (mdu_wtcb,a3),a1
  1166.     move.l    a6,-(sp)
  1167.     movea.l    (md_SysLib,a6),a6
  1168.     SYS    RemTask
  1169.     movea.l    (sp)+,a6
  1170.  
  1171.     moveq    #0,d2
  1172.     move.b    (mdu_UnitNum,a3),d2 ;Save the unit number
  1173.     bsr    FreeUnit    ;Free the unit structure.
  1174.  
  1175.     bclr    d2,(ScoreBoard,a6)
  1176.     bsr    NewVector
  1177.     lsl.l    #2,d2
  1178.     clr.l    (md_Units,a6,d2.l) ;Clear out the unit pointer in the device
  1179.  
  1180.     movem.l    (sp)+,a0/a1/a5/d0-d2
  1181.     rts
  1182.  
  1183. ;This routines frees up resources specific to this driver (the other
  1184. ;resources are taken care of by the skeleton).
  1185. ;Be careful with this routine, so as not to pull the rug out from
  1186. ;underneath the driver...
  1187. ;
  1188. ;Enter with unit ptr in a3 and device ptr in a6
  1189. ;
  1190. ;uses a0,a1,a4,d0,d1
  1191.  
  1192. FreeResources:
  1193.     PUTDEBUG    10,<'%s/FreeResources: called'>
  1194.     movem.l    a0/a1/a4/d0/d1,-(sp)
  1195.     movea.l    (StartBuf,a3),a1    ;Free input buffer memory
  1196.     movea.l    (mdu_prefs,a3),a4
  1197.     move.l    (prefs_RBUFLEN,a4),d0
  1198.     move.l    a6,-(sp)
  1199.     movea.l    (md_SysLib,a6),a6
  1200.     SYS    FreeMem
  1201.     movea.l    (sp)+,a6
  1202.  
  1203.     lea    (timeriorequest,a3),a1 ;Close timer device
  1204.     move.l    a6,-(sp)
  1205.     movea.l    (md_SysLib,a6),a6
  1206.     SYS    CloseDevice
  1207.     movea.l    (sp)+,a6
  1208.     movem.l    (sp)+,a0/a1/a4/d0/d1
  1209.     PUTDEBUG    10,<'%s/FreeResources: finished!'>
  1210.     rts
  1211.  
  1212. ;Here begins the device functions
  1213. ;
  1214. ;Cmdtable is used to look up the address of a routine that will
  1215. ;implement the device command.
  1216.  
  1217. cmdtable:
  1218.     dc.w    Invalid-cmdtable    ;0    CMD_INVALID
  1219.     dc.w    MyReset-cmdtable    ;1    CMD_RESET
  1220.     dc.w    Read-cmdtable    ;2    CMD_READ
  1221.     dc.w    Write-cmdtable    ;3    CMD_WRITE
  1222.     dc.w    Invalid-cmdtable    ;4    CMD_UPDATE (update has no meaning here)
  1223.     dc.w    MyClear-cmdtable    ;5    CMD_CLEAR
  1224.     dc.w    MyStop-cmdtable    ;6    CMD_STOP
  1225.     dc.w    Start-cmdtable    ;7    CMD_START
  1226.     dc.w    Flush-cmdtable    ;8    CMD_FLUSH
  1227.     dc.w    Query-cmdtable    ;9    SDCMD_QUERY
  1228.     dc.w    Break-cmdtable    ;10    SDCMD_BREAK
  1229.     dc.w    SetParams-cmdtable    ;11    SDCMD_SETPARAMS
  1230.     dc.w    Invalid-cmdtable    ;12    not used
  1231.     dc.w    Invalid-cmdtable    ;13    not used
  1232.     dc.w    Invalid-cmdtable    ;14    not used
  1233.     dc.w    Invalid-cmdtable    ;15    not used
  1234.     dc.w    SetControlLines-cmdtable    ;16 - ASDG extension
  1235.  
  1236. ;BeginIO starts all incoming io.  The IO is either queued up for the
  1237. ;unit task or processed immediately.
  1238. ;
  1239. ;BeginIO often is given the responsibility of making devices single
  1240. ;threaded... so two tasks sending commands at the same time don't cause
  1241. ;a problem.  Once this has been done, the command is dispatched.
  1242. ;
  1243. ;Some IO requests do not need single threading. These can be performed
  1244. ;immediatley.
  1245. ;The immediate commands are Invalid, Reset, Stop, Start, Flush, Clear,
  1246. ;Query, SetParams, and SetControlLines.
  1247. ;
  1248. ;IMPORTANT:
  1249. ; The exec WaitIO() function uses the IORequest node type (LN_TYPE)
  1250. ; as a flag.  If set to NT_MESSAGE, it assumes the request is
  1251. ; still pending and will wait.  If set to NT_REPLYMSG, it assumes the
  1252. ; request is finished.  It's the responsibility of the device driver
  1253. ; to set the node type to NT_MESSAGE before returning to the user.
  1254. ;
  1255. ;Notes: This routine looks at IO_COMMAND to determine which task
  1256. ;to use. Break and Write requests go to the write
  1257. ;task. Read requests (only) go to the read task. 
  1258. ;All other requests are performed immediately, i.e. within the caller's
  1259. ;context.
  1260. ;
  1261. ;This routine uses a3,a4,a5 (and a0/a1/d0/d1, but those do not need to be
  1262. ;preserved).
  1263. ; ( iob: a1, device:a6 )
  1264.  
  1265. ;************************** Start of BeginIO ***************************
  1266.  
  1267. BeginIO:
  1268.  
  1269.     movem.l    a3-a5,-(sp)
  1270.  
  1271.     ifge    INFO_LEVEL-1
  1272.     bchg.b    #1,($bfe001).l    ;Blink the power LED
  1273.     endc
  1274.  
  1275.     ifge    INFO_LEVEL-3
  1276.     clr.l    -(sp)
  1277.     move.w    (IO_COMMAND,a1),(2,sp) ;Get entire word
  1278.     PUTDEBUG    3,<'%s/BeginIO  --  %ld'>
  1279.     addq.l    #4,sp
  1280.     endc
  1281.  
  1282.     move.w    (IO_COMMAND,a1),d0
  1283.     cmp.w    #16,d0    ;command in range?
  1284.     bhi    .NoCmd    ;no, reject it.
  1285.  
  1286. ;Do some initial set-up work
  1287.     andi.b    #$f,(IO_FLAGS,a1)    ;clear upper nibble
  1288.     move.b    #NT_MESSAGE,(LN_TYPE,a1) ;So WaitIO() is guaranteed to work
  1289.     movea.l    (IO_UNIT,a1),a3    ;Bookkeeping -> what unit to play with
  1290.     movea.l    (mdu_prefs,a3),a4
  1291.     movea.l    (daciabase,a3),a5
  1292.     clr.b    (IO_ERROR,a1)    ;No error so far
  1293.  
  1294.     cmp.w    #CMD_READ,d0
  1295.     bne    .NotRead
  1296.  
  1297. ;If the task is busy reading, don't read in the caller's context!
  1298.     tst.l    (ReadRequestPtr,a3)
  1299.     bne.b    .ForgetIt
  1300.     lea    (MP_MSGLIST,a3),a0    ;Read port - anything there?
  1301.     movea.l    (a0),a0
  1302.     tst.l    (a0)
  1303.     bne.b    .ForgetIt
  1304.  
  1305. ;Check whether there are enough characters in the buffer to do the read
  1306. ;immediately.
  1307.  
  1308.     btst    #SERB_RAD_BOOGIE,(prefs_SERFLAGS,a4)    ;Check for RAD_BOOGIE
  1309.     beq.b    .ForgetIt
  1310.     bsr    GetBytesInReadBuf
  1311.     cmp.l    (IO_LENGTH,a1),d0
  1312.     blo.b    .ForgetIt
  1313.     bset    #UNITB_READIMMEDIATE,(UNIT_FLAGS,a3)
  1314.     bne.b    .ForgetIt
  1315.     bsr    ReadImmediate
  1316.     bclr    #UNITB_READIMMEDIATE,(UNIT_FLAGS,a3)
  1317.     bra    .ReplyEnd
  1318. .ForgetIt:
  1319.  
  1320. ;Send message to read task
  1321.  
  1322.     move.l    a3,a0
  1323.     bra    .SendMessage
  1324.  
  1325. .NotRead:
  1326.     cmp.w    #CMD_WRITE,d0
  1327.     bne    .NotWrite
  1328.  
  1329.     moveq    #1,d0
  1330.     cmp.l    (IO_LENGTH,a1),d0
  1331.     bne    .QueueForWriteTask
  1332.  
  1333. ;If the write task is busy writing, don't write in the caller's context!
  1334.     tst.l    (WriteRequestPtr,a3)
  1335.     bne    .QueueForWriteTask
  1336.     lea    (mdu_wport+MP_MSGLIST,a3),a0    ;Write port - anything there?
  1337.     movea.l    (a0),a0
  1338.     tst.l    (a0)
  1339.     bne    .QueueForWriteTask
  1340.  
  1341.     btst    #SERB_7WIRE,(prefs_SERFLAGS,a4)
  1342.     bne.b    .Handshake
  1343.     btst    #CSRB_CTSL,(CSR,a5)
  1344.     bne    .QueueForWriteTask
  1345. .Handshake:
  1346.     tst.b    (xstate,a3)
  1347.     beq    .QueueForWriteTask
  1348.  
  1349.     Disable
  1350.     btst    #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
  1351.     beq.b    .NeedInt    ;Enable, then QueueForWriteTask
  1352.     move.l    (IO_DATA,a1),a0
  1353.     move.b    (a0),(TDR,a5)
  1354.     bclr    #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
  1355.     Enable
  1356.     bclr    #UNITB_BREAKSENT,(UNIT_FLAGS,a3)    ;for Query
  1357.     move.l    d0,(IO_ACTUAL,a1)
  1358.     bra.b    .ReplyEnd
  1359.  
  1360. .NotWrite:
  1361.     cmp.w    #SDCMD_BREAK,d0
  1362.     beq.b    .QueueForWriteTask    ;Handle just like a write request
  1363.  
  1364. ;execute immediately
  1365.     lea    (cmdtable,pc),a0
  1366.     add.w    d0,d0
  1367.     add.w    (a0,d0.w),a0
  1368.     jsr    (a0)
  1369.  
  1370. ;If the quick bit is set then we don't need to reply
  1371.  
  1372. .ReplyEnd:
  1373.     btst    #IOB_QUICK,(IO_FLAGS,a1)
  1374.     bne.b    .End
  1375.     push    a6
  1376.     move.l    (4).w,a6
  1377.     SYS    ReplyMsg
  1378.     pop    a6
  1379. .End:    movem.l    (sp)+,a3-a5
  1380.     rts
  1381.  
  1382. .NeedInt:
  1383.     Enable
  1384.  
  1385. .QueueForWriteTask:
  1386. ;Send message to write task
  1387.  
  1388.     lea    (mdu_wport,a3),a0
  1389.  
  1390. .SendMessage:
  1391. ;Send the IO request as a "message" to either the read or write task
  1392. ;Enter with port address in A0 and IORequest in A1
  1393.  
  1394.     bclr    #IOB_QUICK,(IO_FLAGS,a1)    ;We did NOT complete this quickly
  1395.  
  1396.     ifge    INFO_LEVEL-250
  1397.     move.l    a1,-(sp)
  1398.     move.l    a0,-(sp)
  1399.     PUTDEBUG    250,<'%s/PutMsg: Port=%lx Message=%lx'>
  1400.     addq.l    #8,sp
  1401.     endc
  1402.  
  1403.     push    a6
  1404.     movea.l    (md_SysLib,a6),a6
  1405.     SYS    PutMsg    ;Port=a0, Message=a1
  1406.     pop    a6
  1407.     bra    .End
  1408.  
  1409. .NoCmd:
  1410.     PUTDEBUG 200,<'%s/BeginIO_NoCmd!'>
  1411.     move.b    #IOERR_NOCMD,(IO_ERROR,a1)
  1412.     bra    .ReplyEnd
  1413.  
  1414. ;************************* End of BeginIO ****************************
  1415.  
  1416. ;Here begins the functions that implement the device commands
  1417. ;all functions are called with:
  1418. ;  a1 -- a pointer to the io request block
  1419. ;  a3 -- a pointer to the unit
  1420. ;  a4 -- a pointer to prefs
  1421. ;  a5 -- a pointer to the unit hardware
  1422. ;  a6 -- a pointer to the device
  1423. ;
  1424. ;Commands that conflict with 68000 instructions have a "My" prepended to them.
  1425.  
  1426. ;****************************** Read *****************************
  1427.  
  1428. Read:
  1429.     movem.l    d0-d6/a0/a2,-(sp)
  1430.  
  1431. ;Try to do a quick read
  1432.     btst    #SERB_RAD_BOOGIE,(prefs_SERFLAGS,a4)    ;Check for RAD_BOOGIE
  1433.     beq.b    .NoBoogie
  1434.  
  1435.     bsr    GetBytesInReadBuf
  1436.     cmp.l    (IO_LENGTH,a1),d0
  1437.     blo.b    .NotEnoughDataInBuf
  1438.     bsr    ReadImmediate
  1439.     bra    .FinalEndRead
  1440.  
  1441. .NoBoogie:
  1442. .NotEnoughDataInBuf:
  1443.  
  1444.     moveq    #0,d5    ;IO_ACTUAL
  1445.     move.l    (IO_LENGTH,a1),d6
  1446.     movea.l    (IO_DATA,a1),a2
  1447.  
  1448.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  1449.     move.l    d6,-(sp)
  1450.     PUTDEBUG    150,<'%s/Read entered -- %ld bytes requested.'>
  1451.     addq.l    #4,sp
  1452.     endc
  1453.  
  1454.     bra    .ReadEntry
  1455.  
  1456. .ReadLoop:
  1457.     PUTDEBUG    150,<'%s/Read: Waiting for signal from interrupt code.'>
  1458.     move.l    (readsig,a3),d0
  1459.     add.l    (readabortsig,a3),d0
  1460.     bset    #MDUB_WaitingForChar,(MDU_FLAGS,a3)
  1461.     EXEC    Wait    ;Wait for one or more bytes to come in
  1462.     and.l    (readabortsig,a3),d0
  1463.     bne    .ReadAbort
  1464. .NoErrorAtAll:
  1465.     PUTDEBUG    150,<'%s/Read: One or more bytes came in.'>
  1466.  
  1467. .ReadEntry:
  1468.     bsr    GetBytesInReadBuf
  1469.  
  1470.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  1471.     move.l    d0,-(sp)
  1472.     PUTDEBUG    150,<'%s/Read: There are %ld bytes in the buffer.'>
  1473.     addq.l    #4,sp
  1474.     endc
  1475.  
  1476.     tst.l    d0
  1477.     beq    .ReadLoop
  1478.     cmp.l    d0,d6
  1479.     bls.b    .AllDone    ;Branch if d6 <= d0
  1480.     sub.l    d0,d6
  1481.     bsr    DumpReadBuf    ;Dump d0 bytes of the read buffer into the user's buffer
  1482.     tst.l    d0
  1483.     beq    .ReadLoop  
  1484.     bra.b    .EndRead    ;Go if TermArray caused early exit
  1485.  
  1486. ;The number of bytes in the read buffer equals or exceeds the number of
  1487. ;bytes the user wants.
  1488.  
  1489. .AllDone:
  1490.     PUTDEBUG    150,<'%s/Read: All done.'>
  1491.     move.l    d6,d0
  1492.     bsr    DumpReadBuf    ;Dump d0 bytes of the read buffer into the user's buffer
  1493. .EndRead:    PUTDEBUG    150,<'%s/Read: Finished!'>
  1494.  
  1495. ;    bclr    #MDUB_V,(MDU_FLAGS,a3)
  1496. ;    beq.b    NoOverflow
  1497. ;    move.b    #SerErr_BufOverflow,(IO_ERROR,a1)
  1498. ;NoOverflow:
  1499.  
  1500.     move.l    d5,(IO_ACTUAL,a1)
  1501. .FinalEndRead:
  1502.     movem.l    (sp)+,d0-d6/a0/a2
  1503.     rts        ;Done with read
  1504.  
  1505. ;Something exceptional happened.  An informative error code should be
  1506. ;returned.  first, check for error conditions...  Note that the serial.device
  1507. ;standard does not provide a way to inform the caller of simultaneous error
  1508. ;conditions.
  1509.  
  1510. .ReadAbort:
  1511.     PUTDEBUG    150,<'%s/readabort: Something exceptional happened.'>
  1512.     Disable
  1513.     move.b    (ISRcopy,a3),d2
  1514.     move.b    (CSRcopy,a3),d3
  1515.     clr.b    (ISRcopy,a3)
  1516.     clr.b    (CSRcopy,a3)
  1517.     Enable
  1518.     btst    #ISRB_PAR,d2
  1519.     beq.b    .notpar
  1520.  
  1521.     move.b    #SerErr_ParityErr,(IO_ERROR,a1)    ;parity error
  1522.     bra    .EndRead
  1523.  
  1524. .notpar:    btst    #1,d2    ;Check for frame err, overrun, & break
  1525.     beq    .EndRead    ;We infer that an abort has been issued
  1526.  
  1527. ;This is a check for framing error....it might cause problems for
  1528. ;some auto-baud algorithms, so it's commented out for this release.
  1529.  
  1530. ;    btst    #CSRB_FE,d3    ;Probe further...
  1531. ;    beq.b    noframe
  1532.  
  1533. ;    move.b    #SerErr_LineErr,(IO_ERROR,a1)    ;Framing Error
  1534. ;    bra    endread
  1535.  
  1536. .noframe:    btst    #CSRB_RBRK,d3
  1537.     beq    .NoErrorAtAll
  1538.  
  1539. ;Note that we ignore receive overrun errors. Since there is no error
  1540. ;code for it, I assume this is what serial.device does too.
  1541.  
  1542.     move.b    #SerErr_DetectedBreak,(IO_ERROR,a1)    ;Break
  1543.     bra    .EndRead 
  1544.  
  1545. ;****** Subroutines for the read routine ******
  1546.  
  1547. GetBytesInReadBuf:
  1548.  
  1549. ;Return with the number of bytes in the read buffer in d0
  1550.  
  1551.     move.l    d1,-(sp)
  1552.  
  1553.     movem.l    (HeadLong,a3),d0/d1    ;load HeadLong/TailLong
  1554.  
  1555.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  1556.     move.l    d0,-(sp)
  1557.     PUTDEBUG    150,<'%s/GetBytesInReadBuf: HeadLong=%ld'>
  1558.     addq.l    #4,sp
  1559.     endc
  1560.  
  1561.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  1562.     move.l    d1,-(sp)
  1563.     PUTDEBUG    150,<'%s/GetBytesInReadBuf: TailLong=%ld'>
  1564.     addq.l    #4,sp
  1565.     endc
  1566.  
  1567.     sub.l    d0,d1
  1568.     bpl.b    .skipadd
  1569.     add.l    #65536,d1
  1570. .skipadd:
  1571.     move.l    d1,d0
  1572.  
  1573.     move.l    (sp)+,d1
  1574.     rts
  1575.  
  1576. ;Enter with number of bytes to read in d0
  1577. ;Enter with a pointer to a dump buffer in a2
  1578. ;the pointer in a2 is updated to reflect the current position
  1579. ;
  1580. ;This routine uses as scratch: d0,d5,d6,a2
  1581. ;and updates the following: d5,a2
  1582. ;Returns with D0=0 if all is OK, else a TermArray match was found.
  1583.  
  1584. ;This is a subroutine used only by Read
  1585.  
  1586. DumpReadBuf:
  1587.     movem.l    d1/d6/d7/a0/a6,-(sp)
  1588.     move.l    (HeadLong,a3),d1
  1589.     add.w    d0,(Head,a3)
  1590.     move.l    (StartBuf,a3),a0
  1591.  
  1592.     btst    #SERB_RAD_BOOGIE,(prefs_SERFLAGS,a4)
  1593.     bne.b    .Loop
  1594.  
  1595.     btst    #SERB_EOFMODE,(IO_SERFLAGS,a1)
  1596.     beq.b    .XLoop 
  1597.  
  1598. .EOFDump:
  1599.     moveq    #7,d7
  1600.     lea    (prefs_TERMARRAY,a4),a6
  1601.     move.b    (a0,d1.l),d6    ;index MUST be long (sign extended)!
  1602.     btst    #SERB_XDISABLED,(prefs_SERFLAGS,a4)
  1603.     bne.b    .Skip
  1604.     bsr    xcode
  1605. .Skip:    cmp.b    (a6)+,d6
  1606.     dbcc    d7,.Skip
  1607.     beq.b    .TermRead    
  1608.     move.b    d6,(a2)+
  1609.     addq.l    #1,d5
  1610.     addq.w    #1,d1
  1611.     subq.l    #1,d0
  1612.     bne.b    .EOFDump
  1613.     bra.b    .End
  1614.  
  1615. .Loop:
  1616.     move.b    (a0,d1.l),(a2)+    ;index MUST be long (sign extended)!
  1617.     addq.l    #1,d5    ;add to IO_ACTUAL
  1618.     addq.w    #1,d1    ;increment 16-bit head ptr
  1619.     subq.l    #1,d0
  1620.     bne.b    .Loop 
  1621.     bra.b    .End
  1622.  
  1623. .XLoop:
  1624.     move.b    (a0,d1.l),d6    ;index MUST be long (sign extended)!
  1625.     bsr.b    xcode
  1626.     move.b    d6,(a2)+
  1627.     addq.l    #1,d5    ;add to IO_ACTUAL
  1628.     addq.w    #1,d1    ;increment 16-bit head ptr
  1629.     subq.l    #1,d0
  1630.     bne.b    .XLoop 
  1631.     bra.b    .End
  1632.  
  1633. .TermRead:
  1634.     moveq    #-1,d0
  1635.     bra.b    .End1
  1636. .End:
  1637.     moveq    #0,d0
  1638. .End1:
  1639.     movem.l    (sp)+,d1/d6/d7/a0/a6
  1640.     rts
  1641.  
  1642. xcode:
  1643.  
  1644. ;Check for xon/xoff
  1645. ;Enter with current read character in d6.b
  1646.  
  1647.     ifne    INFO_LEVEL
  1648.     move.l    (prefs_CTLCHAR,a4),-(sp)
  1649.     PUTDEBUG    5,<'%s/XCODE: prefs_CTLCHAR = %lx'>
  1650.     addq.l    #4,sp
  1651.     endc
  1652.  
  1653.     ifne    INFO_LEVEL
  1654.     clr.l    -(sp)
  1655.     move.b    d6,(3,sp)
  1656.     PUTDEBUG    5,<'%s/XCODE: Current char = %lx'>
  1657.     addq.l    #4,sp
  1658.     endc
  1659.  
  1660.     cmp.b    (prefs_CTLCHAR,a4),d6    ;Xon check
  1661.     beq.b    .XON
  1662.     cmp.b    (prefs_CTLCHAR+1,a4),d6    ;Xoff check
  1663.     beq.b    .XOFF
  1664.     rts
  1665.  
  1666. .XON:    PUTDEBUG    5,<'%s/XCODE: XON!'>
  1667.     tst.b    (xstate,a3)
  1668.     bne.b    .End    ;If already on, don't signal!
  1669.     st    (xstate,a3)
  1670.     movem.l    d0/d1/a0/a1/a6,-(sp)
  1671.     move.l    (xonsig,a3),d0
  1672.     lea    (mdu_wtcb,a3),a1
  1673.     movea.l    (mdu_SysLib,a3),a6
  1674.     SYS    Signal
  1675.     movem.l    (sp)+,d0/d1/a0/a1/a6
  1676. .End:    rts
  1677.  
  1678. .XOFF:    PUTDEBUG    5,<'%s/XCODE: XOFF!'>
  1679.     clr.b    (xstate,a3)
  1680.     rts
  1681.  
  1682. ReadImmediate:
  1683.  
  1684. ;Fast read routine
  1685. ;Requires boogie mode to be set and for there to be a sufficient number
  1686. ;of bytes in the buffer to completely satisfy the request.
  1687.  
  1688. ;Uses d0,d1,d2,d4,a0,a1,a2,a4,a6
  1689.  
  1690.     movem.l    d0-d2/d4/a0-a2/a4/a6,-(sp)
  1691.     push    a1
  1692.     move.l    (HeadLong,a3),d2
  1693.     move.l    (IO_LENGTH,a1),d4
  1694.     add.w    d4,(Head,a3)
  1695.     move.l    (IO_DATA,a1),a4
  1696.     move.l    (StartBuf,a3),a2
  1697.     move.l    (mdu_SysLib,a3),a6
  1698.  
  1699.     move.l    #65536,d0
  1700.     sub.l    d2,d0
  1701.     cmp.l    d0,d4
  1702.     bls.b    .UseIOLength
  1703.  
  1704. ;Need 2 copy operations
  1705.     sub.l    d0,d4
  1706.     move.l    a4,a1
  1707.     add.l    d0,a4
  1708.     lea    (a2,d2.l),a0
  1709.     SYS    CopyMem
  1710.     move.l    d4,d0
  1711.     move.l    a4,a1
  1712.     move.l    a2,a0
  1713.     SYS    CopyMem
  1714.     bra.b    .ReadQuickEnd
  1715.  
  1716. .UseIOLength:
  1717.     move.l    d4,d0
  1718.     move.l    a4,a1
  1719.     lea    (a2,d2.l),a0
  1720.     SYS    CopyMem
  1721. .ReadQuickEnd:
  1722.     pop    a1
  1723.     move.l    (IO_LENGTH,a1),(IO_ACTUAL,a1)
  1724.     movem.l    (sp)+,d0-d2/d4/a0-a2/a4/a6
  1725.     rts
  1726.  
  1727. ;*************************** Write ******************************
  1728.  
  1729. Write:
  1730.     comment |
  1731. Potential problem: If a TDRE interrupt happens, and just at that instant
  1732. (before the interrupt routine has time to kick into action) CTS is
  1733. deasserted, the interrupt routine will miss the TDRE condition and the
  1734. write routine will hang. This is unlikely, but possible. V2.10 adds
  1735. a time-out feature to avoid this if it ever happens in real life.
  1736. Testing the effectiveness of this solution is difficult, because I am
  1737. solving a problem that has, to my knowledge, never occured. (hehe)
  1738. |
  1739.  
  1740.     movem.l    d0-d5/a0-a2,-(sp)
  1741.     push    a1
  1742.     bclr    #UNITB_BREAKSENT,(UNIT_FLAGS,a3)    ;for Query
  1743.     btst    #SERB_7WIRE,(prefs_SERFLAGS,a4)
  1744.     bne.b    .Handshake
  1745.     btst    #CSRB_CTSL,(CSR,a5)
  1746.     bne    .NotConnected
  1747.  
  1748. .Handshake:
  1749.     movea.l    (IO_DATA,a1),a2
  1750.     move.l    (IO_LENGTH,a1),d2
  1751.     beq    .End
  1752.     bpl.b    .CheckX
  1753.     move.l    a2,a0    ;handle zero-terminated writes
  1754. .L1:    tst.b    (a0)+
  1755.     bne.b    .L1
  1756.     sub.l    a2,a0
  1757.     move.l    a0,d2
  1758. .CheckX:
  1759.     tst.b    (xstate,a3)
  1760.     bne    .DoIt    ;go if no XOFF
  1761.  
  1762.     PUTDEBUG    5,<'%s/Transmit: Waiting for XON!'>
  1763.     move.l    (xonsig,a3),d0
  1764.     add.l    (writeabortsig,a3),d0
  1765.     EXEC    Wait    ;Wait for an x-on signal before sending
  1766.     and.l    (writeabortsig,a3),d0
  1767.     bne    .Abort
  1768.     PUTDEBUG    5,<'%s/Transmit: Received XON!'>
  1769.     bra    .CheckX
  1770.  
  1771. .DoIt:
  1772.     move.l    d2,d4
  1773.     Disable    ;quite neccessary!
  1774.     btst    #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
  1775.     beq.b    .NeedInt
  1776.     bclr    #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
  1777.     move.b    (a2)+,(TDR,a5)    ;If set, we can load up the transmit reg immediately
  1778.     subq.l    #1,d4
  1779.     beq    .DoneWriting    ;does an Enable
  1780.  
  1781. .NeedInt:
  1782.     move.l    a2,(WriteBufferPtr,a3)
  1783.     move.l    d4,(WriteCount,a3)    ;GO!!!
  1784.     Enable
  1785.  
  1786.     lea    (timeriorequest,a3),a1
  1787.     movea.l    (MN_REPLYPORT,a1),a0
  1788.     moveq    #0,d0
  1789.     move.b    (MP_SIGBIT,a0),d0
  1790.     moveq    #0,d3
  1791.     bset    d0,d3
  1792.  
  1793. .TopWaitBlock:
  1794.     moveq    #0,d5    ;clear danger flag
  1795. .WaitBlock:
  1796.     move.w    #TR_ADDREQUEST,(IO_COMMAND,a1)
  1797.     clr.l    (TV_SECS+IO_SIZE,a1)
  1798.     move.l    #100000,(TV_MICRO+IO_SIZE,a1)    ;100ms
  1799.     EXEC    SendIO
  1800.  
  1801.     move.l    d3,d0    ;timer signal
  1802.     add.l    (writeabortsig,a3),d0
  1803.     add.l    (tdresig,a3),d0
  1804.  
  1805. ;Wait for the block write to finish
  1806.     EXEC    Wait    ;Wait for write to finish
  1807.     move.l    d0,d1
  1808.     and.l    (tdresig,a3),d1
  1809.     beq.b    .NotTDRE
  1810.     EXEC    AbortIO    ;kill timer request
  1811.     EXEC    WaitIO
  1812.  
  1813. ;    PUTDEBUG    150,<'%s/Transmit: Write block finished.'>
  1814. .End:
  1815.     moveq    #0,d0    ;value
  1816.     move.l    d3,d1    ;mask
  1817.     EXEC    SetSignal    ;clear timer signal just in case
  1818.     pop    a1
  1819.     move.l    d2,(IO_ACTUAL,a1)
  1820.     movem.l    (sp)+,d0-d5/a0-a2
  1821.     rts
  1822. .NotTDRE:
  1823.     move.l    d0,d1
  1824.     and.l    (writeabortsig,a3),d1
  1825.     beq.b    .CheckOut
  1826.  
  1827. ;Abort signal
  1828.     EXEC    AbortIO    ;kill timer request
  1829.     EXEC    WaitIO
  1830.     bra    .Abort
  1831.  
  1832. .CheckOut:
  1833. ;If we end up here then a 100ms timeout has occured - so check a few
  1834. ;things...
  1835.     EXEC    WaitIO    ;remove the message from the replyport
  1836.     move.l    (WriteCount,a3),d0
  1837.     cmp.l    d4,d0    ;compare with previous WriteCount value
  1838.     beq.b    .Equal
  1839.     move.l    d0,d4
  1840.     bra    .TopWaitBlock
  1841. .Equal:
  1842.     btst    #CSRB_CTSL,(CSR,a5)
  1843.     bne    .TopWaitBlock    ;go if not asserted
  1844.     tst.l    d5
  1845.     bne.b    .Danger
  1846.     moveq    #1,d5    ;set danger flag
  1847.     bra    .WaitBlock
  1848. .Danger:
  1849.  
  1850. ;If we get here we know:
  1851. ;1. Nothing has been outputted (no TDRE) in the last 100-200+ ms, and
  1852. ;2. CTS is asserted (presumably at least 100ms -- we assume this)
  1853. ;So, we assume that we got unlucky and missed a TDRE, and force a byte out:
  1854.  
  1855.     Disable
  1856.     bclr    #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
  1857.     move.l    (WriteBufferPtr,a3),a0
  1858.     move.b    (a0)+,(TDR,a5)
  1859.     move.l    a0,(WriteBufferPtr,a3)
  1860.     subq.l    #1,(WriteCount,a3)
  1861.     beq.b    .DoneWriting
  1862.     Enable
  1863.     bra    .TopWaitBlock
  1864.  
  1865. .DoneWriting:
  1866.     Enable
  1867.     bra    .End
  1868. .NotConnected:
  1869.     move.b    #SerErr_LineErr,(IO_ERROR,a1)
  1870.     bra    .End
  1871. .Abort:
  1872.     sub.l    (WriteCount,a3),d2
  1873.     clr.l    (WriteCount,a3)
  1874.     bra    .End
  1875.  
  1876. ;******* end of write routine *******
  1877.  
  1878. Break:
  1879.     movem.l    d0-d2/a0/a1,-(sp)
  1880.     PUTDEBUG    5,<'%s/Break: called'>
  1881.     move.b    #2,(ACR,a5) ;start break
  1882.     bset    #UNITB_BREAKSENT,(UNIT_FLAGS,a3)
  1883.     lea    (timeriorequest,a3),a1
  1884.     move.w    #TR_ADDREQUEST,(IO_COMMAND,a1)
  1885.     clr.l    (TV_SECS+IO_SIZE,a1)
  1886.     move.l    (prefs_BRKTIME,a4),d0
  1887.     ori.b    #$FF,d0    ;To avoid the V33/V34 timer bug
  1888.  
  1889.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  1890.     move.l    d0,-(sp)
  1891.     PUTDEBUG    5,<'%s/Break: TV_MICRO=%ld'>
  1892.     addq.l    #4,sp
  1893.     endc
  1894.  
  1895.     move.l    d0,(TV_MICRO+IO_SIZE,a1)
  1896.     movea.l    (MN_REPLYPORT,a1),a0
  1897.     moveq    #0,d2
  1898.     move.b    (MP_SIGBIT,a0),d2
  1899.     EXEC    SendIO
  1900.     moveq    #0,d0
  1901.     bset    d2,d0
  1902.     add.l    (writeabortsig,a3),d0
  1903.  
  1904.     PUTDEBUG    5,<'%s/Break: Waiting...'>
  1905.  
  1906.     EXEC    Wait
  1907.     and.l    (writeabortsig,a3),d0
  1908.     beq.b    .BreakOK
  1909.  
  1910.     PUTDEBUG    5,<'%s/Break: Aborted!'>
  1911.  
  1912.     EXEC    AbortIO    ;The break was aborted. Clean up.
  1913. .BreakOK:
  1914.     EXEC    WaitIO 
  1915.     moveq    #0,d0    ;value
  1916.     moveq    #0,d1
  1917.     bset    d2,d1    ;mask
  1918.     EXEC    SetSignal    ;clear timer signal bit just in case
  1919.     move.b    #0,(ACR,a5) ;stop the break
  1920.  
  1921.     PUTDEBUG    5,<'%s/Break: Finished!'>
  1922.     movem.l    (sp)+,d0-d2/a0/a1
  1923.     rts
  1924.  
  1925. ;AbortIO() is a REQUEST to "hurry up" processing of an IORequest.
  1926. ;If the IORequest was already complete, nothing happens (if an IORequest
  1927. ;is quick or LN_TYPE=NT_REPLYMSG, the IORequest is complete).
  1928. ;The message must be replied with ReplyMsg(), as normal.
  1929. ;
  1930. ;Note that AbortIO is called directly, not via BeginIO.
  1931. ;
  1932. ;If sucessful, AbortIO returns IOERR_ABORTED in IO_ERROR and zero in D0
  1933.  
  1934. AbortIO:
  1935.     PUTDEBUG    5,<'%s/AbortIO: called'>
  1936.     Forbid
  1937.     movem.l    d1/a0/a1/a3,-(sp)
  1938.     movea.l    (IO_UNIT,a1),a3
  1939.     move.b    #IOERR_ABORTED,(IO_ERROR,a1)    ;We always say we succeed(ed)
  1940.     cmpi.b    #NT_REPLYMSG,(LN_TYPE,a1)    ;Already complete?
  1941.     beq.b    .End
  1942.     btst    #IOB_QUICK,(IO_FLAGS,a1)
  1943.     bne.b    .End
  1944.  
  1945. ;Check to see whether or not the IORequest is being processed 
  1946.  
  1947.     cmpi.w    #CMD_READ,(IO_COMMAND,a1)
  1948.     bne.b    .NotRead
  1949.     cmp.l    (ReadRequestPtr,a3),a1
  1950.     bne.b    .NotActive
  1951.     move.l    (readabortsig,a3),d0
  1952.     lea    (mdu_rtcb,a3),a1
  1953. .Signal:    EXEC    Signal
  1954.     bra.b    .End
  1955. .NotRead:
  1956.     cmpi.w    #CMD_WRITE,(IO_COMMAND,a1)
  1957.     bne.b    .NotWrite
  1958. .Write:    cmp.l    (WriteRequestPtr,a3),a1
  1959.     bne.b    .NotActive
  1960.     move.l    (writeabortsig,a3),d0
  1961.     lea    (mdu_wtcb,a3),a1
  1962.     bra.b    .Signal
  1963. .NotWrite:
  1964.     cmpi.w    #SDCMD_BREAK,(IO_COMMAND,a1)
  1965.     beq.b    .Write
  1966.     bra.b    .End
  1967.  
  1968. .NotActive:
  1969. ;Set ignore bit in the IORequest
  1970.     bset    #ioflagsB_Ignore,(IO_FLAGS,a1)
  1971.  
  1972. .End:    Permit
  1973.     movem.l    (sp)+,d1/a0/a1/a3
  1974.     moveq    #0,d0    ;error code (always successful)
  1975.     PUTDEBUG    5,<'%s/AbortIO: Finished!'>
  1976.     rts
  1977.  
  1978. ;**************** End of AbortIO *****************
  1979.  
  1980. Invalid:
  1981.     move.b    #IOERR_NOCMD,(IO_ERROR,a1)
  1982.     rts
  1983.  
  1984. ;Clear invalidates all internal buffers.
  1985. ;
  1986. ; a1 -- a pointer to the io request block
  1987. ; a3 -- a pointer to the unit
  1988. ; a4 -- a pointer to prefs
  1989. ; a5 -- a pointer to the unit hardware
  1990. ; a6 -- a pointer to the device
  1991.  
  1992. MyClear:
  1993.     movem.l    d0/d1,-(sp)
  1994.     moveq    #0,d0
  1995.     moveq    #0,d1
  1996.     movem.l    d0/d1,(HeadLong,a3)
  1997.     movem.l    (sp)+,d0/d1
  1998.     rts
  1999.  
  2000. ; a1 -- a pointer to the io request block
  2001. ; a3 -- a pointer to the unit
  2002. ; a4 -- a pointer to prefs
  2003. ; a5 -- a pointer to the unit hardware
  2004. ; a6 -- a pointer to the device
  2005.  
  2006. MyReset:
  2007.     movem.l    d0/d7/a1,-(sp)
  2008.  
  2009.     PUTDEBUG    30,<'%s/MyReset: called'>
  2010.     Forbid
  2011.     move.b    (IERstate,a3),d7
  2012.     clr.b    (IERstate,a3)
  2013.     move.b    #$7f,(IER,a5)    ;Disable ACIA interrupts
  2014.     bsr    Flush    ;Flush pending requests
  2015.  
  2016. ;Abort current IO, if any IO is indeed occuring
  2017.  
  2018.     move.l    a1,-(sp)
  2019.  
  2020.     movea.l    (WriteRequestPtr,a3),a1
  2021.     move.l    a1,d0
  2022.     beq.b    .WriteNotActive
  2023.     bsr    AbortIO
  2024.  
  2025. .WriteNotActive:
  2026.     movea.l    (ReadRequestPtr,a3),a1
  2027.     move.l    a1,d0
  2028.     beq.b    .NothingActive
  2029.     bsr    AbortIO
  2030.  
  2031. .NothingActive:
  2032.     movea.l    (sp)+,a1 
  2033.     bsr    SetDefaultPrefs
  2034.     bsr    CopyPrefs  
  2035.     bsr    FreeResources
  2036.     bsr    SetUpUnit
  2037.  
  2038.     tst.l    d0    ;Check for a possible error condition
  2039.     bmi.b    .OutOfMem
  2040.     subq.l    #1,d0
  2041.     beq.b    .TimerError
  2042.     subq.l    #1,d0
  2043.     beq.b    .ParamError
  2044.  
  2045.     move.b    d7,(IERstate,a3)    ;Enable DACIA interrupts again
  2046.     bset    #7,d7
  2047.     move.b    d7,(IER,a5)
  2048.     Permit
  2049.     clr.l    (IO_ACTUAL,a1)
  2050.     PUTDEBUG    30,<'%s/MyReset: Finished!'>
  2051. .ResetEnd:
  2052.     movem.l    (sp)+,d0/d7/a1
  2053.     rts
  2054.  
  2055. .ParamError:
  2056.     move.b    #SerErr_InvParam,(IO_ERROR,a1)
  2057.     bra.b    .MyResetFailed
  2058.  
  2059. .TimerError:
  2060.     move.b    #SerErr_TimerErr,(IO_ERROR,a1)
  2061.     bra.b    .MyResetFailed
  2062.  
  2063. .OutOfMem:
  2064.     move.b    #SerErr_BufErr,(IO_ERROR,a1)
  2065. .MyResetFailed:
  2066.     Permit
  2067.     clr.l    (IO_ACTUAL,a1)
  2068.     PUTDEBUG    30,<'%s/MyReset: Error!'>
  2069.     bra.b    .ResetEnd
  2070.  
  2071. ; a1 -- a pointer to the io request block
  2072. ; a3 -- a pointer to the unit
  2073. ; a4 -- a pointer to prefs
  2074. ; a5 -- a pointer to the unit hardware
  2075. ; a6 -- a pointer to the device
  2076. ;
  2077. ;Return number of chars in buffer in IO_ACTUAL
  2078. ;Fill in IO_STATUS
  2079.  
  2080. Query:
  2081.     movem.l    d0-d1,-(sp)
  2082. ;    PUTDEBUG    30,<'%s/Query: called.'>
  2083.  
  2084.     bsr    GetBytesInReadBuf
  2085.     move.l    d0,(IO_ACTUAL,a1)
  2086.  
  2087.     ifne    INFO_LEVEL  ;If any debugging enabled at all
  2088.     move.l    d0,-(sp)
  2089. ;    PUTDEBUG    30,<'%s/Query: %ld bytes in buf.'>
  2090.     move.l    (sp)+,d0
  2091.     endc
  2092.  
  2093.     moveq    #0,d0 ;d0 will mirror IO_STATUS
  2094.     move.b    (CSR,a5),d1
  2095.     btst    #0,d1
  2096.     beq.b    Q1
  2097.     bset    #6,d0
  2098. Q1:    btst    #1,d0
  2099.     beq.b    Q2
  2100.     bset    #7,d0
  2101. Q2:    btst    #3,d1
  2102.     beq.b    Q3
  2103.     bset    #3,d0
  2104. Q3:    btst    #4,d1
  2105.     beq.b    Q4
  2106.     bset    #5,d0    ;carrier detect
  2107. Q4:    btst    #5,d1
  2108.     beq.b    Q5
  2109.     bset    #4,d0
  2110. Q5:    btst    #UNITB_BREAKSENT,(UNIT_FLAGS,a3)
  2111.     beq.b    NB
  2112.     bset    #9,d0
  2113. NB:    btst    #2,d1
  2114.     beq.b    NRB
  2115.     bset    #10,d0
  2116. NRB:    tst.b    (xstate,a3)
  2117.     bne.b    xIsOn
  2118.     bset    #11,d0
  2119. xIsOn:    move.w    d0,(IO_STATUS,a1)
  2120.     movem.l    (sp)+,d0-d1
  2121.     rts
  2122.  
  2123. ; a1 -- a pointer to the io request block
  2124. ; a3 -- a pointer to the unit
  2125. ; a4 -- a pointer to prefs
  2126. ; a5 -- a pointer to the unit hardware
  2127. ; a6 -- a pointer to the device
  2128.  
  2129. SetParams:
  2130.     movem.l    d0/a0/a2,-(sp)
  2131.     bclr    #SERB_XDISABLED,(prefs_SERFLAGS,a4)    ;enable
  2132.     btst    #SERB_XDISABLED,(IO_SERFLAGS,a1)
  2133.     beq.b    .NotDisabled
  2134.     bset    #SERB_XDISABLED,(prefs_SERFLAGS,a4)
  2135.     st    (xstate,a3)    ;set to X-ON state
  2136. .NotDisabled:
  2137.  
  2138. ;Now check to see whether the device is busy, i.e. any current or pending requests.
  2139.  
  2140.     Forbid
  2141.     tst.l    (ReadRequestPtr,a3)
  2142.     bne    .DevBusy
  2143.     tst.l    (WriteRequestPtr,a3)
  2144.     bne    .DevBusy
  2145.     lea    (MP_MSGLIST,a3),a0    ;Read port - anything there?
  2146.     movea.l    (a0),a2
  2147.     tst.l    (a2)
  2148.     bne.b    .DevBusy
  2149.     lea    (mdu_wport+MP_MSGLIST,a3),a0    ;Write port - anything there?
  2150.     movea.l    (a0),a2
  2151.     tst.l    (a2)
  2152.     bne.b    .DevBusy
  2153.  
  2154. ;Ok, the device is not busy. Set all params.
  2155.  
  2156.     bsr    SetPrefs    ;First copy the data
  2157.     move.l    #65536,(prefs_RBUFLEN,a4)
  2158.  
  2159. ;---> This section of code was supposed to increase compatibility, but
  2160. ;---> it actually decreases it!! The autodocs fail me again....
  2161. ;If boogie is set, it implies a few other things...(NOT!!!!)
  2162. ;    btst    #SERB_RAD_BOOGIE,(IO_SERFLAGS,a1) ;Check for RAD_BOOGIE
  2163. ;    beq.b    .SkipBoogie
  2164. ;    bclr    #SEXTB_MSPON,(prefs_EXTFLAGS+3,a4)
  2165. ;    bclr    #SERB_PARTY_ON,(prefs_SERFLAGS,a4)
  2166. ;    bset    #SERB_XDISABLED,(prefs_SERFLAGS,a4)
  2167. ;    move.b    #8,(prefs_READLEN,a4)
  2168. ;    move.b    #8,(prefs_WRITELEN,a4)
  2169. ;    bra.b    .SkipNext
  2170. ;.SkipBoogie:
  2171.  
  2172.  
  2173. ;The boogie flag is not set...but maybe it should be...
  2174. ;Note that this logic is depended on in the Read routine
  2175.     btst    #SERB_XDISABLED,(prefs_SERFLAGS,a4)
  2176.     beq.b    .nochance
  2177.     btst    #SERB_EOFMODE,(prefs_SERFLAGS,a4)
  2178.     bne.b    .nochance
  2179.     bset    #SERB_RAD_BOOGIE,(prefs_SERFLAGS,a4) ;Set RAD_BOOGIE !
  2180.  
  2181. .nochance:
  2182. .SkipNext:
  2183.     bsr    InitDACIA    ;Then set up the chip 
  2184.     tst.l    d0
  2185.     bne.b    .Invalid
  2186.  
  2187. .End:    Permit
  2188.     movem.l    (sp)+,d0/a0/a2
  2189.     rts
  2190.  
  2191. .Invalid:    move.b    #SerErr_InvParam,(IO_ERROR,a1)
  2192.     bra.b    .End
  2193.  
  2194. .DevBusy:    move.b    #SerErr_DevBusy,(IO_ERROR,a1)
  2195.     bra.b    .End
  2196.  
  2197. SetControlLines:
  2198.  
  2199.     comment |
  2200.  
  2201. This routine is an extension specified by ASDG for their Dual Serial
  2202. Board. It allows application control of RTS and DTR. It works like this:
  2203.  
  2204. IO_COMMAND = 16
  2205.  
  2206. IO_OFFSET = mask
  2207. IO_LENGTH = value
  2208. Bit 0 = RTS
  2209. Bit 1 = DTR
  2210. |
  2211.  
  2212.     movem.l    d0-d2,-(sp)
  2213.     Forbid
  2214.     move.b    (frstate,a3),d0
  2215.     move.l    (IO_LENGTH,a1),d1    ;state
  2216.     move.l    (IO_OFFSET,a1),d2    ;mask
  2217.     and.b    d2,d1
  2218.     not.b    d2
  2219.     and.b    d2,d0    ;clear
  2220.     or.b    d1,d0    ;set
  2221.     move.b    d0,(frstate,a3)
  2222.     move.b    d0,(FMR,a5)
  2223.     Permit
  2224.     movem.l    (sp)+,d0-d2
  2225.     rts
  2226.  
  2227. ;The Stop command stop all future io requests from being processed until a
  2228. ;Start command is received. The Stop command is NOT stackable: e.g. no matter
  2229. ;how many stops have been issued, it only takes one Start to restart
  2230. ;processing.
  2231.  
  2232. MyStop:
  2233.     PUTDEBUG    30,<'%s/MyStop: called'>
  2234.     bset    #MDUB_STOPPED,(MDU_FLAGS,a3)
  2235.     rts
  2236.  
  2237. Start:
  2238.  
  2239. ;[A3=unit A6=device]
  2240.  
  2241.     movem.l    d0-d1/a0-a2,-(sp)
  2242.     PUTDEBUG    30,<'%s/Start: called'>
  2243.     movea.l    a1,a2
  2244.  
  2245. ;Turn processing back on
  2246.     bclr    #MDUB_STOPPED,(MDU_FLAGS,a3)
  2247.  
  2248. ;Kick the tasks to start them moving
  2249.  
  2250.     move.b    (MP_SIGBIT,a3),d1    ;First the read task...
  2251.     moveq    #0,d0
  2252.     bset    d1,d0    ;Prepared signal mask
  2253.     movea.l    (MP_SIGTASK,a3),a1    ;FIXED: marco-task to signal
  2254.     move.l    a6,-(sp)
  2255.     movea.l    (md_SysLib,a6),a6
  2256.     SYS    Signal    ;FIXED: marco-a6 not a3
  2257.     movea.l    (sp)+,a6
  2258.  
  2259.     movea.l    a2,a1    ;Then the write task
  2260.     lea    (mdu_wport,a3),a0
  2261.     move.b    (MP_SIGBIT,a0),d1
  2262.     moveq    #0,d0
  2263.     bset    d1,d0    ;Prepared signal mask
  2264.     movea.l    (MP_SIGTASK,a0),a1    ;FIXED: marco-task to signal
  2265.     move.l    a6,-(sp)
  2266.     movea.l    (md_SysLib,a6),a6
  2267.     SYS    Signal    ;FIXED: marco-a6 not a3
  2268.     movea.l    (sp)+,a6
  2269.     PUTDEBUG    30,<'%s/Start: Finished!'>
  2270.     movem.l    (sp)+,d0-d1/a0-a2
  2271.     rts
  2272.  
  2273. ;Flush pulls all I/O requests off the queue and sends them back.  We must be
  2274. ;careful not to destroy work in progress, and also that we do not let some io
  2275. ;requests slip by.
  2276.  
  2277. Flush:
  2278.     movem.l    d0-d1/a0/a1/a6,-(sp)
  2279.     PUTDEBUG    30,<'%s/Flush: called'>
  2280.     movea.l    (md_SysLib,a6),a6
  2281.     SYS    Forbid
  2282. ReadFlush_Loop:
  2283.     movea.l    a3,a0
  2284.     SYS    GetMsg    ;Steal messages from task's port
  2285.     tst.l    d0
  2286.     beq.b    WriteFlush_Loop
  2287.  
  2288.     movea.l    d0,a1
  2289.     move.b    #IOERR_ABORTED,(IO_ERROR,a1)
  2290.     SYS    ReplyMsg
  2291.     bra.b    ReadFlush_Loop
  2292.  
  2293. WriteFlush_Loop:
  2294.     lea    (mdu_wport,a3),a0
  2295.     SYS    GetMsg    ;Steal messages from task's port
  2296.     tst.l    d0
  2297.     beq.b    Flush_End
  2298.  
  2299.     movea.l    d0,a1
  2300.     move.b    #IOERR_ABORTED,(IO_ERROR,a1)
  2301.     SYS    ReplyMsg
  2302.     bra.b    WriteFlush_Loop
  2303.  
  2304. Flush_End:
  2305.     SYS    Permit
  2306.     PUTDEBUG    30,<'%s/Flush: Finished!'>
  2307.     movem.l    (sp)+,d0-d1/a0/a1/a6
  2308.     rts
  2309.  
  2310. ;Here begins the task related routines
  2311. ;
  2312. ; Register Usage
  2313. ; ==============
  2314. ; a2 -- device pointer
  2315. ; a3 -- unit pointer
  2316. ; a4 -- prefs pointer
  2317. ; a5 -- hardware pointer
  2318. ; a6 -- syslib pointer
  2319. ;----------------------------------------------------------------------
  2320. ;
  2321. ;Note: Signals must be allocated within this (the task's) context!
  2322. ;The task is responsible for enabling the right DACIA interrupts...AFTER
  2323. ;it has done its setup (like allocating signals).
  2324. ;
  2325. ;NOTE: We actually have two tasks, each with their own separate
  2326. ;      code (but shared data). First comes the read task...:
  2327.  
  2328. ReadTask_Begin:
  2329.     PUTDEBUG    35,<'%s/ReadTask_Begin'>
  2330.     movea.l    (4).w,a6
  2331.  
  2332. ;Grab the arguments passed down from our parent
  2333.  
  2334.     movea.l    (4,sp),a3    ;Unit pointer
  2335.     move.l    (mdu_prefs,a3),a4
  2336.     movea.l    (daciabase,a3),a5
  2337.  
  2338.     lea    (readsig,a3),a2
  2339.     moveq    #1,d6    ;Number of signals to allocate-1
  2340. ReadSigLoop:
  2341.     moveq    #-1,d0    ;-1 is any signal at all
  2342.     SYS    AllocSignal    ;Allocate signals for I/O interrupts
  2343.     moveq    #0,d7    ;Convert bit number signal mask
  2344.     bset    d0,d7
  2345.     move.l    d7,(a2)+    ;Save in unit structure
  2346.     dbra    d6,ReadSigLoop
  2347.  
  2348.     movea.l    (mdu_Device,a3),a2    ;Point to device structure
  2349.  
  2350.     moveq    #-1,d0    ;-1 is any signal at all
  2351.     SYS    AllocSignal    ;Allocate a signal
  2352.     move.b    d0,(MP_SIGBIT,a3)
  2353.     move.b    #PA_SIGNAL,(MP_FLAGS,a3) ;Make message port "live"
  2354.  
  2355.     ifge    INFO_LEVEL-40
  2356.     move.l    ($114,a6),-(sp)
  2357.     move.l    (mdu_Device,a3),-(sp)
  2358.     move.l    a3,-(sp)
  2359.     move.l    d0,-(sp)
  2360.     PUTDEBUG    40,<'%s/ReadTask -- Signal=%ld, Unit=%lx Device=%lx Task=%lx'>
  2361.     adda.l    #4*4,sp
  2362.     endc
  2363.  
  2364. ;Enable read-related ACIA interrupts
  2365.  
  2366.     ori.b    #READINTMASK,(IERstate,a3)
  2367.     move.b    #READINT,(IER,a5)
  2368.     bra    ReadTask_NextMessage
  2369.  
  2370. ;OK, kids, we are done with initialization.  We now can start the main loop
  2371. ;of the driver.  It goes like this.  Because we had the port marked PA_IGNORE
  2372. ;for a while (in InitUnit) we jump to the getmsg code on entry.  (The first
  2373. ;message will probably be posted BEFORE our task gets a chance to run).
  2374. ;  wait for a message
  2375. ;  lock the device
  2376. ;  get a message.  If no message, unlock device and loop
  2377. ;  dispatch the message
  2378. ;  loop back to get a message
  2379.  
  2380. ;Main loop: wait for a new message
  2381.  
  2382. ReadTask_PermitMainLoop:
  2383.     Permit
  2384. ReadTask_MainLoop:
  2385.     PUTDEBUG    75,<'%s/ReadTask ++Sleep'>
  2386.     move.l    a3,a0
  2387.     SYS    WaitPort
  2388.     ifge    INFO_LEVEL-5
  2389.     bchg.b    #1,($bfe001).l  ;Blink the power LED
  2390.     endc
  2391.  
  2392.     PUTDEBUG    75,<'%s/ReadTask ++Wakeup'>
  2393.  
  2394.     btst    #MDUB_STOPPED,(MDU_FLAGS,a3)    ;See if we are stopped
  2395.     bne.b    ReadTask_MainLoop    ;Device is stopped, ignore messages
  2396.  
  2397. ReadTask_NextMessage:
  2398.     movea.l    a3,a0
  2399.     Forbid
  2400.     SYS    GetMsg    ;Get the next request
  2401.     PUTDEBUG    1,<'%s/ReadTask GotMsg'>
  2402.     tst.l    d0
  2403.     beq    ReadTask_PermitMainLoop    ;no message?
  2404.  
  2405.     movea.l    d0,a1    ;Do this request
  2406.     exg    a2,a6    ;Put device ptr in right place
  2407.  
  2408.     btst    #ioflagsB_Ignore,(IO_FLAGS,a1)
  2409.     bne.b    Readignorecmd
  2410.     move.l    a1,(ReadRequestPtr,a3)
  2411.     Permit
  2412.     bsr    Read    ;Do it!
  2413.     clr.l    (ReadRequestPtr,a3)
  2414.     EXEC    ReplyMsg
  2415.  
  2416. ;No longer active - abort has stopped sending signals. Now we can
  2417. ;(and should) clear the abort signal.
  2418.  
  2419.     moveq    #0,d0
  2420.     move.l    (readabortsig,a3),d1
  2421.     EXEC    SetSignal
  2422.     bra.b    Readconttl
  2423.  
  2424. Readignorecmd:
  2425.     Permit
  2426.     clr.l    (IO_ACTUAL,a1)
  2427.     EXEC    ReplyMsg
  2428. Readconttl:
  2429.     exg    a2,a6    ;Get ExecBase back in a6
  2430.     bra    ReadTask_NextMessage
  2431.  
  2432. ;**** End of read task code ****
  2433.  
  2434. ;**** Beginning of write task code ****
  2435.  
  2436. ; Register Usage
  2437. ; ==============
  2438. ; a2 -- device pointer
  2439. ; a3 -- unit pointer
  2440. ; a4 -- prefs pointer
  2441. ; a5 -- hardware pointer
  2442. ; a6 -- syslib pointer
  2443.  
  2444. WriteTask_Begin:
  2445.     PUTDEBUG    35,<'%s/WriteTask_Begin'>
  2446.     movea.l    (SysBase).w,a6
  2447.  
  2448. ;Grab the arguments passed down from our parent
  2449.  
  2450.     movea.l    (4,sp),a3    ;Unit pointer
  2451.     move.l    (mdu_prefs,a3),a4
  2452.     movea.l    (daciabase,a3),a5
  2453.  
  2454.     lea    (tdresig,a3),a2
  2455.     moveq    #2,d6    ;Number of signals to allocate-1
  2456. WriteSigLoop:
  2457.     moveq    #-1,d0    ;-1 is any signal at all
  2458.     SYS    AllocSignal    ;Allocate signals for I/O interrupts
  2459.     moveq    #0,d7    ;Convert bit number signal mask
  2460.     bset    d0,d7
  2461.     move.l    d7,(a2)+    ;Save in unit structure
  2462.     dbra    d6,WriteSigLoop
  2463.  
  2464. ;Allocate a signal for the timer message port
  2465.  
  2466.     moveq    #-1,d0    ;-1 is any signal at all
  2467.     SYS    AllocSignal
  2468.     lea    (timerport,a3),a2
  2469.     move.b    d0,(MP_SIGBIT,a2)
  2470.     move.l    a2,(timeriorequest+MN_REPLYPORT,a3)
  2471.     suba.l    a1,a1
  2472.     SYS    FindTask
  2473.     move.l    d0,(MP_SIGTASK,a2)    
  2474.     move.b    #PA_SIGNAL,(MP_FLAGS,a2) ;Make message port "live"
  2475.  
  2476.     movea.l    (mdu_Device,a3),a2    ;Point to device structure
  2477.  
  2478. ;Allocate a signal for the cmd message port
  2479.  
  2480.     moveq    #-1,d0    ;-1 is any signal at all
  2481.     SYS    AllocSignal
  2482.     move.b    d0,(mdu_wport+MP_SIGBIT,a3)
  2483.     move.b    #PA_SIGNAL,(mdu_wport+MP_FLAGS,a3) ;Make message port "live"
  2484.  
  2485.     ifge    INFO_LEVEL-40
  2486.     move.l    (ThisTask,a6),-(sp)
  2487.     move.l    a5,-(sp)
  2488.     move.l    a3,-(sp)
  2489.     move.l    d0,-(sp)
  2490.     PUTDEBUG    40,<'%s/WriteTask -- Signal=%ld, Unit=%lx Device=%lx Task=%lx'>
  2491.     adda.l    #4*4,sp
  2492.     endc
  2493.  
  2494. ;Enable write-related ACIA interrupts
  2495.  
  2496.     ori.b    #WRITEINTMASK,(IERstate,a3)
  2497.     move.b    #WRITEINT,(IER,a5)
  2498.     bra    WriteTask_NextMessage
  2499.  
  2500. ;Main loop: wait for a new message
  2501.  
  2502. WriteTask_PermitMainLoop:
  2503.     Permit
  2504. WriteTask_MainLoop:
  2505.     PUTDEBUG    75,<'%s/WriteTask ++Sleep'>
  2506.  
  2507.     lea    (mdu_wport,a3),a0
  2508.     SYS    WaitPort
  2509.  
  2510.     ifge    INFO_LEVEL-5
  2511.     bchg.b    #1,($bfe001).l  ;Blink the power LED
  2512.     endc
  2513.     PUTDEBUG    75,<'%s/WriteTask ++Wakeup'>
  2514.  
  2515.     btst    #MDUB_STOPPED,(MDU_FLAGS,a3)    ;See if we are stopped
  2516.     bne    ReadTask_MainLoop    ;Device is stopped, ignore messages
  2517.  
  2518. WriteTask_NextMessage:
  2519.     lea    (mdu_wport,a3),a0
  2520.     Forbid
  2521.     SYS    GetMsg    ;Get the next request
  2522.     PUTDEBUG    1,<'%s/WriteTask GotMsg'>
  2523.     tst.l    d0
  2524.     beq    WriteTask_PermitMainLoop    ;No message?
  2525.  
  2526.     movea.l    d0,a1    ;Do this request
  2527.     exg    a2,a6    ;Put device ptr in right place
  2528.  
  2529.     btst    #ioflagsB_Ignore,(IO_FLAGS,a1)
  2530.     bne.b    Writeignorecmd
  2531.     move.l    a1,(WriteRequestPtr,a3)
  2532.     Permit
  2533.     cmp.w    #CMD_WRITE,(IO_COMMAND,a1)
  2534.     bne.b    .NotWrite
  2535.     bsr    Write
  2536.     bra.b    .Continue
  2537. .NotWrite:
  2538.     bsr    Break
  2539. .Continue:
  2540.     clr.l    (WriteRequestPtr,a3)
  2541.     EXEC    ReplyMsg
  2542.  
  2543. ;No longer active - abort has stopped sending signals. Now we can
  2544. ;(and should) clear the abort signal.
  2545.  
  2546.     moveq    #0,d0
  2547.     move.l    (writeabortsig,a3),d1
  2548.     EXEC    SetSignal
  2549.     bra.b    Writeconttl
  2550.  
  2551. Writeignorecmd:
  2552.     Permit
  2553.     clr.l    (IO_ACTUAL,a1)
  2554.     EXEC    ReplyMsg
  2555. Writeconttl:
  2556.     exg    a2,a6    ; get syslib back in a6
  2557.     bra    WriteTask_NextMessage
  2558.  
  2559. ;********** end of write task code ***********
  2560.  
  2561. ;Initialize the device
  2562.  
  2563. mdu_Init:
  2564. ;Initialize read task message port/tcb
  2565.     INITBYTE    MP_FLAGS,PA_IGNORE    ;Unit starts with read message port
  2566.     INITBYTE    LN_TYPE,NT_MSGPORT
  2567.     INITLONG    LN_NAME,myName
  2568.     INITLONG    mdu_rtcb+LN_NAME,myName
  2569.     INITBYTE    mdu_rtcb+LN_TYPE,NT_TASK
  2570.     INITBYTE    mdu_rtcb+LN_PRI,127
  2571.  
  2572. ;Initialize write task message port/tcb
  2573.  
  2574.     INITBYTE    mdu_wport+MP_FLAGS,PA_IGNORE    ;Write message port
  2575.     INITBYTE    mdu_wport+LN_TYPE,NT_MSGPORT
  2576.     INITLONG    mdu_wport+LN_NAME,myName
  2577.     INITLONG    mdu_wtcb+LN_NAME,myName
  2578.     INITBYTE    mdu_wtcb+LN_TYPE,NT_TASK
  2579.     INITBYTE    mdu_wtcb+LN_PRI,126
  2580.  
  2581. ;Initialize timer message port
  2582.  
  2583.     INITBYTE    timerport+MP_FLAGS,PA_IGNORE    ;Timer message port
  2584.     INITBYTE    timerport+LN_TYPE,NT_MSGPORT
  2585.     INITLONG    timerport+LN_NAME,myName
  2586.  
  2587.     dc.w    0
  2588.  
  2589. ;******************** Interrupt code *********************************
  2590.  
  2591. ;Notes:
  2592.  
  2593. ;In this version of the driver we use a single interrupt routine for all
  2594. ;units, and that routine bypasses the usual Exec conventions. Normally
  2595. ;this would be bad, but the need for speed certainly warrents it in this
  2596. ;case.
  2597.  
  2598. ;This is the interrupt routine. It serves three purposes:
  2599. ;1. Read in a byte if available, store it, and signal the read task
  2600. ;2. Check for TDRE-empty condition and signal write task
  2601. ;3. Check for an exceptional condition and signal read task
  2602.  
  2603. ;uses d0,d7,a0,a3,a5
  2604.  
  2605. DoInt    macro
  2606.     movem.l    d0/d7/a0/a3/a5,-(sp)
  2607.  
  2608.     ifge    \1-1
  2609.     move.l    (Unit3,pc),a3
  2610.     move.l    (daciabase,a3),a5
  2611.     move.b    (ISR,a5),d7
  2612.     and.b    (IERstate,a3),d7    ;Quick check (note that this masking is very
  2613.                 ;important)
  2614.     bne    FastInt    ;Service it
  2615.     endc
  2616.  
  2617.     ifge    \2-1
  2618.     move.l    (_Unit2,pc),a3
  2619.     move.l    (daciabase,a3),a5
  2620.     move.b    (ISR,a5),d7
  2621.     and.b    (IERstate,a3),d7    ;Quick check (note that this masking is very
  2622.                 ;important)
  2623.     bne    FastInt    ;Service it
  2624.     endc
  2625.  
  2626.     ifge    \3-1
  2627.     move.l    (Unit1,pc),a3
  2628.     move.l    (daciabase,a3),a5
  2629.     move.b    (ISR,a5),d7
  2630.     and.b    (IERstate,a3),d7    ;Quick check (note that this masking is very
  2631.                 ;important)
  2632.     bne    FastInt    ;Service it
  2633.     endc
  2634.  
  2635.     ifge    \4-1
  2636.     move.l    (Unit0,pc),a3
  2637.     move.l    (daciabase,a3),a5
  2638.     move.b    (ISR,a5),d7
  2639.     and.b    (IERstate,a3),d7    ;Quick check (note that this masking is very
  2640.                 ;important)
  2641.     bne    FastInt    ;Service it
  2642.     endc
  2643.  
  2644.     movem.l    (sp)+,d0/d7/a0/a3/a5
  2645.     move.l    (OldVec,pc),-(sp)
  2646.     rts
  2647.  
  2648.     endm
  2649.  
  2650. IntRoutines:
  2651.     dc.l    Int0000    ;dummy entry for 0
  2652.     dc.l    Int0001
  2653.     dc.l    Int0010
  2654.     dc.l    Int0011
  2655.     dc.l    Int0100
  2656.     dc.l    Int0101
  2657.     dc.l    Int0110
  2658.     dc.l    Int0111
  2659.     dc.l    Int1000
  2660.     dc.l    Int1001
  2661.     dc.l    Int1010
  2662.     dc.l    Int1011
  2663.     dc.l    Int1100
  2664.     dc.l    Int1101
  2665.     dc.l    Int1110
  2666.     dc.l    Int1111
  2667.  
  2668. ;************* Start of fast interrupt routine **************
  2669.  
  2670. FastInt:
  2671.  
  2672. ;****** NOTE/WARNING:  Reading the ISR will cause the interrupt line
  2673. ;****** to be deasserted, although the bits in the ISR (except for read
  2674. ;****** error bits) will stay set ---- therefore simultaneous
  2675. ;****** conditions MUST!!!! be checked for!!!!!! There is no
  2676. ;****** second chance!
  2677.  
  2678.  
  2679. ;Read error condition?
  2680. ;(Note: Reading the RDR clears the error flags.)
  2681.     move.b    d7,d0
  2682.     and.b    #6,d0
  2683.     bne.b    ReadErr    ;read errors?
  2684.  
  2685.     btst    #ISRB_RDRF,d7    ;Test Receive Data Buffer Full
  2686.     beq.b    DoTDRE
  2687.  
  2688. DoRDRF:
  2689. ;    PUTDEBUG    75,<'%s/Int: Read.'>
  2690.  
  2691. ;Store the byte in the circular buffer.  Note that this code *can't* be
  2692. ;interrupted, so we're safe (that's because CIA B, which we're plugging into,
  2693. ;is connected to INT6*).
  2694.  
  2695.     move.l    (TailLong,a3),d0    ;Read and store
  2696.     move.l    (StartBuf,a3),a0
  2697.     move.b    (RDR,a5),(a0,d0.l)
  2698.     addq.w    #1,(Tail,a3)
  2699.  
  2700. ;Currently waiting for a character?
  2701.     btst    #MDUB_WaitingForChar,(MDU_FLAGS,a3)
  2702.     bne.b    SignalRead    ;yes, signal read task
  2703.     bset    #MDUB_CharAvailable,(MDU_FLAGS,a3)
  2704.  
  2705.     btst    #ISRB_TDRE,d7
  2706.     bne.b    DoTDRE
  2707.  
  2708. ;Return from int routine
  2709.     movem.l    (sp)+,d0/d7/a0/a3/a5
  2710.     move.w    #$2000,(_custom+intreq)
  2711.     rte
  2712.  
  2713. DoTDRE:
  2714. ;Continue with int routine...
  2715.  
  2716. ;We can deduce that the interrupt was caused by TDRE
  2717. ;Therefore we have something to write...
  2718.  
  2719.     tst.l    (WriteCount,a3)
  2720.     beq.b    SetNeedChar
  2721.  
  2722.     bclr    #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
  2723.     move.l    (WriteBufferPtr,a3),a0
  2724.     move.b    (a0)+,(TDR,a5)
  2725.     move.l    a0,(WriteBufferPtr,a3)
  2726.     subq.l    #1,(WriteCount,a3)
  2727.     beq.b    DoneWriting
  2728. EndInt:    movem.l    (sp)+,d0/d7/a0/a3/a5
  2729.     move.w    #$2000,(_custom+intreq)
  2730.     rte
  2731.  
  2732. SetNeedChar:
  2733.     bset    #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
  2734.     bra.b    EndInt
  2735.  
  2736. ReadErr:
  2737.     bra.b    RealReadErr
  2738.  
  2739. SignalRead:
  2740.     bclr    #MDUB_WaitingForChar,(MDU_FLAGS,a3)
  2741.     bset    #MDUB_CharAvailable,(MDU_FLAGS,a3)
  2742.     movem.l    d1/a1/a6,-(sp)
  2743.     movea.l    (mdu_SysLib,a3),a6
  2744.     move.l    (readsig,a3),d0
  2745.     lea    (mdu_rtcb,a3),a1
  2746.     SYS    Signal    ;Signal the read task
  2747.     movem.l    (sp)+,d1/a1/a6
  2748.  
  2749.     btst    #ISRB_TDRE,d7
  2750.     bne    DoTDRE
  2751.  
  2752.     movem.l    (sp)+,d0/d7/a0/a3/a5
  2753.     move.l    (OldVec,pc),-(sp)
  2754.     rts
  2755.  
  2756. DoneWriting:
  2757.  
  2758. ;    PUTDEBUG    75,<'%s/Int: Write signal.'>
  2759.  
  2760.     movem.l    d1/a1/a6,-(sp)
  2761.     move.l    (tdresig,a3),d0
  2762.     lea    (mdu_wtcb,a3),a1
  2763.     movea.l    (mdu_SysLib,a3),a6
  2764.     SYS    Signal    ;Signal the write task
  2765.     movem.l    (sp)+,d1/a1/a6
  2766.     movem.l    (sp)+,d0/d7/a0/a3/a5
  2767.     move.l    (OldVec,pc),-(sp)
  2768.     rts
  2769.  
  2770. ;Exceptional conditions handled here....
  2771.  
  2772. RealReadErr:
  2773.  
  2774. ;An exceptional condition occured - signal the read task
  2775.     movem.l    d1/a1/a6,-(sp)
  2776.     move.b    d7,(ISRcopy,a3)    ;Useful info
  2777.     move.b    (CSR,a5),(CSRcopy,a3) ;More useful info
  2778.     move.l    (readabortsig,a3),d0
  2779.     lea    (mdu_rtcb,a3),a1
  2780.     movea.l    (mdu_SysLib,a3),a6
  2781.     SYS    Signal
  2782.     move.b    (RDR,a5),d0    ;This forces a clear of the error bits
  2783.     movem.l    (sp)+,d1/a1/a6
  2784.  
  2785.     btst    #ISRB_RDRF,d7    ;Test Receive Data Buffer Full
  2786.     bne    DoRDRF
  2787.     btst    #ISRB_TDRE,d7
  2788.     bne    DoTDRE
  2789.  
  2790.     movem.l    (sp)+,d0/d7/a0/a3/a5
  2791.     move.l    (OldVec,pc),-(sp)
  2792.     rts
  2793.  
  2794. ;********* End of fast interrupt routine *********
  2795.  
  2796. Int0000:    DoInt    0,0,0,0
  2797. Int0001:    DoInt    0,0,0,1
  2798. Int0010:    DoInt    0,0,1,0
  2799. Int0011:    DoInt    0,0,1,1
  2800. Int0100:    DoInt    0,1,0,0
  2801. Int0101:    DoInt    0,1,0,1
  2802. Int0110:    DoInt    0,1,1,0
  2803. Int0111:    DoInt    0,1,1,1
  2804. Int1000:    DoInt    1,0,0,0
  2805. Int1001:    DoInt    1,0,0,1
  2806. Int1010:    DoInt    1,0,1,0
  2807. Int1011:    DoInt    1,0,1,1
  2808. Int1100:    DoInt    1,1,0,0
  2809. Int1101:    DoInt    1,1,0,1
  2810. Int1110:    DoInt    1,1,1,0
  2811. Int1111:    DoInt    1,1,1,1
  2812.  
  2813.  
  2814.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  2815.  
  2816. KPutFmt:    move.l    a2,-(sp)
  2817.     lea    (KPutChar,pc),a2
  2818.     bsr.b    KDoFmt
  2819.     movea.l    (sp)+,a2
  2820.     rts
  2821.  
  2822. KDoFmt:    move.l    a6,-(sp)
  2823.     movea.l    (SysBase).w,a6
  2824.     SYS    RawDoFmt
  2825.     movea.l    (sp)+,a6
  2826.     rts
  2827.  
  2828. KPutChar:    move.l    a6,-(sp)
  2829.     movea.l    (SysBase).w,a6
  2830.     SYS    RawPutChar
  2831.     movea.l    (sp)+,a6
  2832.     rts
  2833.  
  2834.     endc
  2835.  
  2836. EndCode:
  2837.     end
  2838.