home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 508.lha / IO_Expansion_Board / NewSER / newser.asm next >
Assembly Source File  |  1991-05-06  |  72KB  |  2,934 lines

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