home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ddkx86v5.zip / DDKX86 / SRC / DEV / ATCOM / ATQUEUE.ASM < prev    next >
Assembly Source File  |  1995-04-14  |  18KB  |  510 lines

  1. ;*DDK*************************************************************************/
  2. ;
  3. ; COPYRIGHT (C) Microsoft Corporation, 1989
  4. ; COPYRIGHT    Copyright (C) 1995 IBM Corporation
  5. ;
  6. ;    The following IBM OS/2 WARP source code is provided to you solely for
  7. ;    the purpose of assisting you in your development of OS/2 WARP device
  8. ;    drivers. You may use this code in accordance with the IBM License
  9. ;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
  10. ;    Copyright statement may not be removed.;
  11. ;*****************************************************************************/
  12. ;       SCCSID = @(#)atqueue.asm        6.3 91/04/22
  13. ; ***************************************************************************
  14. ; *
  15. ; *
  16. ; *
  17. ; ***************************************************************************
  18.  
  19.         PAGE    ,132
  20.         .286p
  21.  
  22.         TITLE   com01.sys - Asynchronous Communication Device Driver
  23.         NAME com01
  24.  
  25. ;       Bryan Diehl
  26. ;       David Gilman
  27.  
  28. ;***    atqueue.asm
  29. ;
  30. ;       The device driver's internal buffers are maintained as circular
  31. ;       queues. This file contains the routines necessary to access and
  32. ;       maintain these queues. There are routines to transfer data to
  33. ;       and from user space, as well as routines used by the interrupt
  34. ;       handlers. These routines have been specialized to convert physical
  35. ;       to virtual addresses and to recognize when flow control states
  36. ;       need to be changed.
  37. ;
  38. ;       The routines that exist in this file are:
  39. ;
  40. ;               + ReadQueueByte - read a single byte from the output queue
  41. ;               + WriteQueueByte - write a single byte to the input queue
  42. ;               + ReadQueue - read a specified number of bytes into user space
  43. ;               + WriteQueue - write a specified number of bytes from user space
  44. ;               + CopyQueue - support routine for ReadQueue and WriteQueue
  45. ;
  46. ;       Modification History
  47. ;
  48. ;       DJG     01//16/87       Re-written to use the circular buffer
  49. ;                               code lifted from dos\pipe.asm
  50. ;
  51. ;       YN      05/25/89        MVDM Support - @VDM
  52. ;
  53. ;       ACW     04/16/91        @PVW Added perfview counters/timers
  54. ;
  55. ;       WDM     04/21/94        82548 - pvwxport.inc now included in atcom.inc
  56. ;
  57.  
  58.  
  59.  
  60.  
  61. .xlist
  62. ;  82548   include pvwxport.inc            ;@PVW
  63. include devhlp.inc
  64. include devsym.inc
  65. include basemaca.inc
  66. include realmac.inc
  67.  
  68. .list
  69.  
  70. include atcom.inc
  71.  
  72.         extrn   DisableRemoteTX:near
  73.         extrn   EnableRemoteTX:near
  74.         EXTRN   DevHlp:DWORD            ; DevHlp entry point
  75.  
  76. CSEG    SEGMENT
  77.         ASSUME  cs:CSEG
  78.  
  79. ;**     ReadQueueByte - read a single byte from the qout IO_Queue
  80. ;
  81. ;       ReadQueueByte removes one character from the output queue
  82. ;       and returns it to the caller in (al).
  83. ;
  84. ;       ENTRY   (ds:si) -> ComInfo
  85. ;
  86. ;       EXIT    if 'C' clear
  87. ;                       (al) = byte
  88. ;                       ioq_count is decremented by one
  89. ;               else
  90. ;                       queue is empty
  91. ;
  92. ;       USES    bx
  93.  
  94. Procedure ReadQueueByte,HYBRID
  95.         ASSUME  cs:CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  96.  
  97.         ChkComInfoPtr
  98.  
  99.         mov     bx,[si].ci_qout.ioq_out
  100.         cmp     bx,[si].ci_qout.ioq_in
  101.         stc                                     ; assume the queue is empty
  102.         je      rqbx                            ; queue is empty (out == in)
  103.  
  104.         mov     al,[bx]                         ; (al) = byte
  105.         dec     [si].ci_qout.ioq_count          ; adjust count
  106.         jnz     rqb10                           ; didn't take last char
  107.  
  108.         or      [si].ci_event,EV_TX_EMPTY       ; show that txq emptied
  109.  
  110. rqb10:  inc     bx                              ; adjust out pointer
  111.         cmp     [si].ci_qout.ioq_end,bx         ; clears carry (end >= bx)
  112.         jne     rqb20                           ; did not hit end of queue
  113.  
  114. ; Hit the end of the queue, wrap out pointer (out == base).
  115.  
  116.         mov     bx,[si].ci_qout.ioq_base        ; (bx) = base of queue
  117. rqb20:  mov     [si].ci_qout.ioq_out,bx         ; reset the output pointer
  118.  
  119. rqbx:   ret
  120.  
  121. EndProc ReadQueueByte
  122.  
  123.  
  124. ;**     WriteQueueByte - write a single byte to the qin IO_Queue
  125. ;
  126. ;       WriteQueueByte takes a single character in (al) and puts
  127. ;       it into the input queue.
  128. ;
  129. ;       If a Last Close is in progress, nothing is done.
  130. ;
  131. ;       The read timeout countdown is reset.
  132. ;       The byte is put into the queue. However if the queue
  133. ;       is actually full the pointers are not adjusted. This can be
  134. ;       done since a 'full' queue has one empty slot (used to differentiate
  135. ;       between full and empty).
  136. ;
  137. ;       ENTRY   (ds:si) -> ComInfo
  138. ;               (al) = byte
  139. ;
  140. ;       EXIT    if Last Close in progress
  141. ;                   return
  142. ;               reset read timeout countdown
  143. ;               if queue is not full
  144. ;                   byte enqued
  145. ;                   ioq_count is incremented by one
  146. ;                   if queue is above highwater mark
  147. ;                       DisableRemoteTX
  148. ;               else queue is full
  149. ;                   if ErrChar Replacement enabled
  150. ;                       last character in queue is replaced with
  151. ;                       the error replacement character
  152. ;
  153. ;       USES    ax bx dx
  154.  
  155. Procedure WriteQueueByte,HYBRID
  156.         ASSUME  cs:CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  157.  
  158.         ChkComInfoPtr
  159.  
  160.         test    [si].ci_flagx,FX_LAST_CLOSE
  161.         jnz     wqbx            ; last close in progress, drop character
  162.  
  163.         ; reset timeout anytime a character is put into the receive queue
  164.         mov     bx,[si].ci_r_to_start   ; get start value for timeout
  165.         mov     [si].ci_r_to,bx         ; reset timeout countdown
  166.  
  167.         mov     bx,[si].ci_qin.ioq_in
  168.         mov     [bx],al                         ; put byte in queue
  169.         inc     bx                              ; adjust in pointer
  170.         cmp     bx,[si].ci_qin.ioq_end
  171.         jne     wqb1                            ; did not wrap
  172.  
  173.         mov     bx,[si].ci_qin.ioq_base  ; wrapped
  174.  
  175. wqb1:   cmp     bx,[si].ci_qin.ioq_out
  176.         je      wqb2                            ; (in + 1) == out
  177.                                                 ; queue was already full
  178.  
  179.         mov     [si].ci_qin.ioq_in,bx           ; update in pointer
  180.         inc     [si].ci_qin.ioq_count           ; adjust count
  181.  
  182.         or      [si].ci_event,EV_RX_CHAR        ; flag rx character
  183.  
  184.  
  185. ; If standard port, we must handle flow control: if the receive queue is
  186. ; above the high water mark, we must disable the remote transmitter.
  187.  
  188.         cmp     [si].ci_qin.ioq_count,RX_HIGH_HS
  189.         jbe     wqbx                    ; queue is below high water mark for HS
  190.  
  191.         call    DisableRemoteTX         ; may send XOFF and/or drop HW HS lines
  192.  
  193. wqbx:   ret
  194.  
  195. ; If the queue is full then we may have to show the user that there
  196. ; was a queue overrun. That is, we may have to perform error character
  197. ; replacement.
  198.  
  199. wqb2:   or      [si].ci_comerr,CE_SW_OVERRUN    ; flag rx queue overrun
  200. ifdef PERFVIEW
  201.         pvw_SW_Overrun                          ;@PVW increment perfview cntr
  202. endif
  203.         or      [si].ci_event,EV_ERR            ; flag rx queue overrun
  204.  
  205.         test    [si].ci_dcb_flags2,F2_ERR_CHAR
  206.         jz      wqbx                            ; error replacement not on
  207.  
  208.         mov     bx,[si].ci_qin.ioq_in           ; (bx) = in pointer
  209.         cmp     bx,[si].ci_qin.ioq_base
  210.         jne     wqb3                            ; we didn't wrap when placing
  211.                                                 ; the byte in the queue
  212.  
  213.         mov     bx,[si].ci_qin.ioq_end          ; 'unwrap' back to end
  214.  
  215. wqb3:   dec     bx                              ; (bx) -> last byte in queue
  216.         mov     al,[si].ci_dcb_ErrChar
  217.         mov     [bx],al                         ; replace it with the error
  218.                                                 ; character
  219.  
  220.         jmp     SHORT wqbx
  221.  
  222. EndProc WriteQueueByte
  223.  
  224.  
  225. ;**     ReadQueue - read from the qin IO_Queue and write to user memory
  226. ;
  227. ;       ReadQueue will transfer no more than (cx) bytes from the input
  228. ;       queue to user memory. It performs the necessary address conversion
  229. ;       as well as recognition of when flow control needs to be changed.
  230. ;
  231. ;       ENTRY   (ds:si) -> ComInfo
  232. ;               (es:di) -> Read Request packet
  233. ;               (cx) = byte count
  234. ;
  235. ;       EXIT    (bx) = number actually moved
  236. ;               (cx) = residual byte count
  237. ;
  238. ;       NOTE    On exit (bx) + (cx) = (cx) on input.
  239. ;
  240. ;       USES    ax bx dx
  241.  
  242. Procedure ReadQueue,HYBRID
  243.         ASSUME  cs:CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  244.  
  245.         ChkComInfoPtr
  246.         ChkRPPtr
  247.  
  248. ; Get destination of transfer.
  249.  
  250.         SaveReg         <es,di>
  251. ;       mov     ax,es:[di].IoPData._hi
  252. ;       mov     bx,es:[di].IoPData._lo          ; (ax:bx)= physical xfer address
  253. ;       mov     dx,(0100h OR DevHlp_PhysToVirt)
  254. ;       DevHelp
  255. ;       jnc     rdq00
  256. ;
  257. ;       ComErr  <ReadQueue : PhysToVirt invalid address>
  258.         les     di,es:[di].IoPData              ; (es:di)-> virtual xfer address
  259.  
  260. rdq00:  SaveReg         <cx>
  261.  
  262.         mov     bx,cx                   ; (bx) = byte count
  263.  
  264. rdq0:   mov     cx,[si].ci_qin.ioq_in
  265.         sub     cx,[si].ci_qin.ioq_out
  266.         jz      rdq5                    ; buffer empty, go return
  267.         jnc     rdq2                    ; can transfer up to in ptr
  268.         mov     cx,[si].ci_qin.ioq_end
  269.         sub     cx,[si].ci_qin.ioq_out  ; can only xfer to end of buffer
  270.  
  271. rdq2:   cmp     cx,bx
  272.         jbe     rdq3                    ; xfer len smaller than byte count
  273.         mov     cx,bx                   ; don't xfer more than byte count
  274.  
  275. rdq3:   push    si                      ; (tos) = ComInfo
  276.         mov     si,[si].ci_qin.ioq_out  ; (si) = offset part of buffer ptr
  277.                                         ; (ds:si) -> source of data
  278.                                         ; (es:di) -> dest for copy
  279.                                         ; (cx) = byte count for this copy
  280.         sub     bx,cx                   ; (bx) = bytes remaining after copy
  281.         call    CopyQueue               ; (ds:si) is adjusted
  282.                                         ; (es:di) is adjusted
  283.                                         ; (cx) = zero
  284.         mov     cx,si                   ; (cx) = offset of new out ptr
  285.         pop     si                      ; (ds:si) -> ComInfo
  286.         ChkComInfoPtr
  287.  
  288.         cmp     cx,[si].ci_qin.ioq_end
  289.         jb      rdq4                    ; didn't hit end of buffer
  290.         mov     cx,[si].ci_qin.ioq_base ; hit end, pointer wraps around
  291.  
  292. rdq4:   mov     [si].ci_qin.ioq_out,cx  ; save the new pointer
  293.         or      bx,bx
  294.         jnz     rdq0                    ; more bytes to xfer
  295.  
  296.         ; Release virtual address
  297. rdq5:
  298. ;       mov     dl,DevHlp_UnPhysToVirt
  299. ;       DevHelp
  300.  
  301.         RestoreReg      <cx>            ; (cx) = requested transfer
  302.  
  303.         RestoreReg      <di,es>         ; (es:di) -> request packet
  304.         ASSUME  es:NOTHING
  305.         ChkRPPtr
  306.  
  307.         sub     cx,bx                   ; (cx) = actual transfer
  308.         add     es:[di].IOpData._lo,cx  ; adjust physical address pointer
  309. ;       adc     es:[di].IOpData._hi,0
  310.         sub     [si].ci_qin.ioq_count,cx; adjust ioq_count
  311.  
  312.         xchg    cx,bx                   ; (cx) = residual byte count
  313.                                         ; (bx) = actual transfer
  314.         mov     [si].ci_r_to_move,cx    ; update number left to move
  315.  
  316.  
  317.         ; If port is STANDARD, may have to flow on remote transmitter.
  318. rdq90:  cmp     [si].ci_qin.ioq_count,RX_LOW_HS
  319.         jae     rdqx                    ; not below low water mark for HS
  320.  
  321.         SaveReg         <cx>
  322.         call    EnableRemoteTX          ; below low water, enable remote TXer
  323.         RestoreReg      <cx>            ; (cx) = residual byte count
  324.  
  325. rdqx:   ret
  326.  
  327. EndProc ReadQueue
  328.  
  329.  
  330. ;**     WriteQueue - read from user memory and write to the qout IO_Queue
  331. ;
  332. ;       WriteQueue will transfer no more than (cx) bytes from user memory
  333. ;       into the output queue. It performs the necessary address conversion.
  334. ;
  335. ;       ENTRY   (ds:si) -> ComInfo
  336. ;               (es:di) -> Write Request packet
  337. ;               (cx) = byte count
  338. ;
  339. ;       EXIT    (bx) = number actually moved
  340. ;               (cx) = residual byte count
  341. ;
  342. ;       NOTE    On exit (bx) + (cx) = (cx) on input.
  343. ;
  344. ;       USES    ax dx si
  345.  
  346. Procedure WriteQueue,HYBRID
  347.         ASSUME  cs:CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  348.  
  349.         ChkComInfoPtr
  350.         ChkRPPtr
  351.  
  352.         SaveReg         <si>
  353.         SaveReg         <es,di>
  354.  
  355. ; Get physical address of xfer source
  356.  
  357. ;       mov     ax,es:[di].IoPData._hi
  358. ;       mov     bx,es:[di].IoPData._lo  ; (ax:bx) = physical addr of user data
  359. ;
  360. ;       push    ds
  361. ;       pop     es
  362. ;       ASSUME  es:DSEG
  363. ;       xchg    si,di
  364. ;
  365. ;       mov     dx,(0000 OR DevHlp_PhysToVirt)
  366. ;       DevHelp
  367. ;       jnc     wrq00
  368. ;
  369. ;       ComErr  <WriteQueue : PhysToVirt invalid address>
  370.  
  371.         push    si
  372.         push    ds
  373.         lds     si,es:[di].IoPData ; (ds:si) -> virtual xfer source
  374.         pop     es
  375.         pop     di                 ; (es:di) -> ComInfo
  376.         ASSUME  es:DSEG
  377.  
  378. wrq00:  SaveReg         <cx>
  379.         mov     bx,cx                           ; (bx) = byte count
  380.  
  381. ;       calculate length of transfer
  382. ;       there are two cases:
  383. ;       1. in ptr is < out ptr
  384. ;               in this case, we can only put (out - in) - 1 bytes in
  385. ;       2. in ptr >= out ptr
  386. ;               In this case, we can only xfer to end of buffer.
  387. ;               If in == out == base, we must leave last byte
  388. ;               empty.
  389.  
  390. wrq0:   mov     cx,es:[di].ci_qout.ioq_in
  391.         mov     dx,es:[di].ci_qout.ioq_out
  392.         sub     cx,dx                   ; (cx) = -(out - in)
  393.         jb      wrq1                    ; in < out, can only go to (out - 1)
  394.         add     cx,dx                   ; (cx) = ioq_in
  395.         sub     cx,es:[di].ci_qout.ioq_end
  396.         cmp     dx,es:[di].ci_qout.ioq_base
  397.         jne     wrq2
  398.  
  399. wrq1:   inc     cx                      ; 'subtract' from negated count
  400.  
  401. wrq2:   neg     cx                      ; (cx) = transfer count
  402.  
  403.         jcxz    wrq5                    ; no room, return
  404.         cmp     cx,bx
  405.         jbe     wrq3                    ; xfer len smaller than request
  406.         mov     cx,bx                   ; don't xfer more than requested
  407.  
  408. ;       (es:di) -> ComInfo
  409. ;       (cx) = byte count for this xfer
  410. ;       (ds:si) -> source
  411.  
  412. wrq3:   push    di
  413.  
  414.         mov     di,es:[di].ci_qout.ioq_in       ; (es:di) -> dest
  415.                                                 ; (ds:si) -> source
  416.                                                 ; (cx) = byte count for copy
  417.         sub     bx,cx                           ; (bx) = bytes remaining
  418.                                                 ; after copy
  419.         call    CopyQueue                       ; (ds:si) is adjusted
  420.                                                 ; (es:di) is adjusted
  421.                                                 ; (cx) = zero
  422.         mov     cx,di                           ; (cx) = offset part of
  423.                                                 ; new out ptr
  424.         pop     di                              ; (es:di) -> ComInfo
  425.         cmp     cx,es:[di].ci_qout.ioq_end
  426.         jb      wrq4                            ; didn't hit end of buffer
  427.         mov     cx,es:[di].ci_qout.ioq_base     ; hit end, handle wrap around
  428.  
  429. wrq4:   mov     es:[di].ci_qout.ioq_in,cx       ; and save the new pointer
  430.         or      bx,bx
  431.         jnz     wrq0                            ; more bytes to xfer
  432.  
  433. ; Release virtual address
  434.  
  435. wrq5:   mov     ax,es
  436.         mov     ds,ax                           ; (ds) -> DD data
  437.         ASSUME  ds:DSEG
  438.  
  439. ;       mov     dl,DevHlp_UnPhysToVirt
  440. ;       DevHelp
  441.  
  442.         RestoreReg      <cx>                    ; (cx) = requested transfer
  443.  
  444.         sub     cx,bx                           ; (cx) = actual transfer
  445.         add     es:[di].ci_qout.ioq_count,cx    ; adjust ioq_count
  446.  
  447.         RestoreReg      <di,es>         ; (es:di) -> request packet
  448.         RestoreReg      <si>            ; (ds:si) -> ComInfo
  449.         ChkComInfoPtr
  450.         ChkRPPtr
  451.  
  452.         add     es:[di].IOpData._lo,cx  ; adjust physical address pointer
  453. ;       adc     es:[di].IOpData._hi,0
  454.         xchg    cx,bx                   ; (cx) = byte count
  455.                                         ; (bx) = actual transfer
  456.         mov     [si].ci_w_to_move,cx    ; update number left to move
  457.  
  458.         ret
  459.  
  460. EndProc WriteQueue
  461.  
  462.  
  463. ;**     CopyQueue - move contents of memory
  464. ;
  465. ;       We copy bytes from one place to another, optimizing for
  466. ;       word alignment (word aligned moves are faster).
  467. ;
  468. ;       ENTRY   (ds:si) -> source
  469. ;               (es:di) -> destination
  470. ;               (cx)    = byte count
  471. ;
  472. ;       EXIT    (ds:si) -> one past last byte copied in source
  473. ;               (es:di) -> one past last byte copied in dest
  474. ;               (cx) = 0
  475. ;
  476. ;       NOTE    Move is assumed to be non-overlapping
  477. ;               Length is assumed to be non-zero
  478. ;
  479. ;       USES    si di cx flags
  480.  
  481. Procedure CopyQueue,NEAR
  482.         ASSUME  cs:CSEG,ds:DSEG,es:NOTHING,ss:NOTHING
  483.  
  484.         jcxz    cpqer
  485.  
  486.         test    si,1
  487.         jz      cpq1            ; source is even
  488.         test    di,1
  489.         jz      cpq1            ; dest is even
  490.         movsb                   ; both are odd, copy one byte to make both even
  491.         dec     cx              ; and adjust the count
  492.         jz      cpq2            ; it was only one byte
  493.  
  494. cpq1:   shr     cx,1            ; word count, carry set if count was odd
  495.         rep     movsw           ; mov cx words (doesn't jam carry flag)
  496.         jnc     cpq2            ; count was even, we're done
  497.         movsb
  498.  
  499. cpq2:   ret
  500.  
  501. cpqer:
  502.         ComErr  <CopyQueue : count is zero.>
  503.  
  504. EndProc CopyQueue
  505.  
  506.  
  507. CSEG    ENDS
  508.  
  509.         END
  510.