home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Workbench / Dvices / 8N1V3725.LHA / 8n1_000.s next >
Encoding:
Text File  |  1996-11-30  |  57.4 KB  |  1,918 lines

  1. ********************************************************************************
  2. **                                          **
  3. **  Name       : 8n1_000.s                              **
  4. **  Copyright  : © Copyright 96                           **
  5. **  Author     : Iain Barclay                              **
  6. **  Created    : 30 Nov 96                              **
  7. **  Version    : 37.25                                  **
  8. **                                          **
  9. ********************************************************************************
  10.      ;
  11.      ;      SNMA specific options
  12.      ;
  13.      IFD      SNMA
  14.      ;
  15.      CPU      M68010
  16.      ;
  17.      SNMAOPT  Q,A,M,T,E-
  18.      ;
  19.      ELSE
  20.      machine 68010
  21.      OPT !
  22.      ENDC
  23.      ;
  24.      INCDIR   "dcc:Ainclude/"
  25.      ;
  26.      ;
  27.      ;
  28. DEBUG     SET    0
  29. NEWCODE  SET    1
  30. EOFCODE  SET    1
  31. SETDSR     SET    0
  32. NCOMM     SET    0
  33.      ;
  34.      ;
  35.      ;
  36.      SECTION  text,CODE
  37.      ;
  38.      ;
  39.      ;
  40. DEVICES_SERIAL_I_OBSOLETE  EQU        1
  41.      ;
  42.      ;
  43.      ;
  44.      INCLUDE  "exec/lists.i"
  45.      INCLUDE  "exec/memory.i"
  46.      INCLUDE  "exec/resident.i"
  47.      INCLUDE  "exec/devices.i"
  48.      INCLUDE  "exec/execbase.i"
  49.      INCLUDE  "exec/io.i"
  50.      INCLUDE  "exec/ports.i"
  51.      INCLUDE  "exec/errors.i"
  52.      INCLUDE  "exec/initializers.i"
  53.      INCLUDE  "intuition/preferences.i"
  54.      INCLUDE  "devices/timer.i"
  55.      INCLUDE  "devices/serial.i"
  56.      INCLUDE  "hardware/custom.i"
  57.      INCLUDE  "hardware/cia.i"
  58.      INCLUDE  "hardware/intbits.i"
  59.      INCLUDE  "hardware/adkbits.i"
  60.      INCLUDE  "resources/misc.i"
  61.      INCLUDE  "exec/alerts.i"
  62.      INCLUDE  "exec/macros.i"
  63.      INCLUDE  "8n1.device_rev.i"
  64.      ;
  65.      ;      Define hardware references
  66.      ;
  67.      XREF      _AbsExecBase
  68.      XREF      _custom
  69.      XREF      _intena,_intenar,_intreq,_intreqr
  70.      XREF      _ciab,_ciabpra
  71.      XREF      _serper,_serdat,_serdatr
  72.      XREF      _adkcon,_adkconr
  73.      ;
  74.      ;      Exec Functions
  75.      ;
  76.      XREF      _LVORemDevice,_LVOOpenDevice,_LVOCloseDevice
  77.      XREF      _LVOSupervisor
  78.      XREF      _LVORemove,_LVORemHead,_LVOAddTail
  79.      XREF      _LVOAllocMem,_LVOFreeMem,_LVOCopyMem
  80.      XREF      _LVOReplyMsg
  81.      XREF      _LVOSendIO,_LVOAbortIO
  82.      XREF      _LVODisable,_LVOEnable
  83.      XREF      _LVOFindName
  84.      XREF      _LVOOpenResource
  85.      XREF      _LVOAddIntServer,_LVORemIntServer
  86.      XREF      _LVOSetIntVector
  87.      XREF      _LVOAlert
  88.      XREF      _LVOOpenLibrary,_LVOCloseLibrary
  89.      ;
  90.      ;      Misc Resource Functions
  91.      ;
  92.      XREF      _LVOAllocMiscResource,_LVOFreeMiscResource
  93.      ;
  94.      ;      Intuition Functions
  95.      ;
  96.      XREF      _LVOGetPrefs
  97.      ;
  98.      ;      Mask used to get rid of the printer bits.
  99.      ;
  100. PRTMASK  EQU      (CIAF_PRTRPOUT|CIAF_PRTRBUSY)
  101.      ;
  102.      ;      Autovector offsets
  103.      ;
  104. LVL1VEC  EQU      (1-1)*4+$64
  105. LVL5VEC  EQU      (5-1)*4+$64
  106.      ;
  107.      ;      Device base
  108.      ;
  109.      STRUCTURE Base8n1,LIB_SIZE
  110.      UBYTE      vb_SaveDDRA
  111.      UBYTE      vb_SavePRA
  112.      APTR      vb_MiscBase
  113.      APTR      vb_OldLevel1
  114.      APTR      vb_OldLevel5
  115.      ULONG      vb_SegList
  116.      ULONG      vb_DefBaud
  117.      ULONG      vb_DefRBufLen
  118.      ULONG      vb_CurRBuf
  119.      ULONG      vb_CurRBufLen
  120.      ULONG      vb_CurBaud
  121.      UBYTE      vb_SerFlags
  122.      UBYTE      vb_Initialized
  123.      LABEL      sizeof_Base8n1
  124.      ;
  125.      ;
  126.      ;
  127. DISABLE  MACRO
  128.      IFNC      '\1',''
  129.      move.w   #INTF_\1,_intena
  130.      ELSE
  131.      jsr      _LVODisable(a6)
  132.      ENDC
  133.      ENDM
  134.      ;
  135. ENABLE     MACRO
  136.      IFNC      '\1',''
  137.      move.w   #INTF_SETCLR|INTF_\1,_intena
  138.      ELSE
  139.      jsr      _LVOEnable(a6)
  140.      ENDC
  141.      ENDM
  142.      ;
  143.      ;
  144.      ;
  145. PUTDEBUG macro      ;[msg]
  146.      ifge      DEBUG-2
  147.      movem.l  a0/a1/d0/d1,-(sp)
  148.      lea      (.msg\@,pc),a0  ;Point to static format string
  149.      lea      (4*4,sp),a1      ;Point to args
  150.      XREF      DPutFmt
  151.      bsr      DPutFmt
  152.      movem.l  (sp)+,d0/d1/a0/a1
  153.      bra.b      .end\@
  154.  
  155. .msg\@     dc.b      \1,10,0
  156.      CNUL      0,4
  157. .end\@
  158.      endc
  159.      endm
  160.      ;
  161.      ;
  162.      ;
  163. DEBUG1     MACRO
  164.      IFEQ       DEBUG-1
  165.      XREF      _SendText
  166.      move.l   \2,-(sp)
  167.      pea.l      debug1s\@$
  168.      pea.l      Name
  169.      jsr      _SendText(pc)
  170.      lea.l      12(sp),sp
  171.      bra.b      debug1x\@$
  172. debug1s\@$:
  173.      dc.b      \1,0
  174.      CNOP      0,2
  175. debug1x\@$:
  176.      ENDC
  177.      ENDM
  178. DEBUG0     MACRO
  179.      XREF      _SendText
  180.      pea.l      debug1s\@$
  181.      pea.l      Name
  182.      jsr      _SendText(pc)
  183.      addq      #8,sp
  184.      bra.b      debug1x\@$
  185. debug1s\@$:
  186.      dc.b      \1,0
  187. debug1x\@$:
  188.      ENDM
  189.  
  190. DEBUGIO  MACRO
  191.      IFEQ      DEBUG-1
  192.      lea.l      \1,a0
  193.      jsr      printIO
  194.      ENDC
  195.      ENDM
  196.      ;
  197.      ;
  198.      ;
  199. Start:
  200.      moveq      #-1,d0                  ; set return code
  201.      rts                          ; return
  202.      ;
  203.      ;      RamLib looks for this romtag
  204.      ;
  205. ROMTag     DC.W      RTC_MATCHWORD               ; RT_MATCHWORD
  206.      DC.L      ROMTag                  ; RT_MATCHTAG
  207.      DC.L      ENDTag                  ; RT_ENDSKIP
  208.      DC.B      RTF_AUTOINIT                  ; RT_FLAGS
  209.      DC.B      VERSION                  ; RT_VERSION
  210.      DC.B      NT_DEVICE                  ; RT_TYPE
  211.      DC.B      0                      ; RT_PRI
  212.      DC.L      Name                      ; RT_NAME
  213.      DC.L      IdString                  ; RT_IDSTRING
  214.      DC.L      Init                      ; RT_INIT
  215.      ;
  216.      ;      Perform device initialization
  217.      ;
  218. InitRoutine:
  219.      exg      d0,a0                   ; swap seglist and base
  220.      move.l   d0,vb_SegList(a0)              ; store seglist in base
  221.      move.l   a6,SysBase                  ; store in global storage
  222.      exg      a0,d0                   ; swap them back
  223.      rts                          ; return
  224.      ;
  225.      ;
  226.      ;
  227. dev_Open:
  228.      DEBUG1   "Devstart %lx",#Start
  229.      move.l   a5,-(sp)                  ; save registers
  230.      movea.l  a6,a5                   ; save base
  231.      movea.l  SysBase(pc),a6              ; get ExecBase
  232.      ;
  233.      tst.l      d0                      ; unit 0 specified?
  234.      bne.b      50$                      ; nope, error (who cares?)
  235.      ;
  236.      tst.w      LIB_OPENCNT(a5)              ; currently open?
  237.      bne.b      10$                      ; yep, go process
  238.      ;
  239.      move.b   IO_SERFLAGS(a1),vb_SerFlags(a5)     ; save flags
  240.      ;
  241.      tst.b      vb_Initialized(a5)              ; already initialized?
  242.      bne.b      40$                      ; yep, skip initialization
  243.      ;
  244.      bsr      initResources               ; go alloc resources
  245.      tst.l      d0                      ; initialized?
  246.      bne.b      50$                      ; nope, error
  247.      ;
  248.      bra.b      40$                      ; go exit
  249.      ;
  250. 10$     moveq      #SerErr_DevBusy,d0              ; preset error status
  251.      btst.b   #SERB_SHARED,vb_SerFlags(a5)          ; opened shared?
  252.      beq.b      50$                      ; nope, error
  253.      btst.b   #SERB_SHARED,IO_SERFLAGS(a1)          ; requesting shared?
  254.      beq.b      50$                      ; nope, error
  255.      ;
  256.      ;      Initialize I/O request
  257.      ;
  258. 40$     moveq      #8,d0                   ; get char size
  259.      move.b   d0,IO_READLEN(a1)              ; set read length
  260.      move.b   d0,IO_WRITELEN(a1)              ; set write length
  261.      moveq      #1,d0                   ; get stop bits
  262.      move.b   d0,IO_STOPBITS(a1)              ; set stop bits
  263.      move.b   IO_SERFLAGS(a1),d0
  264.      ori.b      #SERF_XDISABLED|SERF_RAD_BOOGIE|SERF_QUEUEDBRK|SERF_7WIRE,d0 ;flags
  265.      andi.b   #~(SERF_PARTY_ODD|SERF_PARTY_ON),d0 ; not used
  266.      move.b   d0,IO_SERFLAGS(a1)
  267.      move.l   vb_CurBaud(a5),IO_BAUD(a1)          ; set baud
  268.      move.l   vb_CurRBufLen(a5),IO_RBUFLEN(a1)    ; set read buffer length
  269.      ;
  270.      addq.w   #1,LIB_OPENCNT(a5)              ; incr open count
  271.      andi.b   #~(1<<LIBB_DELEXP),LIB_FLAGS(a5)    ; clear expunge bit
  272.      moveq      #0,d0                   ; no error
  273.      ;
  274. 50$     move.b   d0,IO_ERROR(a1)              ; store error code
  275.      movea.l  a5,a6                   ; restore base
  276.      move.l   (sp)+,a5                  ; restore registers
  277.      rts                          ; return
  278.      ;
  279.      ;      Attempt to allocate one of the serial resources.
  280.      ;
  281. allocResource:
  282.      move.l   a6,-(sp)                  ; save base pointer
  283.      move.l   d0,-(sp)                  ; save unit
  284.      lea.l      Name(pc),a1                  ; get lock name
  285.      move.l   vb_MiscBase(a5),a6              ; get MiscBase
  286.      jsr      _LVOAllocMiscResource(a6)          ; go allocate it
  287.      tst.l      d0                      ; did we get it?
  288.      beq.b      20$                      ; yep, branch
  289.      ;
  290.      ;      It's in use, so we try to locate the device using the string
  291.      ;      returned and attempt to remove it.
  292.      ;
  293.      movea.l  SysBase(pc),a6              ; get ExecBase
  294.      ;
  295.      movea.l  d0,a1                   ; get ptr to serial name
  296.      lea.l      DeviceList(a6),a0              ; get ptr to device list
  297.      jsr      _LVOFindName(a6)              ; go find it
  298.      tst.l      d0                      ; found?
  299.      beq.b      10$                      ; nope, branch
  300.      ;
  301.      movea.l  d0,a1                   ; xfer device ptr
  302.      jsr      _LVORemDevice(a6)              ; remove it
  303.      ;
  304.      ;      We then retry the allocate.
  305.      ;
  306. 10$     move.l   (sp),d0                  ; get unit
  307.      lea.l      Name(pc),a1                  ; get lock name
  308.      movea.l  vb_MiscBase(a5),a6              ; get MiscBase
  309.      jsr      _LVOAllocMiscResource(a6)          ; go allocate it
  310.      ;
  311. 20$     addq.l   #4,sp                   ; restore stack ptr
  312.      movea.l  (sp)+,a6                  ; restore base ptr
  313.      rts                          ; return
  314.      ;
  315.      ;
  316.      ;
  317. initResources:
  318.      move.l   a1,-(sp)                  ; save register
  319.      ;
  320.      lea.l      miscresource(pc),a1              ; ptr to resource name
  321.      jsr      _LVOOpenResource(a6)              ; go open it
  322.      move.l   d0,vb_MiscBase(a5)              ; save base
  323.      ;
  324.      moveq      #MR_SERIALPORT,d0              ; set unit number
  325.      bsr.b      allocResource               ; go allocate it
  326.      tst.l      d0                      ; did we get it?
  327.      bne.b      20$                      ; nope, error
  328.      ;
  329.      moveq      #MR_SERIALBITS,d0              ; set unit number
  330.      bsr.b      allocResource               ; go allocate it
  331.      tst.l      d0                      ; did we get it?
  332.      bne.b      10$                      ; nope, error
  333.      ;
  334.      bsr      getPrefs                  ; get default preferences
  335.      tst.l      d0                      ; got 'em?
  336.      beq.b      30$                      ; yep, branch
  337.      ;
  338.      moveq      #MR_SERIALBITS,d0              ; set unit
  339.      movea.l  vb_MiscBase(a5),a6              ; get MiscBase
  340.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  341.      ;
  342. 10$     moveq      #MR_SERIALPORT,d0              ; set unit
  343.      movea.l  vb_MiscBase(a5),a6              ; get MiscBase
  344.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  345.      movea.l  SysBase(pc),a6              ; restore ExecBase
  346.      ;
  347. 20$     moveq      #SerErr_DevBusy,d0              ; set error status
  348.      bra      40$                      ; go return
  349.      ;
  350. 30$     moveq      #0,d1                   ; clear flags
  351.      moveq      #UNIT_VBLANK,d0              ; set unit
  352.      lea.l      timerReq(pc),a1              ; ptr to timer request
  353.      lea.l      timerdevice(pc),a0              ; ptr to device name
  354.      jsr      _LVOOpenDevice(a6)              ; go open it
  355.      ;
  356.      DISABLE                      ; disable interrupts
  357.      ;
  358.      lea.l      _ciab,a1                  ; get ptr to ciab
  359.      move.b   ciaddra(a1),d0
  360.      move.b   d0,vb_SaveDDRA(a5)              ; save DDR value
  361.      andi.b   #PRTMASK,d0                  ; make serial bits input
  362.      move.b   ciapra(a1),d1
  363.      ori.b      #CIAF_COMDTR|CIAF_COMRTS,d0          ; make DTR/RTS output
  364.      move.b   d1,vb_SavePRA(a5)              ; save PR value
  365.      andi.b   #CIAF_COMDTR|CIAF_COMRTS|PRTMASK,d0 ; turn on DTR/RTS
  366.      move.b   d0,ciaddra(a1)
  367.      andi.b   #CIAF_COMCTS|CIAF_COMDSR|PRTMASK,d1 ; make CTS/DSR input
  368.      move.b   d1,ciapra(a1)
  369.      ;
  370.      moveq      #INTB_PORTS,d0              ; get interrupt number
  371.      lea.l      VBInterrupt(pc),a1              ; get interrupt ptr
  372.      jsr      _LVOAddIntServer(a6)              ; add it to the list
  373.      ;
  374.      bsr      getVBR                  ; get vector base (in A0)
  375.      ;
  376.      move.l   LVL1VEC(a0),vb_OldLevel1(a5)          ; save original vector
  377.      lea.l      level1(pc),a1               ; get new vector ptr
  378.      move.l   a1,LVL1VEC(a0)              ; set new vector
  379.      ;
  380.      move.l   LVL5VEC(a0),vb_OldLevel5(a5)          ; save original vector
  381.      lea.l      level5(pc),a1               ; get new vector ptr
  382.      move.l   a1,LVL5VEC(a0)              ; set new vector
  383.      ;
  384.      lea.l      _custom,a1                  ; get ptr to custom chips
  385.      move.w   #INTF_RBF|INTF_TBE,intreq(a1)       ; clear pending interrupts
  386.      move.w   #INTF_SETCLR|INTF_RBF|INTF_TBE,intena(a1) ; enable RBF & TBE
  387.      ;
  388.      addq.b   #1,vb_Initialized(a5)           ; set flag
  389.      moveq      #0,d0                   ; set good status
  390.      ;
  391.      ENABLE                       ; enable interrupts
  392.      ;
  393. 40$     movea.l  (sp)+,a1                  ; restore register
  394.      rts                          ; return
  395.      ;
  396.      ;      Get system preferences
  397.      ;
  398. getPrefs:
  399.      move.l   a1,-(sp)                  ; save registers
  400.      ;
  401.      lea.l      intuitlib(pc),a1              ; ptr to library name
  402.      moveq      #0,d0                   ; can't use OldOpenLibrary as this will not be supported.
  403.      jsr      _LVOOpenLibrary(a6)              ; go open it (any version)
  404.      movea.l  d0,a6                   ; get intuition base
  405.      ;
  406.      move.l   #(pf_SerParShk+3)&$fffffffc,d0      ; size we need (aligned)
  407.      suba.l   d0,sp                   ; reserve space
  408.      ;
  409.      movea.l  sp,a0                   ; set data area ptr
  410.      jsr      _LVOGetPrefs(a6)              ; get preferences
  411.      ;
  412.      movea.l  a6,a1                   ; get intuition base
  413.      movea.l  SysBase(pc),a6              ; restore ExecBase
  414.      jsr      _LVOCloseLibrary(a6)              ; close it
  415.      ;
  416.      moveq      #$0f,d1                  ; set mask
  417.      and.b      pf_SerStopBuf(sp),d1              ; get bufsize index
  418.      addq.l   #8,d1                   ; calc shift value
  419.      moveq      #2,d0                   ; get 1<<1
  420.      lsl.l      d1,d0                   ; get default bufsize
  421.      move.l   d0,vb_DefRBufLen(a5)              ; and store
  422.      ;
  423.      moveq      #0,d1                   ; clear upper half
  424.      move.w   pf_BaudRate(sp),d1              ; get baud rate
  425.      add.l      d1,d1                   ; generate offset
  426.      move.w   baudTable(pc,d1.w),d1           ; get default baud
  427.      move.l   d1,vb_DefBaud(a5)              ; and store
  428.      ;
  429.      bsr      internalReset               ; go init baud and buffer
  430.      ;
  431.      lea.l      (pf_SerParShk+3)&$fffffffc(sp),sp   ; restore stack
  432.      movea.l  (sp)+,a1                  ; restore registers
  433.      rts                          ; return ( status in D0 )
  434.      ;
  435.      ;      Preferences baud lookup table
  436.      ;
  437. baudTable:
  438.      dc.w      112,300,1200,2400,4800,9600,19200,31250,38400,57600,62400,64800
  439.      ;
  440.      ;      Set exception vectors
  441.      ;
  442. getVBR:
  443.      move.l   a5,-(sp)                  ; save registers
  444.      suba.l   a0,a0                   ; ptr to vector base (68000)
  445.      btst.b   #AFB_68010,AttnFlags+1(a6)          ; 68010 or higher?
  446.      beq.b      10$                      ; nope, go set vector
  447.      lea.l      20$(pc),a5                  ; ptr to routine
  448.      jsr      _LVOSupervisor(a6)              ; get into supervisor state
  449. 10$     movea.l  (sp)+,a5                  ; restore register
  450.      rts                          ; return
  451. 20$     movec.l  vbr,a0                  ; get vector base
  452.      rte                          ; return
  453.      ;
  454.      ;
  455.      ;
  456. freeResources:
  457.      move.l   a1,-(sp)                  ; save registers
  458.      ;
  459.      DISABLE                      ; disable interrupts
  460.      ;
  461.      bsr      getVBR                  ; get vector base (in A0)
  462.      ;
  463.      moveq      #1,d0                   ; set not restored code
  464.      ;
  465.      lea.l      level1(pc),a1               ; get our vector ptr
  466.      cmpa.l   LVL1VEC(a0),a1              ; do they match?
  467.      bne      10$                      ; nope, can't restore
  468.      ;
  469.      lea.l      level5(pc),a1               ; get our vector ptr
  470.      cmpa.l   LVL5VEC(a0),a1              ; do they match?
  471.      bne      10$                      ; nope, can't restore
  472.      ;
  473.      move.l   vb_OldLevel1(a5),LVL1VEC(a0)          ; restore original vector
  474.      move.l   vb_OldLevel5(a5),LVL5VEC(a0)          ; restore original vector
  475.      ;
  476.      moveq      #INTB_PORTS,d0              ; get interrupt number
  477.      lea.l      VBInterrupt(pc),a1              ; get interrupt ptr
  478.      jsr      _LVORemIntServer(a6)              ; remove it from the list
  479.      ;
  480.      lea.l      _custom,a0
  481.      move.w   #INTF_RBF|INTF_TBE,d0           ; indicate serial interrupts
  482.      move.w   d0,_intena(a0)              ; disable interrupts
  483.      move.w   d0,_intreq(a0)              ; clear pending interrupts
  484.      ;
  485.      bsr      freeBuf                  ; free allocated buffers
  486.      ;
  487.      lea.l      _ciab,a0                  ; get pointer to ciab
  488.      move.b   ciaddra(a0),d0              ; get DDR value
  489.      andi.b   #PRTMASK,d0                  ; save printer bits
  490.      ori.b      #~PRTMASK,d0                  ; set serial bits to output
  491.      move.b   d0,ciaddra(a0)              ; store value
  492.      ;
  493.      move.b   ciapra(a0),d0               ; get PR value
  494.      andi.b   #PRTMASK,d0                  ; mask out serial bits
  495.      move.b   vb_SavePRA(a5),d1              ; get saved value
  496.      andi.b   #~PRTMASK,d1                  ; mask out printer bits
  497.      or.b      d1,d0                   ; combine the two
  498.      move.b   d0,ciapra(a0)               ; and store
  499.      ;
  500.      move.b   ciaddra(a0),d0              ; get DDR value
  501.      andi.b   #PRTMASK,d0                  ; mask out serial bits
  502.      move.b   vb_SaveDDRA(a5),d1              ; get saved value
  503.      andi.b   #~PRTMASK,d1                  ; mask out printer bits
  504.      or.b      d1,d0                   ; combine the two
  505.      move.b   d0,ciaddra(a0)              ; and store
  506.      ;
  507.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  508.      jsr      _LVOCloseDevice(a6)              ; go close it
  509.      ;
  510.      movea.l  vb_MiscBase(a5),a6              ; get MiscBase
  511.      moveq      #MR_SERIALBITS,d0              ; set unit
  512.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  513.      ;
  514.      moveq      #MR_SERIALPORT,d0              ; set unit
  515.      jsr      _LVOFreeMiscResource(a6)          ; release the resource
  516.      movea.l  SysBase(pc),a6              ; restore ExecBase
  517.      ;
  518.      ENABLE                       ; enable interrupts
  519.      ;
  520.      subq.b   #1,vb_Initialized(a5)           ; clear flag
  521.      moveq      #0,d0                   ; free up everything
  522.      ;
  523. 10$     movea.l  (sp)+,a1                  ; restore registers
  524.      rts                          ; return
  525.      ;
  526.      ;      Device Close routine
  527.      ;
  528. dev_Close:
  529.      ;
  530.      moveq      #-1,d0                  ; invalidate
  531.      move.l   d0,IO_DEVICE(a1)              ;   device
  532.      ;
  533.      subq.w   #1,LIB_OPENCNT(a6)              ; decr open count
  534.      bne.b      dev_Null                  ; still open? yep, branch
  535.      ;
  536.      move.l   a5,-(sp)                  ; save registers
  537.      movea.l  a6,a5                   ; save base
  538.      movea.l  SysBase(pc),a6              ; get ExecBase
  539.      ;
  540.      bsr      freeResources               ; free allocated resources
  541.      ;
  542.      movea.l  a5,a6                   ; restore base
  543.      movea.l  (sp)+,a5                  ; restore registers
  544.      ;
  545.      tst.l      d0                      ; freed?
  546.      bne.b      dev_Null                  ; nope, can't expunge, exit
  547.      ;
  548.      clr.b      vb_SerFlags(a6)              ; clear flags
  549.      ;
  550.      btst.b   #LIBB_DELEXP,LIB_FLAGS(a6)          ; delayed expunge set?
  551.      beq.b      dev_Null                  ; nope, go exit
  552.      ;
  553.      ;      Device Expunge routine (also fall through from dev_Close)
  554.      ;
  555. dev_Expunge:
  556.      ori.b      #1<<LIBB_DELEXP,LIB_FLAGS(a6)       ; Set expunge flag
  557.      tst.w      LIB_OPENCNT(a6)              ; currently open?
  558.      bne.b      dev_Null                  ; yep, so just exit
  559.      ;
  560.      move.l   vb_SegList(a6),d0              ; get seglist ptr
  561.      movem.l  d0/a5/a6,-(sp)              ; save registers (save D0!)
  562.      ;
  563.      movea.l  a6,a5                   ; save base
  564.      movea.l  SysBase(pc),a6              ; get ExecBase
  565.      movea.l  a5,a1                   ; get base
  566.      jsr      _LVORemove(a6)              ; Remove it
  567.      ;
  568.      movea.l  a5,a1                   ; get base
  569.      moveq      #0,d0                   ; clear work
  570.      move.w   LIB_NEGSIZE(a5),d0              ; calculate
  571.      suba.w   d0,a1                   ;   memory address
  572.      add.w      LIB_POSSIZE(a5),d0              ;     and size
  573.      jsr      _LVOFreeMem(a6)              ; free it
  574.      ;
  575.      movem.l  (sp)+,d0/a5/a6              ; restore registers
  576.      rts                          ; return (seglist in D0!)
  577.      ;
  578.      ;      Device "ExtFunc" routine
  579.      ;
  580. dev_Null:
  581.      moveq      #0,d0                   ; set return code
  582.      rts                          ; return
  583.      ;
  584.      ;
  585.      ;
  586.      IFEQ      DEBUG-1
  587. printIO:
  588.      movem.l  d0-d7/a0-a6,-(sp)
  589.      addq.l   #1,ioctr
  590.      move.l   ioctr,-(sp)
  591.      move.l   a1,-(sp)
  592.      move.l   a0,-(sp)
  593.      pea.l      0$
  594.      pea.l      Name
  595.      DISABLE  TBE|INTF_PORTS
  596.      jsr      _SendText(pc)
  597.      ENABLE   TBE|INTF_PORTS
  598.      lea.l      20(sp),sp
  599.  
  600.      moveq      #0,d0
  601.      move.w   IO_COMMAND(a1),d0
  602.      move.l   d0,-(sp)
  603.      move.l   MN_REPLYPORT(a1),-(sp)
  604.      moveq      #0,d0
  605.      move.b   LN_TYPE(a1),d0
  606.      move.l   d0,-(sp)
  607.      pea.l      1$
  608.      pea.l      Name
  609.      DISABLE  TBE|INTF_PORTS
  610.      jsr      _SendText(pc)
  611.      ENABLE   TBE|INTF_PORTS
  612.      lea.l      20(sp),sp
  613.  
  614.      move.l   IO_LENGTH(a1),-(sp)
  615.      moveq      #0,d0
  616.      move.b   IO_ERROR(a1),d0
  617.      move.l   d0,-(sp)
  618.      move.b   IO_FLAGS(a1),d0
  619.      move.l   d0,-(sp)
  620.      pea.l      2$
  621.      pea.l      Name
  622.      DISABLE  TBE|INTF_PORTS
  623.      jsr      _SendText(pc)
  624.      ENABLE   TBE|INTF_PORTS
  625.      lea.l      20(sp),sp
  626.  
  627.      move.l   IO_EXTFLAGS(a1),-(sp)
  628.      move.l   IO_RBUFLEN(a1),-(sp)
  629.      move.l   IO_ACTUAL(a1),-(sp)
  630.      pea.l      3$
  631.      pea.l      Name
  632.      DISABLE  TBE|INTF_PORTS
  633.      jsr      _SendText(pc)
  634.      ENABLE   TBE|INTF_PORTS
  635.      lea.l      20(sp),sp
  636.  
  637.      moveq      #0,d0
  638.      move.b   IO_WRITELEN(a1),d0
  639.      move.l   d0,-(sp)
  640.      move.b   IO_READLEN(a1),d0
  641.      move.l   d0,-(sp)
  642.      move.l   IO_BAUD(a1),-(sp)
  643.      pea.l      4$
  644.      pea.l      Name
  645.      DISABLE  TBE|INTF_PORTS
  646.      jsr      _SendText(pc)
  647.      ENABLE   TBE|INTF_PORTS
  648.      lea.l      20(sp),sp
  649.  
  650.      moveq      #0,d0
  651.      move.w   IO_STATUS(a1),d0
  652.      move.l   d0,-(sp)
  653.      moveq      #0,d0
  654.      move.b   IO_SERFLAGS(a1),d0
  655.      move.l   d0,-(sp)
  656.      move.b   IO_STOPBITS(a1),d0
  657.      move.l   d0,-(sp)
  658.      pea.l      5$
  659.      pea.l      Name
  660.      DISABLE  TBE|INTF_PORTS
  661.      jsr      _SendText(pc)
  662.      ENABLE   TBE|INTF_PORTS
  663.      lea.l      20(sp),sp
  664.      movem.l  (sp)+,d0-d7/a0-a6
  665.      rts
  666. 0$     dc.b      '%ls - I/O     %8lx, Cnt = %ld',0
  667. 1$     DC.B      'Type    %8ld     ReplyPort %8lx    Command  %8ld',0
  668. 2$     DC.B      'Flags   %8lx     Error     %8ld    Length   %8ld',0
  669. 3$     DC.B      'Actual  %8ld     RBufLen   %8ld    ExtFlags %8lx',0
  670. 4$     DC.B      'Baud    %8ld     ReadLen   %8ld    WriteLen %8ld',0
  671. 5$     DC.B      'StopBit %8ld     SerFlags  %8lx    Status   %8lx',0
  672.      ;
  673.      ;
  674.      ;
  675. abortIOs dc.b      'Abort Start',0
  676. abortIOe dc.b      'Abort End',0
  677. abortIOa dc.b      'Aborting',0
  678. beginIOs dc.b      'Begin Start',0
  679. beginIOe dc.b      'Begin End',0
  680. openIO     dc.b      'Open IO',0
  681. replyIO  dc.b      'replyIO',0
  682.      ds.l      0
  683. ioctr     dc.l      0
  684.      ENDC
  685.      ;
  686. cmdTable dc.w      cmd_Invalid-cmdTable              ; CMD_INVALID
  687.      dc.w      cmd_Reset-cmdTable              ; CMD_RESET
  688.      dc.w      cmd_Read-cmdTable              ; CMD_READ
  689.      dc.w      cmd_Write-cmdTable              ; CMD_WRITE
  690.      dc.w      cmd_Invalid-cmdTable              ; CMD_UPDATE
  691.      dc.w      cmd_Clear-cmdTable              ; CMD_CLEAR
  692.      dc.w      cmd_Invalid-cmdTable              ; CMD_STOP
  693.      dc.w      cmd_Invalid-cmdTable              ; CMD_START
  694.      dc.w      cmd_Flush-cmdTable              ; CMD_FLUSH
  695.      dc.w      sdcmd_Query-cmdTable              ; SDCMD_QUERY
  696.      dc.w      sdcmd_Break-cmdTable              ; SDCMD_BREAK
  697. endTable dc.w      sdcmd_SetParams-cmdTable          ; SDCMD_SETPARAMS
  698.      ;
  699.      ;      Device BeginIO routine
  700.      ;
  701. dev_BeginIO:
  702.      move.l   a5,-(sp)                  ; save register
  703.      movea.l  a6,a5                   ; save base
  704.      movea.l  SysBase(pc),a6              ; get ExecBase
  705.      DEBUGIO  beginIOs
  706.      ;
  707.      move.b   #NT_MESSAGE,LN_TYPE(a1)          ; set type
  708.      clr.b      IO_ERROR(a1)                  ; clear error
  709.      ;
  710.      andi.b   #~(IOSERF_QUEUED|IOSERF_ACTIVE),IO_FLAGS(a1) ; clear flags
  711.      ;
  712.      move.w   IO_COMMAND(a1),d0              ; get command
  713.      add.w      d0,d0                   ; multiply by 2
  714.      cmpi.w   #endTable-cmdTable,d0           ; in range?
  715.      bhi.b      30$                      ; nope, error
  716.      ;
  717.      move.w   cmdTable(pc,d0.w),d0              ; get routine offset
  718.      jsr      cmdTable(pc,d0.w)              ; go do it
  719.      tst.l      d0                      ; I/O completed?
  720.      bne.b      19$                      ; nope, go return
  721.      ;
  722. 10$     DEBUGIO  beginIOe
  723.      btst.b   #IOB_QUICK,IO_FLAGS(a1)          ; need to reply?
  724.      bne.b      20$                      ; nope, branch
  725. 15$     jsr      _LVOReplyMsg(a6)              ; send it back
  726.      ;
  727. 19$     andi.b   #~(1<<IOB_QUICK),IO_FLAGS(a1)         ; clear quick bit
  728. 20$     movea.l  a5,a6                   ; restore base
  729.      movea.l  (sp)+,a5                  ; restore register
  730.      rts                          ; return
  731.      ;
  732. 30$     move.b   #IOERR_NOCMD,IO_ERROR(a1)          ; invalid command
  733.      bra.b      10$                      ; branch
  734.      ;
  735.      ;      Device AbortIO routine
  736.      ;
  737. dev_AbortIO:
  738.      move.l   a5,-(sp)                  ; save registers
  739.      movea.l  a6,a5                   ; save base
  740.      movea.l  SysBase(pc),a6              ; get ExecBase
  741.      DEBUGIO  abortIOs
  742.      ;
  743.      DISABLE                      ; disable interrupts
  744.      ;
  745.      move.b   IO_FLAGS(a1),d1
  746.      btst.b   #IOSERB_QUEUED,d1              ; queued request?
  747.      bne.b      40$                      ; yep, branch
  748.      ;
  749.      btst.b   #1<<IOSERB_ACTIVE,d1              ; active request?
  750.      bne.b      10$                      ; nope, just exit
  751.      ;
  752.      move.w   IO_COMMAND(a1),d0              ; get command
  753.      subq.w   #CMD_READ,d0                  ; was it a read?
  754.      beq.b      20$                      ; yep, go process
  755.      ;
  756.      subq.w   #CMD_WRITE-CMD_READ,d0          ; was it a write?
  757.      beq.b      30$                      ; yep, go process
  758.      ;
  759.      subq.w   #SDCMD_BREAK-CMD_WRITE,d0          ; was it a break?
  760.      beq.b      30$                      ; yep, go process
  761.      ;
  762.      ;      Fall through or enter from below
  763.      ;
  764. 10$     ENABLE                       ; enable ints and return
  765. 15$     movea.l  a5,a6                   ; restore base
  766.      movea.l  (sp)+,a5                  ; restore registers
  767.      rts                          ; return
  768.      ;
  769.      ;      Abort an active read request
  770.      ;
  771. 20$     clr.l      cr_IOReq                  ; no longer active
  772.      bra.b      50$                      ; go set flags
  773.      ;
  774.      ;      Abort an active write request
  775.      ;
  776. 30$     clr.l      cw_Length                  ; no longer active
  777.      clr.l      cw_IOReq                  ; no longer active
  778.      move.l   cw_Buffer(pc),d0              ; get buffer ptr
  779.      sub.l      IO_DATA(a1),d0              ; calc number of bytes xfer'd
  780.      move.l   d0,IO_ACTUAL(a1)              ; store
  781.      ;
  782.      ;      Force a TBE interrupt to get the next write going.
  783.      ;
  784.      move.w   #INTF_SETCLR|INTF_TBE,_intreq       ; make TBE pending
  785.      bra.b      50$                      ; go set flags
  786.      ;
  787.      ;      Remove I/O from queue.
  788.      ;
  789. 40$     move.l   a1,-(sp)                  ; save ptr
  790.      jsr      _LVORemove(a6)              ; remove it
  791.      movea.l  (sp)+,a1                  ; restore ptr
  792.      ;
  793.      ;      Set error and return I/O
  794.      ;
  795. 50$     move.b   #IOERR_ABORTED,IO_ERROR(a1)          ; set error code
  796.      move.b   IO_FLAGS(a1),d1              ; get flags
  797.      ori.b      #1<<IOSERB_ABORT,d1              ; set abort flag
  798.      andi.b   #~(IOSERF_QUEUED|IOSERF_ACTIVE),d1  ; clear flags
  799.      move.b   d1,IO_FLAGS(a1)              ; store flags
  800.      DEBUGIO  abortIOe
  801.      btst.b   #1<<IOB_QUICK,d1              ; need to reply?
  802.      bne.b      10$                      ; nope, branch
  803.      jsr      _LVOReplyMsg(a6)              ; send it back
  804.      bra.b      10$                      ; branch to return
  805.      ;
  806.      ;      Abort all active/queued commands and reset internal state
  807.      ;
  808. cmd_Reset:
  809.      move.l   a1,-(sp)                  ; save I/O request
  810.      bsr.b      cmd_Flush                  ; go abort queued requests
  811.      ;
  812.      DISABLE                      ; disable interrupts
  813.      ;
  814.      ;      This must follow the DISABLE
  815.      ;
  816.      exg      a5,a6                   ; exchange base and ExecBase
  817.      ;
  818.      move.l   cr_IOReq(pc),d0              ; active read?
  819.      beq.b      10$                      ; nope, branch
  820.      movea.l  d0,a1                   ; get I/O request
  821.      bsr      dev_AbortIO                  ; go abort it
  822.      ;
  823.      ;
  824.      ;
  825. 10$     move.l   cw_IOReq(pc),d0              ; active write?
  826.      beq.b      20$                      ; nope, branch
  827.      movea.l  d0,a1                   ; get I/O request
  828.      bsr      dev_AbortIO                  ; go abort it
  829.      ;
  830. 20$     exg      a5,a6                   ; restore base and ExecBase
  831.      movea.l  (sp)+,a1                  ; restore I/O request
  832.      moveq      #8,d0                   ; get char size
  833.      move.b   d0,IO_READLEN(a1)              ; set read length
  834.      move.b   d0,IO_WRITELEN(a1)              ; set write length
  835.      moveq      #1,d0                   ; get stop bits
  836.      move.b   d0,IO_STOPBITS(a1)              ; set stop bits
  837.      move.l   vb_DefBaud(a5),IO_BAUD(a1)          ; set to default baud
  838.      move.l   vb_DefRBufLen(a5),IO_RBUFLEN(a1)    ; set to default buflen
  839.      bsr      internalReset               ; go set/verify parameters
  840.      move.b   d0,IO_ERROR(a1)              ; set error code
  841.      ENABLE                       ; enable interrupts
  842.      ;
  843.      ;      Set RC and return
  844.      ;
  845.      moveq      #0,d0                   ; I/O complete
  846.      rts                          ; return
  847.      ;
  848.      ;      Abort all "queued" requests, leaving all active alone.
  849.      ;
  850. cmd_Flush:
  851.      movem.l  a1/a2,-(sp)                  ; save registers
  852.      DISABLE                      ; disable interrupts
  853.      ;
  854.      ;      Abort all queued read requests.
  855.      ;
  856.      lea.l      readQ(pc),a2                  ; get ptr to read queue
  857.      bsr.b      20$                      ; branch to abort
  858.      ;
  859.      ;      Abort all queued write requests.
  860.      ;
  861.      lea.l      writeQ(pc),a2               ; get ptr to write queue
  862.      bsr.b      20$                      ; branch to abort
  863.      ;
  864.      ;      Enable, restore, and return to caller
  865.      ;
  866.      ENABLE                       ; enable interrupts
  867.      movem.l  (sp)+,a1/a2                  ; restore registers
  868.      ;
  869.      ;      Set RC and return
  870.      ;
  871.      moveq      #0,d0                   ; I/O complete
  872.      ;
  873.      ;      !!!NOTE!!!  In a mad attempt to save 2 bytes, this RTS is used
  874.      ;      by the subroutine below.  Why waste 'em?  B-)
  875.      ;
  876. 10$     rts                          ; return ( used below too!! )
  877.      ;
  878.      ;      Subroutine to remove and reply each I/O request.
  879.      ;
  880. 20$     movea.l  a2,a0                   ; get list ptr
  881.      jsr      _LVORemHead(a6)              ; get I/O request
  882.      tst.l      d0                      ; end of list?
  883.      beq.b      10$                      ; yep, branch to return
  884.      ;
  885.      movea.l  d0,a1                   ; get I/O request
  886.      andi.b   #~(1<<IOSERB_QUEUED),IO_FLAGS(a1)   ; no longer queued
  887.      moveq      #IOERR_ABORTED,d0              ; indicate aborted
  888.      move.b   d0,IO_ERROR(a1)              ; store status
  889.      ;
  890.      jsr      _LVOReplyMsg(a6)              ; send it back
  891.      bra.b      20$                      ; continue with next
  892.      ;
  893.      ;      Process a CMD_READ request.
  894.      ;
  895. cmd_Read:
  896.      ;
  897.      ;      Zero length requests just get returned.
  898.      ;
  899.      clr.l      IO_ACTUAL(a1)               ; clear bytes read
  900.      move.l   IO_LENGTH(a1),d0              ; get length and test
  901.      beq.b      20$                      ; yep, leave
  902.      ;
  903.      ;      This can be used to circumvent a bug in NComm 3.0 which
  904.      ;      references the buffer even when there was nothing read.
  905.      ;
  906.     IFNE     NCOMM
  907.      move.l   IO_DATA(A1),a0              ; get data pointer
  908.      clr.b      (a0)                      ; clear first byte in buffer
  909.     ENDC
  910.      ;
  911.      ;      The disable counter works just like exec's TDNestCnt field.  It's
  912.      ;      initialized to -1.  After incrementing, if it is 0, then we
  913.      ;      can attempt to process this request immediately.  If it's > 0,
  914.      ;      then we're already disabled and we must queue this request.
  915.      ;
  916.      addq.b   #1,disableRead              ; incr disable count
  917.      bgt.b      50$                      ; >0, already disabled
  918.      ;
  919.      ;      If we're already processing an request, this one has to wait
  920.      ;      until that one is done, so go queue it.
  921.      ;
  922.      move.l   cr_IOReq(pc),d1              ; have an active request?
  923.      bne.b      50$                      ; yep, go queue this one
  924.      ;
  925.      ;      If we don't have enough bytes to satisfy this request then go
  926.      ;      queue it.
  927.      ;
  928.      cmp.l      i_InCnt(pc),d0              ; length > current bytes?
  929.      bgt.b      50$                      ; yep, go queue it
  930.      ;
  931.      ;      Setup fields and go copy the data
  932.      ;
  933.      move.l   IO_DATA(a1),cr_OutPtr           ; get/set output ptr
  934.      move.l   IO_LENGTH(a1),cr_Length          ; get/set output count
  935.      bsr      copyData                  ; go copy 'em
  936.      moveq      #0,d0                   ; I/O complete
  937.      ;
  938.      ;      We're done, so back off the disable counter.
  939.      ;
  940. 10$     subq.b   #1,disableRead              ; decr disable count
  941.      ;
  942.      ;      Return to caller
  943.      ;
  944. 20$     rts                          ; return
  945.      ;
  946.      ;      Just set flags and queue.  The read interrupt will handle it.
  947.      ;
  948. 50$     ori.b      #1<<IOSERB_QUEUED,IO_FLAGS(a1)      ; indicate queued
  949.      ;
  950.      ;      Add this request to the end.
  951.      ;
  952.      DISABLE                      ; disable interrupts
  953.      lea.l      readQ(pc),a0                  ; get pointer to read queue
  954.      move.l   a1,-(sp)                  ; save I/O request
  955.      jsr      _LVOAddTail(a6)              ; and queue it
  956.      movea.l  (sp)+,a1                  ; restore I/O request
  957.      ENABLE                       ; enable interrupts
  958.      ;
  959.      ;      Indicate that this request was not handled immediatly.
  960.      ;
  961.      moveq      #1,d0                   ; I/O not complete
  962.      bra.b      10$                      ; branch to return
  963.      ;
  964.      ;      Process a CMD_WRITE request.
  965.      ;
  966. cmd_Write:
  967.      clr.l      IO_ACTUAL(a1)               ; clear bytes written
  968.     IFNE NEWCODE
  969.      tst.l      IO_LENGTH(a1)               ; get length and test
  970.     ELSE
  971.      move.l   IO_LENGTH(a1),d0              ; get length and test
  972.     ENDC
  973.      beq.b      wbexit                  ; yep, leave
  974.      ;
  975.      ;      Entry point for Break command and fall through from cmd_Write.
  976.      ;
  977. sdcmd_Break:
  978.      ;
  979.      ;      Just set flags and queue. The TBE interrupt will handle it.
  980.      ;
  981.      ori.b      #1<<IOSERB_QUEUED,IO_FLAGS(a1)      ; indicate queued
  982.      ;
  983.      ;      Protect.
  984.      ;
  985.      DISABLE                      ; disable interrupts
  986.      ;
  987.      ;      Add request to end of queue.
  988.      ;
  989.      lea.l      writeQ(pc),a0               ; get queue list ptr
  990.      move.l   a1,-(sp)                  ; save I/O request
  991.      jsr      _LVOAddTail(a6)              ; and queue it
  992.      movea.l  (sp)+,a1                  ; restore I/O request
  993.      ;
  994.      ;      If we have an active request, don't force interrupt.
  995.      ;
  996.      move.l   cw_IOReq(pc),d0              ; have an active request?
  997.      bne.b      10$                      ; yep, branch
  998.      ;
  999.      ;      Force a TBE interrupt to get the writes going.
  1000.      ;
  1001.      move.w   #INTF_SETCLR|INTF_TBE,_intreq       ; make TBE pending
  1002.      ;
  1003.      ;      Enable, set RC and return to caller.
  1004.      ;
  1005. 10$     ENABLE                       ; enable interrupts
  1006.      moveq      #1,d0                   ; I/O not complete
  1007. wbexit     rts                          ; return
  1008.      ;
  1009.      ;      Resets serial read buffer
  1010.      ;
  1011.      ;      Since this routine is called internally, it must NOT reference
  1012.      ;      the I/O request.
  1013.      ;
  1014. cmd_Clear:
  1015.      DISABLE                      ; disable interrupts
  1016.      ;
  1017.      ;      Load registers
  1018.      ;
  1019.      move.l   vb_CurRBuf(a5),d0              ; get internal buffer ptr
  1020.      move.l   vb_CurRBufLen(a5),d1              ; and internal buffer len
  1021.      lea.l      i_BufPtr(pc),a0              ; get ptr internal control
  1022.      ;
  1023.      ;      Initialize global buffer variables
  1024.      ;
  1025.      move.l   d0,(a0)                  ; store buffer ptr
  1026.      move.l   d0,4(a0)                  ; set current input ptr
  1027.      move.l   d0,8(a0)                  ; set current output ptr
  1028.      add.l      d1,d0                   ; add buffer length
  1029.      move.l   d0,12(a0)                  ; store ptr to end of buffer
  1030.      clr.l      16(a0)                  ; clear byte cnt
  1031.      move.l   vb_CurBaud(a5),d0              ; get internal baud
  1032.      lsr.l      #4,d0                   ; divide by 16
  1033.      sub.l      d0,d1                   ; subtract from length
  1034.      move.l   d1,20(a0)                  ; set threshold
  1035.      ;
  1036.      ;      Enable, set RC and return.
  1037.      ;
  1038.      ENABLE                       ; enable interrupts
  1039.      moveq      #0,d0                   ; I/O complete
  1040.      rts                          ; return
  1041.      ;
  1042.      ;
  1043.      ;
  1044. cmd_Invalid
  1045.      move.b   #IOERR_NOCMD,IO_ERROR(a1)          ; set bad status
  1046.      moveq      #0,d0                   ; I/O complete
  1047.      rts                          ; return
  1048.      ;
  1049.      ;      Returns number of bytes currently in internal buffer and
  1050.      ;      current serial port status.
  1051.      ;
  1052.      ;      NOTE:  Not completely compatible with standard serial.device
  1053.      ;      since it doesn't return the upper byte of IO_STATUS.
  1054.      ;
  1055. sdcmd_Query:
  1056.      DISABLE                      ; disable interrupts
  1057.      moveq      #0,d0                   ; clear d0
  1058.      move.b   _ciabpra,d0                  ; get PR register
  1059.      andi.w   #~PRTMASK,d0                  ; zap printer bits
  1060.      ;
  1061.      ;      Uncomment the following to turn on the DSR bit.  This was done
  1062.      ;      for a user whose DSR pin did not function.
  1063.      ;
  1064.     IFNE SETDSR
  1065.      andi      #~(1<<CIAB_COMDSR),d0             ; set DSR
  1066.     ENDC
  1067.      ;
  1068.      ;
  1069.      ;
  1070.      move.w   d0,IO_STATUS(a1)              ; store status
  1071.      move.l   i_InCnt(pc),IO_ACTUAL(a1)          ; byte left in buffer
  1072.      ;
  1073.      ;      Enable, set RC and return.
  1074.      ;
  1075.      ENABLE                       ; enable interrupts
  1076.      moveq      #0,d0                   ; I/O complete
  1077.      rts                          ; return
  1078.      ;
  1079.      ;
  1080.      ;
  1081. sdcmd_SetParams:
  1082.      ;
  1083.      ;      Validate the read, write, and stop bit lengths.
  1084.      ;
  1085.      moveq      #8,d0                   ; get char length
  1086.      cmp.b      IO_READLEN(a1),d0              ; 8 bit chars for read?
  1087.      bne.b      40$                      ; nope, branch
  1088.      cmp.b      IO_WRITELEN(a1),d0              ; 8 bit chars for write?
  1089.      bne.b      40$                      ; nope, branch
  1090.      moveq      #1,d0                   ; get stop bits
  1091.      cmp.b      IO_STOPBITS(a1),d0              ; 1 stop bit?
  1092.      bne.b      40$                      ; nope, branch
  1093.      ;
  1094.      ;      Get and validate the baud rate.
  1095.      ;
  1096.      move.l   IO_BAUD(a1),d1              ; get baud from I/O req
  1097.      bne.b      20$                      ; specified?
  1098.      move.l   vb_CurBaud(a5),d1              ; get current baud from base
  1099.      bne.b      20$                      ; specified?
  1100.      move.l   vb_DefBaud(a5),d1              ; get default baud from base
  1101. 20$     cmpi.l   #110,d1                  ; too low?
  1102.      blt.b      40$                      ; error
  1103.      cmpi.l   #292000,d1                  ; too high?
  1104.      bgt.b      40$                      ; error
  1105.      ;
  1106.      ;      Get and validate the buffer length.
  1107.      ;
  1108.      move.l   IO_RBUFLEN(a1),d0              ; get buffer length
  1109.      bne.b      30$                      ; specified?
  1110.      move.l   vb_CurRBufLen(a5),d0              ; get current from base
  1111.      bne.b      30$                      ; specified?
  1112.      move.l   vb_DefRBufLen(a5),d0              ; get default from base
  1113.      ;
  1114. 30$     bsr.b      internalReset               ; go init baud and buffer
  1115. 35$     move.b   d0,IO_ERROR(a1)              ; set error code
  1116.      bne.b      39$
  1117.      ;
  1118.      ;      If the 7wire bit is not on, we will only use 3-wire protocol
  1119.      ;
  1120.      moveq      #0,d0                   ; clear flag
  1121.      btst.b   #SERB_7WIRE,IO_SERFLAGS(a1)          ; use 7wire handshaking?
  1122.      beq.b      36$                      ; nope, branch
  1123.      moveq      #1,d0                   ; set flag
  1124. 36$     move.b   d0,Handshake                  ; store flag
  1125.      ;
  1126.      ;      Set RC and return.
  1127.      ;
  1128. 39$     moveq      #0,d0                   ; I/O complete
  1129.      rts                          ; return
  1130.      ;
  1131.      ;      Invalid parm detected.
  1132.      ;
  1133. 40$     moveq      #SerErr_InvParam,d0              ; set error
  1134.      bra.b      35$                      ; go return
  1135.      ;
  1136.      ;      Reset the buffer and baud rate
  1137.      ;
  1138.      ;      Registers:  D0 = Buffer length
  1139.      ;              D1 = Baud rate
  1140.      ;
  1141. internalReset:
  1142.      ;
  1143.      ;      Disable interrupts.
  1144.      ;
  1145.      DISABLE                      ; disable interrupts
  1146.      ;
  1147.      ;      Save buffer length and go set serper.
  1148.      ;
  1149.      move.l   d0,-(sp)                  ; save D0
  1150.      move.l   d1,d0                   ; get baud rate
  1151.      bsr.b      setPeriod                  ; go set the serper register
  1152.      move.l   (sp)+,d0                  ; restore D0
  1153.      ;
  1154.      ;      Determine if the buffer length is adequate for the selected CPS.
  1155.      ;      If not, use 64K for the length.
  1156.      ;
  1157.      move.l   vb_CurBaud(a5),d1              ; get current baud
  1158.      lsr.l      #$3,d1                  ; divide by 8
  1159.      cmp.l      d1,d0                   ; buflen > CPS
  1160.      bhi.b      10$                      ; yep, branch
  1161.      move.l   #65536,d0                  ; else use 64K
  1162.      ;
  1163. 10$     bsr.b      allocBuf                  ; go allocate a new buffer
  1164.      ;
  1165.      ;      Enable and return to caller.
  1166.      ;
  1167.      ENABLE                       ; enable interrupts
  1168.      rts                          ; return (D0 has status)
  1169.      ;
  1170.      ;      Set serial period register
  1171.      ;
  1172. setPeriod:
  1173.      cmp.l      vb_CurBaud(a5),d0              ; current baud = new baud?
  1174.      beq.b      40$                      ; yep, just exit
  1175.      move.l   d0,vb_CurBaud(a5)              ; save new baud
  1176.      move.l   d0,d1                   ; save again
  1177.      lsl.l      #3,d0                   ; baud *= 8
  1178.      sub.l      d1,d0                   ; baud -= saved baud
  1179.      move.l   #25000000,d1                  ; get NTSC base
  1180.      cmpi.b   #50,PowerSupplyFrequency(a6)          ; PAL machine?
  1181.      bne.b      10$                      ; nope, branch
  1182.      move.l   #24772416,d1                  ; get PAL base
  1183. 10$     cmpi.l   #$FFFF,d0                  ; Divide
  1184.      ble.b      20$                      ;
  1185.      lsr.l      #5,d0                   ;
  1186.      divu.w   d0,d1                   ;
  1187.      andi.l   #$FFFF,d1                  ;
  1188.      lsr.l      #5,d1                   ;
  1189.      bra.b      30$                      ;
  1190. 20$     divu.w   d0,d1                   ;
  1191. 30$     move.w   d1,_serper                  ; set period value
  1192. 40$     rts
  1193.      ;
  1194.      ;      Allocate new internal buffer
  1195.      ;
  1196. allocBuf:
  1197.      cmp.l      vb_CurRBufLen(a5),d0              ; len same as previous?
  1198.      beq.b      10$                      ; yep, so no need to alloc
  1199.      move.l   d0,d1                   ; save length
  1200.      movem.l  d1/a1,-(sp)                  ; save registers
  1201.      moveq      #MEMF_PUBLIC,d1              ; public memory
  1202.      jsr      _LVOAllocMem(a6)              ; go allocate it
  1203.      movem.l  (sp)+,d1/a1                  ; restore registers
  1204.      tst.l      d0                      ; did we get it?
  1205.      beq.b      20$                      ; if zero, error
  1206.      bsr.b      freeBuf                  ; go free previous buffer
  1207.      move.l   d0,vb_CurRBuf(a5)              ; store new ptr
  1208.      move.l   d1,vb_CurRBufLen(a5)              ; and length
  1209.      bsr      cmd_Clear                  ; go setup buffer
  1210. 10$     moveq      #0,d0                   ; success
  1211. 15$     rts                          ; return
  1212. 20$     moveq      #SerErr_BufErr,d0              ; set error status
  1213.      bra.b      15$                      ; return
  1214.      ;
  1215.      ;      Free internal buffer
  1216.      ;
  1217. freeBuf:
  1218.      movem.l  d0-d1/a0-a1,-(sp)              ; save registers
  1219.      move.l   vb_CurRBuf(a5),d0              ; is one there?
  1220.      beq.b      10$                      ; no so branch
  1221.      movea.l  d0,a1                   ; get ptr
  1222.      move.l   vb_CurRBufLen(a5),d0              ; get length
  1223.      clr.l      vb_CurRBuf(a5)              ; clear
  1224.      clr.l      vb_CurRBufLen(a5)              ; clear
  1225.      jsr      _LVOFreeMem(a6)              ; free it
  1226. 10$     movem.l  (sp)+,d0-d1/a0-a1              ; restore registers
  1227.      rts                          ; return
  1228.      ;
  1229.      ;      Checks CTS status and if clear generates a TBE interrupt or
  1230.      ;      requeues the timer request.
  1231.      ;
  1232.      ;      Entered from Exec using the MsgPort callback.
  1233.      ;
  1234.      ;      Input:   a6 = ExecBase
  1235.      ;      Output:  none
  1236.      ;
  1237.      ;      No need to preserve d0/d1/a0/a1
  1238.      ;
  1239. timerRtn:
  1240.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  1241.      jsr      _LVORemove(a6)              ; remove request
  1242.      ;
  1243.      ;      If we were breaking, reset adkcon.
  1244.      ;
  1245.      lea      _custom,a0                  ; get ptr to custom regs
  1246.      btst.b   #ADKB_UARTBRK,_adkconr(a0)          ; were we breaking?
  1247.      beq.b      10$                      ; nope, skip reset
  1248.      ;
  1249.      move.w   #ADKF_UARTBRK,_adkcon(a0)          ; stop breaking
  1250.      ;
  1251.      ;
  1252.      ;
  1253. 10$     move.b   Handshake(pc),d0              ; are we handshaking?
  1254.      beq.b      20$                      ; nope, generate interrupt
  1255.      btst.b   #CIAB_COMCTS,_ciabpra           ; clear to send?
  1256.      beq.b      20$                      ; yep, go start writing
  1257.      ;
  1258.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  1259.      move.l   #1000,IOTV_TIME+TV_MICRO(a1)          ; wait for .001 seconds
  1260.      jsr      _LVOSendIO(a6)              ; go queue it
  1261.      bra.b      30$                      ; branch to return
  1262.      ;
  1263.      ;      CTS is clear so generate TBE interrupt to restart writing
  1264.      ;
  1265. 20$     move.w   #INTF_SETCLR|INTF_TBE,_intreq(a0)   ; set TBE interrupt
  1266. 30$     rts                          ; return
  1267.      ;
  1268.      ;      Non serial interrupt
  1269.      ;
  1270. level1n:
  1271.      movem.l  d0-d1/a0-a1/a5-a6,-(sp)          ; save registers
  1272.      lea      _custom,a0                  ; get ptr to custom regs
  1273.      move.w   intenar(a0),d1              ; get enabled interrupts
  1274.      and.w      intreqr(a0),d1              ; and in requested interrupts
  1275.      movea.l  SysBase(pc),a6              ; get ExecBase
  1276.      ;
  1277.      btst      #INTB_DSKBLK,d1              ; Disk block done?
  1278.      beq.b      10$                      ; nope, branch
  1279.      ;
  1280.      movem.l  IVDSKBLK(a6),a1/a5              ; get data and code ptrs
  1281.      pea.l      20$(pc)                  ; push return address
  1282.      jmp      (a5)                      ; jump to routine
  1283.      ;
  1284. 10$     btst      #INTB_SOFTINT,d1              ; software interrupt?
  1285.      beq.b      20$                      ; nope, branch
  1286.      ;
  1287.      movem.l  IVSOFTINT(a6),a1/a5              ; get data and code ptrs
  1288.      pea.l      20$(pc)                  ; push return address
  1289.      jmp      (a5)                      ; jump to routine
  1290.      ;
  1291. 20$     movem.l  (sp)+,d0-d1/a0-a1/a5-a6          ; restore registers
  1292.      rte                          ; return
  1293.      ;
  1294.      ;      Level 1 interrupt handler
  1295.      ;
  1296. level1:
  1297.      btst.b   #INTB_INTEN,_intenar              ; interrupts enabled?
  1298.      beq.b      35$                      ; nope, ignore
  1299.      btst.b   #INTB_SOFTINT,_intreqr+1          ; software interrupt?
  1300.      bne.b      level1n                  ; nope, branch
  1301.      btst.b   #INTB_TBE,_intreqr+1              ; xmit buffer empty?
  1302.      beq.b      level1n                  ; nope, invoke old handler
  1303.      ;
  1304.      ;      Handle "Transmit Buffer Empty" interrupt (write)
  1305.      ;
  1306.      move.w   #INTF_TBE,_intreq              ; clear interrupt
  1307.      move.l   d0,-(sp)                  ; save D0 (faster than MOVEM)
  1308.      move.l   a0,-(sp)                  ; save A0 (faster than MOVEM)
  1309.      ;
  1310.      ;      If we're not handshaking, bypass it.
  1311.      ;
  1312. 10$     move.b   Handshake(pc),d0              ; are we handshaking?
  1313.      beq.b      20$                      ; nope, skip CTS test
  1314.      btst.b   #CIAB_COMCTS,_ciabpra           ; clear to send?
  1315.      bne.b      40$                      ; nope, branch
  1316.      ;
  1317.      ;      If cw_Length goes negative here, we are either done with a
  1318.      ;      request or we were called as a result of a fake interrupt
  1319.      ;      to force us to get the next request going.
  1320.      ;
  1321. 20$     subq.l   #1,cw_Length                  ; decr write length
  1322.      blt.b      60$                      ; < zero, done, branch
  1323.      ;
  1324.      ;      Currently processing a request.
  1325.      ;
  1326.      movea.l  cw_Buffer(pc),a0              ; get buffer ptr
  1327.      move.w   #256,d0                  ; set stop bit
  1328.      move.b   (a0)+,d0                  ; get next byte
  1329.      move.l   a0,cw_Buffer                  ; store buffer ptr
  1330.      move.w   d0,_serdat                  ; store in serdat reg
  1331.      ;
  1332. 30$     movea.l  (sp)+,a0                  ; restore registers
  1333.      move.l   (sp)+,d0                  ; restore registers
  1334. 35$     rte                          ; return
  1335.      ;
  1336.      ;      Queue a timer request to recheck CTS status
  1337.      ;
  1338. 40$     movem.l  d1/a1/a6,-(sp)              ; save registers
  1339.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  1340.      move.l   #1000,IOTV_TIME+TV_MICRO(a1)          ; wait for .001 seconds
  1341.      movea.l  SysBase(pc),a6              ; get ExecBase
  1342.      jsr      _LVOSendIO(a6)              ; queue the request
  1343.      movem.l  (sp)+,d1/a1/a6              ; restore registers
  1344.      bra.b      30$                      ; go return
  1345.      ;
  1346.      ;      There aren't anymore requests, so clear and exit
  1347.      ;
  1348. 50$     clr.l      cw_Length-Start(a6)              ; clear length
  1349.      clr.l      cw_IOReq-Start(a6)              ; clear
  1350.      movem.l  (sp)+,d1/a1/a6              ; restore registers
  1351.      bra.b      30$                      ; go return
  1352.      ;
  1353.      ;      Write request completed
  1354.      ;
  1355. 60$     movem.l  d1/a1/a6,-(sp)              ; save registers
  1356.      ;
  1357.      move.l   cw_IOReq(pc),d0              ; active I/O request?
  1358.      beq.b      70$                      ; nope, branch
  1359.      ;
  1360.      ;      Reply it and setup for next
  1361.      ;
  1362.      movea.l  d0,a1                   ; get I/O request
  1363.      andi.b   #~(1<<IOSERB_ACTIVE),IO_FLAGS(a1)   ; no longer active
  1364.      clr.b      IO_ERROR(a1)                  ; no error
  1365.      movea.l  SysBase(pc),a6              ; get ExecBase
  1366.      DEBUGIO  replyIO
  1367.      jsr      _LVOReplyMsg(a6)              ; return I/O request
  1368.      ;
  1369. 70$     lea.l      Start(pc),a6                  ; get section base
  1370.      ;
  1371.      lea.l      writeQ(pc),a1               ; get ptr to write queue
  1372.      move.l   (a1),a0                  ; get head of list
  1373.      move.l   (a0),d0                  ; get successor
  1374.      beq.b      50$                      ; end of list? yep, branch
  1375.      ;
  1376.      ;      Remove the node from the list
  1377.      ;
  1378.      move.l   d0,(a1)                  ; make new head
  1379.      exg.l      d0,a0                   ; swap nodes
  1380.      move.l   a1,LN_PRED(a0)              ; store predecessor
  1381.      ;
  1382.      move.l   d0,a1                   ; get I/O request
  1383.      ;
  1384.      ;      If it's a BREAK, then branch to process as such.
  1385.      ;
  1386.      cmpi.w   #SDCMD_BREAK,IO_COMMAND(a1)          ; BREAK command?
  1387.      beq.b      100$                      ; yep, branch
  1388.      ;
  1389.      ;      Check for absolute length
  1390.      ;
  1391.      move.l   IO_DATA(a1),a0              ; get data ptr
  1392.      moveq      #-1,d1                  ; get value
  1393.      move.l   IO_LENGTH(a1),d0              ; get length
  1394.      cmp.l      d1,d0                   ; length = -1?
  1395.      bne.b      90$                      ; nope, skip scan
  1396.      ;
  1397.      ;      Scan the data for null to calc the length
  1398.      ;
  1399.      move.l   a0,d1                   ; save data ptr
  1400.     ; Buffer size is multiple of 64bytes so we can safely move a long
  1401. 80$     move.l   (a0),d0                  ; move a long into d0
  1402.      addq.l   #1,a0                   ; update pointer
  1403.      tst.b      d0                      ; does it equal 0? (first byte)
  1404.      beq.b      81$                      ; yep, finish
  1405.      addq.l   #1,a0                   ; update pointer
  1406.      lsl.l      #8,d0                   ; shift too second byte
  1407.      tst.b      d0                      ; does it equal 0? (second byte)
  1408.      beq.b      81$                      ; yep, finish
  1409.      addq.l   #1,a0                   ; update pointer
  1410.      lsl.l      #8,d0                   ; shift too third byte
  1411.      tst.b      d0                      ; does it equal 0? (third byte)
  1412.      beq.b      81$                      ; yep, finish
  1413.      addq.l   #1,a0                   ; update pointer
  1414.      lsl.l      #8,d0                   ; shift too fourth byte
  1415.      tst.b      d0                      ; does it equal 0? (fourth byte)
  1416.      beq.b      81$                      ; yep, finish
  1417.      bra.b      80$                      ; loop
  1418. 81$
  1419.      suba.l   d1,a0                   ; calc # of bytes
  1420.      move.l   a0,d0                   ; xfer
  1421.      movea.l  d1,a0                   ; get data ptr
  1422.      ;
  1423. 90$     move.l   d0,IO_ACTUAL(a1)              ; go ahead and set it
  1424.      move.b   IO_FLAGS(a1),d1
  1425.      andi.b   #~(1<<IOSERB_QUEUED),d1          ; no longer queued
  1426.      ori.b      #1<<IOSERB_ACTIVE,d1              ; make it active
  1427.      move.b   d1,IO_FLAGS(a1)
  1428.      move.l   d0,cw_Length-Start(a6)          ; store length
  1429.      move.l   a0,cw_Buffer-Start(a6)          ; store buffer ptr
  1430.      move.l   a1,cw_IOReq-Start(a6)           ; store I/O request ptr
  1431.      ;
  1432.      movem.l  (sp)+,d1/a1/a6              ; restore registers
  1433.      bra      10$                      ; go start request
  1434.      ;
  1435.      ;      Start the BREAK.
  1436.      ;
  1437. 100$     move.b   IO_FLAGS(a1),d1
  1438.      andi.b   #~(1<<IOSERB_QUEUED),d1          ; no longer queued
  1439.      ori.b      #1<<IOSERB_ACTIVE,d1              ; make it active
  1440.      move.b   d1,IO_FLAGS(a1)
  1441.      clr.l      cw_Length-Start(a6)              ; clear length
  1442.      move.l   a1,cw_IOReq-Start(a6)           ; store I/O request ptr
  1443.      move.w   #ADKF_SETCLR|ADKF_UARTBRK,_adkcon   ; start break
  1444.      move.l   IO_BRKTIME(a1),d0              ; get break time
  1445.      lea.l      timerReq(pc),a1              ; get ptr to timer request
  1446.      move.l   d0,IOTV_TIME+TV_MICRO(a1)          ; set the timeout
  1447.      movea.l  SysBase(pc),a6              ; get ExecBase
  1448.      jsr      _LVOSendIO(a6)              ; queue the request
  1449.      movem.l  (sp)+,d1/a1/a6              ; restore registers
  1450.      bra      30$                      ; go exit
  1451.      ;
  1452.      ;      Non serial interrupt
  1453.      ;
  1454. level5n:
  1455.      movem.l  d0-d1/a0-a1/a5-a6,-(sp)          ; save registers
  1456.      lea      _custom,a0                  ; get ptr to custom regs
  1457.      move.w   intenar(a0),d1              ; get enabled interrupts
  1458.      and.w      intreqr(a0),d1              ; and in requested interrupts
  1459.      movea.l  SysBase(pc),a6              ; get ExecBase
  1460.      btst      #INTB_DSKSYNC,d1              ; Disk synchronized?
  1461.      beq.b      10$                      ; nope, branch
  1462.      movem.l  IVDSKSYNC(A6),a1/a5              ; get data and code ptrs
  1463.      jsr      (a5)                      ; branch to routine
  1464. 10$     movem.l  (sp)+,d0-d1/a0-a1/a5-a6          ; restore registers
  1465.      rte                          ; return
  1466.      ;
  1467.      ;      Default Level 5 handler
  1468.      ;
  1469. level5:
  1470.      btst.b   #INTB_INTEN,_intenar              ; interrupts enabled?
  1471.      beq.b      45$                      ; nope, ignore
  1472.      btst.b   #INTB_RBF,_intreqr              ; receive buffer full?
  1473.      beq.b      level5n                  ; nope, invoke old handler
  1474.      ;
  1475.      move.l   a0,-(sp)                  ; save registers
  1476.      move.l   a1,-(sp)                  ; save registers
  1477.      lea      _custom,a1                  ; get ptr to custom regs
  1478.      ;
  1479. 10$     btst.b   #7,_serdatr(a1)              ; Overrun?
  1480.      bne.b      50$                      ; yep, branch
  1481.      ;
  1482. 20$     movea.l  i_BufIn(pc),a0              ; get current ptr
  1483.      move.b   _serdatr+1(a1),(a0)+              ; store received byte
  1484.      move.w   #INTF_RBF,_intreq(a1)           ; clear RBF interrupt
  1485.      addq.l   #1,i_InCnt                  ; incr bytes in buffer
  1486.      ;
  1487.      cmpa.l   i_BufEnd(pc),a0              ; hit end of buffer?
  1488.      beq.b      60$                      ; yep, branch
  1489. 30$     move.l   a0,i_BufIn                  ; store input ptr
  1490.      ;
  1491.      subq.l   #1,i_Thresh                  ; close to full buffer?
  1492.      beq.b      70$                      ; yep, branch
  1493.      ;
  1494. 40$     btst.b   #INTB_RBF,_intreqr(a1)          ; receive buffer full?
  1495.      bne.b      10$                      ; yep, go get another byte
  1496.      ;
  1497.      movea.l  (sp)+,a1                  ; restore registers
  1498.      movea.l  (sp)+,a0                  ; restore registers
  1499. 45$     rte                          ; return
  1500.      ;
  1501.      ;      We've missed some data, so set overrun flag.
  1502.      ;
  1503. 50$     addq.b   #1,Overrun                  ; set overrun flag
  1504.      bra.b      20$                      ; continue
  1505.      ;
  1506.      ;      Hit physical end of buffer, so wrap to the start of the buffer.
  1507.      ;
  1508. 60$     movea.l  i_BufPtr(pc),a0              ; get buffer ptr
  1509.      bra.b      30$                      ; continue
  1510.      ;
  1511.      ;      Hit buffer threshold, so tell other end not to send any more
  1512.      ;      data.
  1513.      ;
  1514. 70$     tst.b      Handshake                  ; are we handshaking?
  1515.      beq.b      40$                      ; nope, skip RTS
  1516.      ori.b      #1<<CIAB_COMRTS,_ciabpra          ; block further input
  1517.      bra.b      40$                      ; go return
  1518.      ;
  1519.      ;
  1520.      ;
  1521. level2:
  1522.      ;
  1523.      ;      If there's nothing in the buffer, there's no point in going
  1524.      ;      any further.
  1525.      ;
  1526.      move.l   i_InCnt(pc),d0              ; anything in the buffer?
  1527.      bne.b      20$                      ; yep, branch
  1528. 10$     moveq      #0,d0                   ; set Z flag
  1529.      rts                          ; return
  1530.      ;
  1531.      ;      If we've been "disabled" then get out.
  1532.      ;
  1533. 20$     move.b   disableRead(pc),d0              ; internally disabled?
  1534.      bge.b      10$                      ; yep, get out of here
  1535.      lea.l      Start(pc),a5                  ; get base
  1536.      ;
  1537.      ;      If we have an active request, branch down and try to fulfill it.
  1538.      ;
  1539.      move.l   cr_IOReq(pc),d0              ; get and test active I/O
  1540.      bne.b      30$                      ; nzero, active, branch
  1541.      ;
  1542.      ;      Get first node in list and test if empty.
  1543.      ;
  1544.      move.l   (a1),a0                  ; get head of list
  1545.      move.l   (a0),d0                  ; get successor
  1546.      beq.b      10$                      ; end of list? yep, branch
  1547.      ;
  1548.      ;      Remove the node from the list
  1549.      ;
  1550.      move.l   d0,(a1)                  ; make new head
  1551.      exg.l      d0,a0                   ; swap nodes
  1552.      move.l   a1,LN_PRED(a0)              ; store predecessor
  1553.      ;
  1554.      ;      Setup fields for processing a read request
  1555.      ;
  1556.      movea.l  d0,a1                   ; get I/O request
  1557.      move.b   IO_FLAGS(a1),d1
  1558.      andi.b   #~(1<<IOSERB_QUEUED),d1          ; no longer queued
  1559.      ori.b      #1<<IOSERB_ACTIVE,d1              ; make it active
  1560.      move.b   d1,IO_FLAGS(a1)
  1561.      move.l   a1,cr_IOReq-Start(a5)           ; store I/O request
  1562.      move.l   IO_DATA(a1),cr_OutPtr-Start(a5)     ; get/set output ptr
  1563.      move.l   IO_LENGTH(a1),cr_Length-Start(a5)   ; get/set output count
  1564.      ;
  1565.      ;      Process an active I/O request
  1566.      ;
  1567. 30$     movea.l  SysBase(pc),a6              ; get ExecBase
  1568.      move.l   d0,a1                   ; get I/O request
  1569.      bsr      copyData                  ; go copy 'em
  1570.      tst.l      d0                      ; done with request?
  1571.      beq.b      10$                      ; nope, branch
  1572.      ;
  1573.      ;      the request has been satisfied, so return it.
  1574.      ;
  1575.      clr.l      cr_IOReq-Start(a5)              ; clear request
  1576.      andi.b   #~(1<<IOSERB_ACTIVE),IO_FLAGS(a1)   ; no longer active
  1577.      DEBUGIO  replyIO
  1578.      jsr      _LVOReplyMsg(a6)              ; return I/O
  1579.      bra.b      10$
  1580.      ;
  1581.      ;      Registers:
  1582.      ;      Entry:   A1        Ptr to I/O Request
  1583.      ;           A6        ExecBase
  1584.      ;      Exit:    D0        ZERO - request not done, do not reply it
  1585.      ;                NZERO - request done, reply it
  1586.      ;
  1587. copyData:
  1588.      ;
  1589.      ;      Process an active I/O request (or fall through from above)
  1590.      ;
  1591.      movem.l  d2-d5/a1-a5,-(sp)              ; save registers
  1592.      lea.l      Start(pc),a5                  ; get base
  1593.      movea.l  a1,a4                   ; get I/O request
  1594.      ;
  1595.      movea.l  i_BufOut(pc),a2              ; get current bufout ptr
  1596.      movea.l  cr_OutPtr(pc),a3              ; get current output ptr
  1597.      move.l   cr_Length(pc),d2              ; get current bytes needed
  1598.      move.l   i_InCnt(pc),d3              ; get current bytes in buffer
  1599.      ;
  1600.      ;      If we don't have enough bytes to satisfy the request,
  1601.      ;      set the length to the number of bytes we do have.
  1602.      ;
  1603.      cmp.l      d2,d3                   ; enuf to satisfy request?
  1604.      bge.b      15$                      ; yep, so branch
  1605.      move.l   d3,d2                   ; # to copy = # in buffer
  1606.      bra.b      15$                      ; branch to loop entry
  1607.      ;
  1608.      ;      Start of copy loop.
  1609.      ;
  1610. 10$     movea.l  i_BufPtr(pc),a2              ; reset bufout to start
  1611.      ;
  1612.      ;      Entry point of copy loop.
  1613.      ;
  1614. 15$     move.l   d2,d3                   ; xfer # of bytes to copy
  1615.      ;
  1616.      ;      If the copy will extend past the end of the buffer, we can
  1617.      ;      only copy the number of bytes to the end this go around.
  1618.      ;
  1619.      move.l   i_BufEnd(pc),d0              ; get ptr to end of buf
  1620.      sub.l      a2,d0                   ; calc # of bytes to end
  1621.      cmp.l      d0,d3                   ; # to copy < # to end?
  1622.      blt.b      20$                      ; yep, branch
  1623.      move.l   d0,d3                   ; get bytes to end
  1624.      ;
  1625.      ;      Registers:
  1626.      ;
  1627.      ;      A2 = pointer from which data will be copied
  1628.      ;      A3 = pointer to which data will be copied
  1629.      ;      D2 = number of bytes that need to be copied
  1630.      ;      D3 = number of bytes to copy this iteration
  1631.      ;
  1632.     IFNE EOFCODE
  1633. 20$     btst.b   #SERB_EOFMODE,IO_SERFLAGS(a4)       ; EOFMODE requested?
  1634.      beq.b      30$                      ; nope, just go copy
  1635.      ;
  1636.      ;      EOFMODE was specified so copy characters 1 at a time until
  1637.      ;      we hit an EOF character, the output butter has filled, or
  1638.      ;      the input buffer has drained.
  1639.      ;
  1640.      move.l   d3,d0                   ; get length
  1641.      ;
  1642.      lea.l      IO_TERMARRAY(a4),a1              ; get termarry ptr
  1643. 21$     move.b   (a2)+,d1                  ; get byte
  1644.      ; This way the term char IS copied (cause of crash?)
  1645.      move.b   d1,(a3)+                  ; put in output buffer
  1646.      ;
  1647.      cmp.b      (a1),d1                  ; found term char?
  1648.      bge.b      22$                      ; possibly, branch
  1649.      cmp.b      1(a1),d1                  ; found term char?
  1650.      bge.b      22$                      ; possibly, branch
  1651.      cmp.b      2(a1),d1                  ; found term char?
  1652.      bge.b      22$                      ; possibly, branch
  1653.      cmp.b      3(a1),d1                  ; found term char?
  1654.      bge.b      22$                      ; possibly, branch
  1655.      cmp.b      4(a1),d1                  ; found term char?
  1656.      bge.b      22$                      ; possibly, branch
  1657.      cmp.b      5(a1),d1                  ; found term char?
  1658.      bge.b      22$                      ; possibly, branch
  1659.      cmp.b      6(a1),d1                  ; found term char?
  1660.      bge.b      22$                      ; possibly, branch
  1661.      cmp.b      7(a1),d1                  ; found term char?
  1662.      bgt.b      23$                      ; nope, branch
  1663. 22$     beq.b      24$                      ; term char found?
  1664.      ;
  1665.      ;      Didn't find a term character, so continue with the copy loop
  1666.      ;
  1667. 23$
  1668.      subq.l   #1,d0                   ; decr length counter
  1669.      bne.b      21$                      ; continue if more
  1670.      bra.b      40$                      ; done with copy, branch
  1671.      ;
  1672.      ;      We've found a termination character.
  1673.      ;
  1674. 24$     clr.l      cr_Length-Start(a5)              ; done with request
  1675.      bra.b      50$                      ; branch
  1676.     ELSE
  1677. 20$
  1678.     ENDC
  1679.      ;
  1680.      ;      EOFMODE not specified, so just do a bulk copy.
  1681.      ;
  1682.      ;      XXX POSSIBLE SPEEDUP XXX
  1683.      ;
  1684.      ;      For short copies it would be quicker to have a simple inline
  1685.      ;      loop, but what's short???  It would be different by CPU.
  1686.      ;
  1687. 30$     move.l   d3,d0                   ; get length
  1688.      movea.l  a3,a1                   ; where to put it
  1689.      movea.l  a2,a0                   ; where to get it
  1690.      jsr      _LVOCopyMem(a6)              ; copy it
  1691.      adda.l   d3,a2                   ; update bufout
  1692.      adda.l   d3,a3                   ; update outptr
  1693.      ;
  1694.      ;      Fall through and entered from EOFMODE loop
  1695.      ;
  1696.      ;      If the following calculation results in a value greater than
  1697.      ;      zero, then we have a buffer wrap and need to process the
  1698.      ;      remaining bytes at the beginning of the buffer.
  1699.      ;
  1700. 40$     sub.l      d3,d2                   ; calc bytes left to copy
  1701.      bgt      10$                      ; >0, more to copy, branch
  1702.      ;
  1703.      ;
  1704.      ;
  1705. 50$     move.l   a3,d1                   ; get outptr
  1706.      sub.l      cr_OutPtr(pc),d1              ; calc length
  1707.      move.l   a3,cr_OutPtr-Start(a5)          ; update outptr
  1708.      ;
  1709.      ;      Update output ptr and I/O request
  1710.      ;
  1711.      move.l   a2,i_BufOut-Start(a5)           ; store bufout ptr
  1712.      add.l      d1,IO_ACTUAL(a4)              ; update I/O request
  1713.      ;
  1714.      ;      Update number of bytes left in the buffer.
  1715.      ;
  1716.      sub.l      d1,i_InCnt-Start(a5)              ; calc bytes left in buffer
  1717.      ;
  1718.      ;      If the threshold becomes positive here, then, if requested,
  1719.      ;      tell the other end that it's okay to start sending more data.
  1720.      ;
  1721.      add.l      d1,i_Thresh-Start(a5)           ; calc thresh and test
  1722.      ble.b      60$                      ; <= 0, need more data, skip
  1723.      tst.b      Handshake-Start(a5)              ; are we handshaking?
  1724.      beq.b      60$                      ; nope, skip RTS
  1725.      andi.b   #~(1<<CIAB_COMRTS),_ciabpra            ; ready to receive more data
  1726.      ;
  1727.      ;      Set error if we've had any overruns.
  1728.      ;
  1729. 60$     tst.b      Overrun-Start(a5)              ; did overrun occur?
  1730.      beq.b      70$                      ; nope, branch
  1731.      clr.b      Overrun-Start(a5)              ; reset overrun flag
  1732.      move.b   #SerErr_LineErr,IO_ERROR(a4)          ; set error code
  1733.      ;
  1734.      ;      Calc number of bytes left to copy.  If the result is greater
  1735.      ;      than zero, then we have more to copy so return an incomplete
  1736.      ;      status.
  1737.      ;
  1738. 70$     moveq      #0,d0                   ; assume I/O incomplete
  1739.      sub.l      d1,cr_Length-Start(a5)          ; update length and test
  1740.      bgt.b      90$                      ; >0, more to do, branch
  1741.      ;
  1742.      ;      We've completed the I/O request either by copying the requested
  1743.      ;      of bytes or by finding an EOFMODE character, so return a "reply"
  1744.      ;      status.
  1745.      ;
  1746.      moveq      #1,d0                   ; indicate reply
  1747.      ;
  1748.      ;      Restore and exit
  1749.      ;
  1750. 90$     movem.l  (sp)+,d2-d5/a1-a5              ; restore registers
  1751.      rts                          ; return (status in D0)
  1752.      ;
  1753.      ;      Align data
  1754.      ;
  1755.      CNOP      0,4
  1756.      ;
  1757.      ;
  1758.      ;
  1759. Init:
  1760.      DC.L      sizeof_Base8n1
  1761.      DC.L      funcTab
  1762.      DC.L      dataTab
  1763.      DC.L      InitRoutine
  1764.      ;
  1765.      ;
  1766.      ;
  1767. funcTab:
  1768.      DC.W      -1
  1769.      DC.W      dev_Open-funcTab
  1770.      DC.W      dev_Close-funcTab
  1771.      DC.W      dev_Expunge-funcTab
  1772.      DC.W      dev_Null-funcTab
  1773.      DC.W      dev_BeginIO-funcTab
  1774.      DC.W      dev_AbortIO-funcTab
  1775.      DC.W      -1
  1776.      ;
  1777.      ;
  1778.      ;
  1779. dataTab:
  1780.      INITBYTE LN_TYPE,NT_DEVICE
  1781.      INITLONG LN_NAME,Name
  1782.      INITBYTE LIB_FLAGS,LIBF_SUMUSED|LIBF_CHANGED
  1783.      INITWORD LIB_VERSION,VERSION
  1784.      INITWORD LIB_REVISION,REVISION
  1785.      INITLONG LIB_IDSTRING,IdString
  1786.      DC.W      0
  1787.      ;
  1788.      ;      String Constants
  1789.      ;
  1790. miscresource:
  1791.      DC.B      "misc.resource",0
  1792. timerdevice:
  1793.      DC.B      "timer.device",0
  1794. intuitlib:
  1795.      DC.B      "intuition.library",0
  1796. Name:
  1797.      DC.B      "8n1.device",0
  1798. IdString:
  1799.      VSTRING
  1800.      ;
  1801.      ;      End of checksummed area.  (Realigns data too!)
  1802.      ;
  1803. ENDTag:
  1804.      CNOP      0,4
  1805.      ;
  1806.      ;      Global SysBase (Use instead of AbsExecBase for speed)
  1807.      ;
  1808. SysBase:
  1809.      DC.L      0
  1810.      ;
  1811.      ;      Internal buffer tracking (DO NOT CHANGE THE ORDER!!!!)
  1812.      ;
  1813. i_BufPtr:
  1814.      DC.L      0
  1815. i_BufIn:
  1816.      DC.L      0
  1817. i_BufOut:
  1818.      DC.L      0
  1819. i_BufEnd:
  1820.      DC.L      0
  1821. i_InCnt:
  1822.      DC.L      0
  1823. i_Thresh:
  1824.      DC.L      0
  1825.      ;
  1826.      ;      Used while processing a read request.
  1827.      ;
  1828. cr_IOReq:
  1829.      DC.L      0
  1830. cr_OutPtr:
  1831.      DC.L      0
  1832. cr_Length:
  1833.      DC.L      0
  1834.      ;
  1835.      ;      List head for read requests
  1836.      ;
  1837. readQ:
  1838.      DC.L      readQ+MLH_TAIL
  1839.      DC.L      0
  1840.      DC.L      readQ
  1841.      ;
  1842.      ;      Write control.
  1843.      ;
  1844. cw_Length:
  1845.      DC.L      0
  1846. cw_Buffer:
  1847.      DC.L      0
  1848. cw_IOReq:
  1849.      DC.L      0
  1850.      ;
  1851.      ;      List head for write requests
  1852.      ;
  1853. writeQ:
  1854.      DC.L      writeQ+MLH_TAIL
  1855.      DC.L      0
  1856.      DC.L      writeQ
  1857.      ;
  1858.      ;
  1859.      ;
  1860. timerPort:
  1861.      DC.L      0                      ; LN_SUCC
  1862.      DC.L      0                      ; LN_PRED
  1863.      DC.B      NT_MSGPORT                  ; LN_TYPE
  1864.      DC.B      0                      ; LN_PRI
  1865.      DC.L      0                      ; LN_NAME
  1866.      DC.B      3                      ; MP_FLAGS (undoc'ed)
  1867.      DC.B      0                      ; MP_SIGBIT
  1868.      DC.L      timerRtn                  ; MP_SIGTASK
  1869.      DC.L      timerPort+MP_MSGLIST+LH_TAIL          ; LH_HEAD
  1870.      DC.L      0                      ; LH_TAIL
  1871.      DC.L      timerPort+MP_MSGLIST              ; LH_TAILPRED
  1872.      DC.B      0                      ; LH_TYPE
  1873.      DC.B      0                      ; LH_pad
  1874.      DC.W      0                      ; long align
  1875.      ;
  1876.      ;
  1877.      ;
  1878. timerReq:
  1879.      DC.L      0                      ; LN_SUCC
  1880.      DC.L      0                      ; LN_PRED
  1881.      DC.B      NT_MESSAGE                  ; LN_TYPE
  1882.      DC.B      0                      ; LN_PRI
  1883.      DC.L      0                      ; LN_NAME
  1884.      DC.L      timerPort                  ; MN_REPLYPORT
  1885.      DC.W      IOTV_SIZE                  ; MN_LENGTH
  1886.      DC.L      0                      ; IO_DEVICE
  1887.      DC.L      0                      ; IO_UNIT
  1888.      DC.W      TR_ADDREQUEST               ; IO_COMMAND
  1889.      DC.B      0                      ; IO_FLAGS
  1890.      DC.B      0                      ; IO_ERROR
  1891.      DC.L      0                      ; TV_SECS
  1892.      DC.L      0                      ; TV_MICROS
  1893.      ;
  1894.      ;
  1895.      ;
  1896. VBInterrupt:
  1897.      DC.L      0                      ; LN_SUCC
  1898.      DC.L      0                      ; LN_PRED
  1899.      DC.B      NT_INTERRUPT                  ; LN_TYPE
  1900.      DC.B      0                      ; LN_PRI
  1901.      DC.L      Name                      ; LN_NAME
  1902.      DC.L      readQ                   ; IS_DATA
  1903.      DC.L      level2                  ; IS_CODE
  1904.      ;
  1905.      ;      Global flags
  1906.      ;
  1907. Overrun:
  1908.      DC.B      0
  1909. Handshake:
  1910.      DC.B      1
  1911. disableRead:
  1912.      DC.B      -1
  1913.      ;
  1914.      ;
  1915.      ;
  1916.      END
  1917.  
  1918.