home *** CD-ROM | disk | FTP | other *** search
/ Point Programming 1 / PPROG1.ISO / c / pas_sdk1 / pas / subs / midi / midia.asm < prev    next >
Encoding:
Assembly Source File  |  1992-09-23  |  39.8 KB  |  1,752 lines

  1. ;#>
  2.  
  3. ;$Author:   DCODY  $
  4. ;$Date:   23 Sep 1992 10:34:44  $
  5. ;$Header:   X:/sccs/midi/midia.asv   1.6   23 Sep 1992 10:34:44   DCODY  $
  6. ;$Log:   X:/sccs/midi/midia.asv  $
  7. ;  
  8. ;     Rev 1.6   23 Sep 1992 10:34:44   DCODY
  9. ;  changed MVGetH... to mvGetH...
  10. ;  
  11. ;     Rev 1.5   04 Sep 1992 16:55:12   DCODY
  12. ;  NEAR external choked large model programs
  13. ;  
  14. ;     Rev 1.4   20 Jul 1992 11:42:44   DCODY
  15. ;  call to MVGetHWVersion requests active I/O detection. Found some
  16. ;  I/O that was not relocatable, and now performs XOR relocation.
  17. ;  
  18. ;     Rev 1.3   17 Jul 1992 13:57:30   DCODY
  19. ;  make I/O addresses relocatable.
  20. ;  
  21. ;     Rev 1.2   27 Jun 1992 15:44:56   DCODY
  22. ;  removed debug output code.
  23. ;  
  24. ;     Rev 1.1   25 Jun 1992 21:48:46   DCODY
  25. ;  PAS2 update
  26. ;  
  27. ;     Rev 1.0   15 Jun 1992 10:42:58   BCRANE
  28. ;  Initial revision.
  29. ;$Logfile:   X:/sccs/midi/midia.asv  $
  30. ;$Modtimes$
  31. ;$Revision:   1.6  $
  32. ;$Workfile:   midia.asm  $ 
  33.  
  34. ;#<
  35.  
  36.         Title   MIDIA.ASM  --  Media Vision 3802 Midi Hardware Dependent Module
  37.     Subttl    Copyright (c) 1991,1992. Media Vision Inc. All Rights Reserved.
  38.     page    64,131
  39.  
  40. ;   /*\
  41. ;---|*|-----------------------====< MIDIA.ASM >====------------------------
  42. ;---|*|
  43. ;---|*| Low Level MIDI I/O routines for the Pro Audio Spectrum cards.
  44. ;---|*|
  45. ;   \*/
  46.  
  47.     .xlist
  48.     include model.inc
  49.     include masm.inc
  50.     include mvmidi.inc
  51.     include common.inc
  52.     include target.inc
  53.         .list
  54.  
  55. ;
  56. ;   /*\
  57. ;---|*|----====< int mvMIDIEnable >====----
  58. ;---|*|
  59. ;---|*| mvMIDIEnable - Initialize the MIDI interface
  60. ;---|*|
  61. ;---|*|   Entry Conditions:
  62. ;---|*|      wParm1 is a bit field for process control
  63. ;---|*|      D0 = 1 to enable input interrupts
  64. ;---|*|      D1 = 1 to enable output interrupts
  65. ;---|*|
  66. ;---|*|   Exit Conditions:
  67. ;---|*|      AX = -1 if cannot init the MIDI hardware.
  68. ;---|*|
  69. ;---|*|----====< void mvMIDIDisable >====----
  70. ;---|*|
  71. ;---|*| mxdDisable - MIDI shutdown
  72. ;---|*|
  73. ;---|*| Entry Conditions
  74. ;---|*|     None
  75. ;---|*|
  76. ;---|*| Exit Conditions
  77. ;---|*|     There is no return value.
  78. ;---|*|
  79. ;---|*|----====< int mvMIDIGetBuff >====----
  80. ;---|*|
  81. ;---|*| mvMIDIGetBuff - get data byte from MIDI channel
  82. ;---|*|
  83. ;---|*| Entry Conditions
  84. ;---|*|     wParm1 holds the count to move
  85. ;---|*|     dParm2 points to the target buffer
  86. ;---|*|
  87. ;---|*| Exit Conditions
  88. ;---|*|     AX = 0, no data, # of bytes moved
  89. ;---|*|
  90. ;---|*|----====< int mvMIDIGetByte >====----
  91. ;---|*|
  92. ;---|*| mvMIDIGetByte - get/check one byte from MIDI channel buffer
  93. ;---|*|
  94. ;---|*| Entry Conditions
  95. ;---|*|     None
  96. ;---|*|
  97. ;---|*| Exit Conditions
  98. ;---|*|     AX = byte, or -1 if no data
  99. ;---|*|
  100. ;---|*|----====< void mvMIDISendBuff >====----
  101. ;---|*|
  102. ;---|*| mvMIDISendBuff - send a buffer of data
  103. ;---|*|
  104. ;---|*| Entry Conditions
  105. ;---|*|     wParm1 = integer of count to load
  106. ;---|*|     dParm1 = far pointer to the buffer
  107. ;---|*|
  108. ;---|*| Exit Conditions
  109. ;---|*|     There is no return value.
  110. ;---|*|
  111. ;---|*|----====< void mvMIDISendByte >====----
  112. ;---|*|
  113. ;---|*| mvMIDISendByte - send data byte out MIDI channel
  114. ;---|*|
  115. ;---|*| Entry Conditions
  116. ;---|*|     wParm1  datum
  117. ;---|*|
  118. ;---|*| Exit Conditions
  119. ;---|*|     There is no return value.
  120. ;---|*|
  121. ;   \*/
  122. ;
  123.     .data
  124. ;
  125. ;   /*\
  126. ;---|*|------------====< Global Data Definitions >====------------
  127. ;   \*/
  128. ;
  129.     extrn    _MVTranslateCode:word
  130.     extrn    _MVHWVersionBits:word
  131. ;
  132. ; The overflow count will always be here, but we won't make it public
  133. ; except for debugging purposes
  134. ;
  135.  
  136. ifdef DEBUG
  137.         public  _overflow
  138. endif
  139. _overflow       dw      0               ; overflow count
  140.  
  141. ;
  142. ; MidiInFilter allows certain types of MIDI messages to be tossed out...
  143. ;
  144. ;   NOTE: this currently works for active sense ONLY.
  145. ;
  146.     public    _MidiInFilter
  147. _MidiInFilter    dw    MF_ACTSENSE    ; default ignores active sense
  148.  
  149. ;
  150. ;   /*\
  151. ;---|*|------------====< Private Data Definitions >====------------
  152. ;   \*/
  153. ;
  154.  
  155. ;
  156. ; This midi code uses interrupt driven I/O, so a circular buffer is used
  157. ; to support the data flow.
  158. ;
  159.  
  160. MAXQUEUE    equ    128
  161.  
  162. ;
  163. ; MIDI input circular buffer
  164. ;
  165. iCircularQueue    db    MAXQUEUE    dup (0)
  166.  
  167. MIDIiQueueCnt    dw    0
  168.  
  169. lpiMIQueue    dw    iCircularQueue
  170. lpiMOQueue    dw    iCircularQueue
  171.  
  172. ;
  173. ; MIDI output circular buffer
  174. ;
  175. oCircularQueue    db    MAXQUEUE    dup (0)
  176.  
  177. MIDIoQueueCnt    dw    0
  178.  
  179. lpoMIQueue    dw    oCircularQueue
  180. lpoMOQueue    dw    oCircularQueue
  181.  
  182. ;
  183. ; Interrupt channel number and mask
  184. ;
  185.  
  186. _IRQNumb        db      -1
  187. _IRQMask    db    0
  188.  
  189. ;
  190. ; Interrupt Service Routine re-entrancy sema-phore
  191. ;
  192. ISRbusy         db      -1              ; ISR semaphore
  193.  
  194. ;
  195. ; Internal process control to handle polled or interrupt driven data I/O
  196. ;
  197. ProcessControl  db      0               ; Interrupt or polled I/O
  198. INTINPUT    equ    00000001b
  199. INTOUTPUT    equ    00000010b    ; (currently not implemented)
  200.  
  201.  
  202. ;
  203. ;   /*\
  204. ;---|*|------------====< Yamaha 3802 midi interface variables >====------------
  205. ;   \*/
  206. ;
  207.  
  208. MDctrl        db    0    ; MDSYSCTLR shadow for write only hardware
  209. ISRenab     db    0    ; R06 TX and RX int enable bits
  210.  
  211. ; r02/r03/r06 bit definitions
  212. TxIRQ    equ    01000000b    ; Tx FIFO interrupt
  213. RxIRQ    equ    00100000b    ; Rx FIFO interrupt
  214.  
  215. ; r34 bit definitions
  216. RxRDY    equ    10000000b    ; Rx FIFO non-empty
  217.  
  218. ; r54 bit definitions
  219. TxEMP    equ    10000000b    ; Tx FIFO empty
  220. TxRDY    equ    01000000b    ; Tx FIFO non-full
  221.  
  222. TIMER1    equ    2173
  223.  
  224. ;
  225. ;------------------------================================----------------------
  226. ;------------------------====< MIDI Common Routines >====----------------------
  227. ;------------------------================================----------------------
  228. ;
  229.         .code
  230.     assume    ds:@data,es:nothing
  231.  
  232.     externADDR    mvGetHWVersion        ; determine the installed hardware type
  233. ;
  234. ; We will save the old IRQ vector here to guarrantee access at all times.
  235. ;
  236.  
  237. OldISR          dd      0               ; holds the original IRQ vector
  238.  
  239. ;
  240. ;    Toggle the MIDI interrupt to stimulate latent IRQs
  241. ;
  242. ToggleMV101mask macro
  243.  
  244.         mov     dx,INTRCTLR
  245.     xor    dx,[_MVTranslateCode]
  246.  
  247.     in    al,dx            
  248.     xor    al,bICmidi    ; disable MIDI interrupts
  249.     out    dx,al
  250.     pause
  251.     xor    al,bICmidi    ; enable MIDI interrupts
  252.     out    dx,al
  253.  
  254.     endm
  255.  
  256. ;
  257. ;   /*\
  258. ;---|*|----====< int mvMIDIEnable >====----
  259. ;---|*|
  260. ;---|*| Initialize the MIDI interface
  261. ;---|*|
  262. ;---|*| Entry Conditions:
  263. ;---|*|       wParm1 is a bit field for process control:
  264. ;---|*|      D0 = 1 to enable input interrupts.
  265. ;---|*|      D1 = 1 to enable output interrupts.
  266. ;---|*|
  267. ;---|*| Exit Conditions:
  268. ;---|*|     AX = -1 if cannot init the MIDI hardware.
  269. ;---|*|
  270. ;   \*/
  271. ;
  272.         public  mvMIDIEnable
  273. mvMIDIEnable   proc
  274.     push    bp            ; frame the stack for our 1 parameter
  275.     mov    bp,sp
  276. ;
  277. ; reset the MIDI buffering system
  278. ;
  279.     mov    [lpiMIQueue],OFFSET iCircularQueue
  280.     mov    [lpiMOQueue],OFFSET iCircularQueue
  281.     mov    [lpoMIQueue],OFFSET oCircularQueue
  282.     mov    [lpoMOQueue],OFFSET oCircularQueue
  283.     mov    [MIDIoQueueCnt],0
  284.     mov    [MIDIiQueueCnt],0
  285.     mov    [_overflow],0
  286.     mov    [_MidiInFilter],MF_ACTSENSE
  287. ;
  288. ; If the hardware bits have not been determined, do it...
  289. ;
  290.     cmp    _MVHWVersionBits,-1    ; version bits = -1 if the function
  291.     jnz    @F            ; hasn't been called yet.
  292.     mov    ax,USE_ACTIVE_ADDR    ; do the call
  293.     push    ax            ; to setup the hardware bits, etc.
  294.     call    mvGetHWVersion
  295.     pop    ax
  296.     ;
  297.     @@:
  298. ;
  299. ; determine the IRQ for the Pro Audio card
  300. ;
  301.     call    whereirq        ; looks for MVSOUND.SYS
  302. ;
  303. ; convert each bit to a full mask. Send this mask to each routine.
  304. ;
  305.     mov    ax,wParm1        ; load the bit flags
  306.     mov    [ProcessControl],al    ; save as our process control
  307.     ror    ax,1            ; ah holds input bit, al holds output
  308.     neg    ah
  309.     sbb    ah,ah            ; ah = FF to enable ints, else 0
  310.     neg    al
  311.     sbb    al,al            ; al = FF to enable ints, else 0
  312. ;
  313. ; perform the proper init
  314. ;
  315.     test    [_MVHWVersionBits],bMV101; MV101 version of MIDI?
  316.     jz    @F             ; no, go do yamaha
  317. ;
  318. ; initialize the MV101 MIDI device
  319. ;
  320.         call    enable_mv101
  321.     pop    bp
  322.         ret
  323. ;
  324. @@:
  325. ;
  326. ; initialize the Yamaha 3802
  327. ;
  328.         call    enable_yamaha
  329.     pop    bp
  330.         ret
  331.  
  332. mvMIDIEnable   endp
  333.  
  334. ;
  335. ;   /*\
  336. ;---|*|----====< void mvMIDIDisable >====----
  337. ;---|*|
  338. ;---|*| MIDI device shutdown.
  339. ;---|*|
  340. ;---|*| Entry Conditions:
  341. ;---|*|     None.
  342. ;---|*|
  343. ;---|*| Exit Conditions:
  344. ;---|*|     There is no return value.
  345. ;---|*|
  346. ;   \*/
  347. ;
  348.         public  mvMIDIDisable
  349. mvMIDIDisable  proc
  350. ;
  351. ; remove ourselves from the chain
  352. ;
  353.         call    unhook_interrupt
  354. ;
  355. ; perform the proper init
  356. ;
  357.     test    [_MVHWVersionBits],bMV101; MV101 version of MIDI?
  358.     jz    @F             ; no, go do yamaha
  359.  
  360.     call    disable_MV101        ; disable the MV101 MIDI
  361.         ret
  362.     ;
  363.     @@:
  364.     call    disable_yamaha        ; disable the Yamaha MIDI
  365. ;
  366. midblexit:
  367.         ret
  368.  
  369. mvMIDIDisable  endp
  370.  
  371. ;
  372. ;   /*\
  373. ;---|*|----====< int mvMIDIGetBuff >====----
  374. ;---|*|
  375. ;---|*| Get data byte from MIDI channel.
  376. ;---|*|
  377. ;---|*| Entry Conditions
  378. ;---|*|     wParm1 holds the count to move.
  379. ;---|*|     dParm2 points to the target buffer.
  380. ;---|*|
  381. ;---|*| Exit Conditions
  382. ;---|*|     AX = 0, no data, # of bytes moved.
  383. ;---|*|
  384. ;   \*/
  385. ;
  386.         public  mvMIDIGetBuff
  387. mvMIDIGetBuff  proc
  388.     push    bp
  389.     mov    bp,sp
  390. ;
  391. ; save the C criticals
  392. ;
  393.         push    es
  394.     push    si
  395.     push    di
  396. ;
  397. ; load the parameters
  398. ;
  399.         mov     cx,wParm1               ; get the number of bytes to move
  400.     les    di,wParm2        ; get the target pointer
  401.     mov    si,[lpiMOqueue]     ; get the source pointer
  402.     sub    dx,dx            ; dx holds the # of bytes moved
  403.     cld
  404. ;
  405. ; using interrupt driven input?
  406. ;
  407.         test    [ProcessControl],INTINPUT
  408.     jz    mvigb_20        ; polled, check each h/w
  409. ;
  410. mvigb_05:
  411. ;
  412. ; read as many bytes out of the queues until one is empty, or full.
  413. ;
  414.     cmp    [MIDIiQueueCnt],0    ; all done?
  415.     jz    mvigb_10        ; yes, return # of bytes moved
  416.     movsb
  417.     dec    [MIDIiQueueCnt]     ; one less byte here...
  418.     inc    dx
  419.     cmp    si,offset iCircularQueue+MAXQUEUE
  420.     jl    @F
  421.     mov    si,offset iCircularQueue
  422.     ;
  423.     @@:
  424.     loop    mvigb_05        ; get it all...
  425. ;
  426. mvigb_10:
  427.     mov    [lpiMOQueue],si     ; save the pointer
  428.     mov    ax,dx
  429. ;
  430. mvigb_ret:
  431.     pop    di
  432.     pop    si
  433.     pop    es
  434.     pop    bp
  435.         ret
  436. ;
  437. mvigb_20:
  438. ;
  439. ; This is a little slow, but avoids messy code duplication
  440. ;
  441.     push    si            ; save si
  442.     mov    si,cx            ; si will be our loop counter
  443.     mov    bp,cx            ; bp will hold the total count
  444. ;
  445. mvigb_25:
  446.     call    FFAR ptr mvMIDIGetByte    ; get the next byte
  447.     cmp    ax,-1            ; any data?
  448.     jz    mvigb_30        ; nope, we're done...
  449.     stosb                ; save in the callers buffer
  450.     dec    si            ; all done?
  451.     jnz    mvigb_25        ; nope, continue looping
  452. ;
  453. mvigb_30:
  454.         sub     bp,si                   ; bp holds the total read count
  455.     mov    ax,bp
  456.     pop    si
  457.     jmp    short mvigb_ret
  458.  
  459. mvMIDIGetBuff  endp
  460.  
  461. ;
  462. ;   /*\
  463. ;---|*|----====< int mvMIDIGetByte >====----
  464. ;---|*|
  465. ;---|*| Get one byte from MIDI channel buffer.
  466. ;---|*|
  467. ;---|*| Entry Conditions
  468. ;---|*|     None.
  469. ;---|*|
  470. ;---|*| Exit Conditions
  471. ;---|*|     AX = -1 if no data.
  472. ;---|*|     AH =  0 if data in AL.
  473. ;---|*|
  474. ;   \*/
  475. ;
  476.         public  mvMIDIGetByte
  477. mvMIDIGetByte  proc
  478. ;
  479. ; If the code is running as interrupt input, then we can check the queue
  480. ;
  481.         test    [ProcessControl],INTINPUT
  482.     jz    mvgbt_20        ; polled, check each h/w
  483.  
  484.     cmp    [MIDIiQueueCnt],0    ; any data?
  485.     jz    mvgbt_none        ; no, just return now
  486.  
  487.     mov    bx,[lpiMOqueue]     ; get the source pointer
  488.     sub    ah,ah            ; clear out the top
  489.     mov    al,[bx]         ; load the bottom
  490.  
  491.     dec    [MIDIiQueueCnt]     ; one less byte here...
  492.     inc    bx
  493.     cmp    bx,offset iCircularQueue+MAXQUEUE
  494.     jl    mvgbt_05
  495.     mov    bx,offset iCircularQueue
  496. ;
  497. mvgbt_05:
  498.     mov    [lpiMOqueue],bx     ; save the new pointer
  499.         ret
  500. ;
  501. mvgbt_none:
  502.     mov    ax,-1            ; bad, so exit with error flag
  503.     ret
  504. ;
  505. mvgbt_20:
  506. ;
  507. ; This is the polled mode of MIDI input - go check the correct chip FIFO
  508. ;
  509.         test    [_MVHWVersionBits],bMV101; MV101 version of MIDI?
  510.     jz    mvgbt_yamaha         ; no, go do yamaha
  511. ;
  512. ; read the MV101 MIDI fifo
  513. ;
  514.     mov    dx,MIDISTATUS        ; check data available
  515.     xor    dx,[_MVTranslateCode]    ; translated I/O addr
  516.  
  517.     in    al,dx            ; isolate the data available bit
  518.     and    ax,bMSRififo
  519.     jz    mvgbt_none        ; no data available, go report it...
  520.  
  521.     mov    dx,MIDIDATA
  522.         xor     dx,[_MVTranslateCode]   ; translated I/O addr
  523.  
  524.     in    al,dx            ; return the byte in al, ah = 0
  525.  
  526.     ret
  527. ;
  528. mvgbt_yamaha:
  529. ;
  530. ; read the Yamaha 3802 MIDI fifo.
  531. ;
  532.         mov     al, 3                   ; 3x
  533.     mov    dx, MDSYSCTLR        ; set the 3802 global reg set index
  534.     mov    [MDctrl],al        ; shadow...
  535.     out    dx, al
  536.  
  537.         mov     dx, MDGROUP4            ; 34 = FIFO-Rx status
  538.     in    al, dx
  539.     and    ax, RxRDY        ; RxRDY bit?
  540.         jz      mvgbt_none              ; no data available, go report it...
  541.  
  542.     mov    dx, MDGROUP6        ; 36 = FIFO-Rx data
  543.  
  544.     in    al, dx            ; return the byte in al, ah = 0
  545.  
  546.     ret
  547.  
  548. mvMIDIGetByte  endp
  549.  
  550. ;
  551. ;   /*\
  552. ;---|*|----====< void mvMIDISendByte >====----
  553. ;---|*|
  554. ;---|*| mvMIDISendByte - send a MIDI data byte out the MIDI channel.
  555. ;---|*|
  556. ;---|*| Entry Conditions
  557. ;---|*|     wParm1 - MIDI byte to be sent.
  558. ;---|*|
  559. ;---|*| Exit Conditions
  560. ;---|*|     There is no return value.
  561. ;   \*/
  562. ;
  563.     public    mvMIDISendByte
  564. mvMIDISendByte    proc
  565. ;
  566. ; send the byte out directly if polled output, else queue it up to keep order
  567. ;
  568.         push    bp
  569.     mov    bp,sp
  570.  
  571.     mov    al,wParm1        ; grab the byte
  572.  
  573.     test    [ProcessControl],INTOUTPUT ; interrupt output?
  574.     jnz    mvsnd_ints           ; yes, we will queue it...
  575.  
  576.         call    dosendbyte              ; send it out straight
  577.  
  578.         pop     bp
  579.     ret
  580. ;
  581. mvsnd_ints:
  582. ;
  583. ; Interrupt driven output requires the byte be queue to keep the byte order.
  584. ;
  585.         mov     bx,[lpoMIQueue]         ; get the input-to-buffer pointer
  586. ;
  587. @@:
  588.     cmp    [MIDIoQueueCnt],MAXQUEUE; is the internal queue full?
  589.     jnz    @F            ; no, go load another byte
  590.     call    primexmit        ; make sure the xmitter is working
  591.     jmp    short @B        ; go wait for data to move
  592. ;
  593. @@:
  594.     mov    [bx],al
  595.     inc    bx
  596.     cmp    bx,offset oCircularQueue+MAXQUEUE ; wrapped?
  597.     jnz    @F
  598.     mov    bx,offset oCircularQueue      ; yes, go back to the beginning
  599. ;
  600. @@:
  601.         mov     [lpoMIQueue],bx         ; save the new input-to-buffer pointer
  602.     inc    [MIDIoQueueCnt]     ; add one more into the FIFO
  603.  
  604.         call    primexmit               ; make sure the xmitter is working
  605.     pop    bp
  606.     ret
  607.  
  608. mvMIDISendByte endp
  609.  
  610. ;
  611. ;   /*\
  612. ;---|*|----====< void mvMIDISendBuff >====----
  613. ;---|*|
  614. ;---|*| mvMIDISendBuff - send a buffer of data.
  615. ;---|*|
  616. ;---|*| Entry Conditions
  617. ;---|*|     wParm1 = integer of count to load.
  618. ;---|*|     dParm1 = far pointer to the buffer.
  619. ;---|*|
  620. ;---|*| Exit Conditions
  621. ;---|*|     Returns when all the bytes are loaded in the circular queue.
  622. ;   \*/
  623. ;
  624.     public    mvMIDISendBuff
  625. mvMIDISendBuff    proc
  626.         push    bp
  627.     mov    bp,sp            ; 'C' frame
  628.  
  629.     push    es            ; save the 'C' criticals
  630.     push    si
  631. ;
  632. ; we will load the entire block into the FIFO. This even means waiting for the
  633. ; transmitter to empty enough data until we're done.
  634. ;
  635.     mov    cx,wParm1        ; get the buffer counter
  636.     les    si,wParm2        ; get the far pointer
  637.     mov    bx,[lpoMIQueue]     ; get the input-to-buffer pointer
  638. ;
  639. queueloop:
  640.     cmp    [MIDIoQueueCnt],MAXQUEUE; is the internal queue full?
  641.     jnz    @F            ; no, go load another byte
  642.     call    primexmit        ; make sure the xmitter is working
  643.     jmp    short queueloop
  644. ;
  645. @@:
  646.     lods    byte ptr es:[si]    ; get the next MIDI byte
  647.     mov    [bx],al
  648.     inc    bx
  649.     cmp    bx,offset oCircularQueue+MAXQUEUE ; wrapped?
  650.     jnz    @F
  651.     mov    bx,offset oCircularQueue      ; yes, go back to the beginning
  652. ;
  653. @@:
  654.     inc    [MIDIoQueueCnt]     ; add one more into the FIFO
  655.     loop    queueloop        ; load all the bytes into the queue
  656.     mov    [lpoMIQueue],bx     ; save the new input-to-buffer pointer
  657. ;
  658. ; We've loaded the FIFO. if polling, call the output routine till done.
  659. ;
  660.     test    [ProcessControl],INTOUTPUT ; interrupt driven output?
  661.     jnz    sendbuffints           ; yes, force the xmitter to work
  662. ;
  663. ; this byte goes out the MV101
  664. ;
  665.     @@:
  666.     call    primexmit        ; make sure the xmitter is working
  667.     cmp    [MIDIoQueueCnt],0    ; any more queued up data?
  668.     jnz    @B            ; yes, stay here till sent...
  669.  
  670.     jmp    short sendbuffexit    ; all done, return home
  671. ;
  672. sendbuffints:
  673. ;
  674. ; make sure the xmitter is primed to generate interrupts
  675. ;
  676.     call    primexmit
  677. ;
  678. sendbuffexit:
  679.     pop    si
  680.     pop    es
  681.     pop    bp
  682.     ret
  683.  
  684. mvMIDISendBuff endp
  685.  
  686. ;
  687. ;---------------------------==============================---------------------
  688. ;---------------------------====< Local Subroutines > ====---------------------
  689. ;---------------------------==============================---------------------
  690. ;
  691.  
  692. ;
  693. ;   /*\
  694. ;---|*|----====< disable_MV101 >====----
  695. ;---|*|
  696. ;---|*| This routine will disable any MV101 MIDI
  697. ;---|*| interrupts and reset the tranceiver.
  698. ;---|*|
  699. ;---|*| Entry Conditions:
  700. ;---|*|     None.
  701. ;---|*|
  702. ;---|*| Exit Conditions:
  703. ;---|*|     AX, DX modified
  704. ;---|*|
  705. ;   \*/
  706. ;
  707. disable_MV101    proc    near
  708.  
  709.     mov    dx,MIDICONTROL        ; get the control address
  710.     xor    dx,[_MVTranslateCode]    ; translate the address
  711.  
  712.         sub     al,al                   ; flush all enables
  713.     out    dx,al            ; kill fifo irq
  714.  
  715.         ret
  716.  
  717. disable_MV101   endp
  718.  
  719. ;
  720. ;   /*\
  721. ;---|*|----====< disable_yamaha >====----
  722. ;---|*|
  723. ;---|*| This routine will disable any Yamaha MIDI
  724. ;---|*| interrupts and reset the tranceiver.
  725. ;---|*|
  726. ;---|*| Entry Conditions:
  727. ;---|*|     None.
  728. ;---|*|
  729. ;---|*| Exit Conditions:
  730. ;---|*|     AX, DX modified
  731. ;---|*|
  732. ;   \*/
  733. ;
  734. disable_yamaha  proc    near
  735. ;
  736. ; disable interrupts in the yamaha 3802
  737. ;
  738.     sub    ax, ax
  739.     mov    [MDctrl], al
  740.     mov    dx, MDSYSCTLR
  741.     out    dx, al            ; 0x
  742.  
  743.         mov     dx, MDGROUP6            ; 06 = IRQ enable request
  744.     out    dx, al
  745.  
  746.         .errnz  MDGROUP6-MDGROUP5-1
  747.  
  748.     dec    dx            ; 05 = IRQ mode control
  749.     out    dx, al
  750.  
  751.         ret
  752.  
  753. disable_yamaha    endp
  754.  
  755. ;
  756. ;   /*\
  757. ;---|*|----====< dosendbyte >====----
  758. ;---|*|
  759. ;---|*| A generic routine to send one byte out to the hardware.
  760. ;---|*|
  761. ;---|*| Entry Conditions;
  762. ;---|*|     AL holds the byte to be sent.
  763. ;---|*|
  764. ;---|*| Exit Conditions:
  765. ;---|*|     AX,BX,CX,DX modified.
  766. ;---|*|     Byte sent, no return value.
  767. ;---|*|
  768. ;   \*/
  769. ;
  770. dosendbyte      proc    near
  771. ;
  772. ; save the byte until we need it...
  773. ;
  774.         mov     ah,al                   ; ah holds the byte to send
  775. ;
  776. ; select the proper chip.
  777. ;
  778.         test    [_MVHWVersionBits],bMV101; MV101 version of MIDI?
  779.     jz    send_yamaha         ; no, go do yamaha
  780. ;
  781. ; this byte goes out the MV101
  782. ;
  783.     mov    dx, MIDIFIFOS        ; get the transmitter status
  784.         xor     dx,[_MVTranslateCode]   ; translated I/O addr
  785. ;
  786. ; we will only load up to 15 bytes in the output FIFO since a zero count
  787. ; means either 16 bytes free or 0 bytes free. By only loading 15 bytes max,
  788. ; we assume a zero means 16 bytes free.
  789. ;
  790.     in    al,dx            ; get the FIFO output free room count
  791.     and    al,bMFCofifo        ; isolate the count
  792.     jz    mvsendit        ; 16 bytes free
  793.     sub    cx,cx            ; we will do a timeout
  794.     ;
  795.     @@:
  796.     in    al, dx            ; get the FIFO counts
  797.     and    al, bMFCofifo        ; any room in the output FIFO?
  798.     cmp    al, 10h         ; one byte left in the FIFO?
  799.     loopz    @b            ; wait till there is more room
  800.     jcxz    deadtx            ; exit on a timeout
  801. ;
  802. mvsendit:
  803.     mov    dx, MIDIDATA        ; get the data output port
  804.         xor     dx,[_MVTranslateCode]   ; translated I/O addr
  805.  
  806.     mov    al, ah
  807.     out    dx, al            ; ship stuff...
  808. ;
  809. deadtx:
  810.         ret
  811. ;
  812. send_yamaha:
  813. ;
  814. ; this byte goes out the yamaha 3802
  815. ;
  816.         mov     al, 5                   ; 5x
  817.     mov    [MDctrl], al        ; shadow it...
  818.     mov    dx, MDSYSCTLR        ; get the port
  819.     out    dx, al            ; let'er rip...
  820.  
  821.     mov    dx, MDGROUP4        ; 54 = FIFO-Tx status
  822. ;
  823. @@:     in      al, dx
  824.     test    al, TxRDY        ; TxRDY bit?
  825.     jz    @b            ; ..jump if FIFO full
  826.  
  827.     mov    dl, LOW MDGROUP6    ; 56 = FIFO-Tx data
  828.     mov    al, ah
  829.     out    dx, al            ; ship datum
  830.  
  831.     ret
  832.  
  833. dosendbyte    endp
  834.  
  835. ;
  836. ;   /*\
  837. ;---|*|----====< enable_mv101 >====----
  838. ;---|*|
  839. ;---|*| Enable the MV101 tranceiver, and any appropriate interrupts
  840. ;---|*|
  841. ;---|*| Entry Conditions:
  842. ;---|*|     AH = FF to enable input interrupts
  843. ;---|*|     AL = FF to enable output interrupts
  844. ;---|*|
  845. ;---|*| Exit Conditions:
  846. ;---|*|     AX,BX,CX,DX modified.
  847. ;---|*|
  848. ;   \*/
  849. ;
  850. enable_mv101    proc    near
  851. ;
  852. ; build the correct mask bits in ah
  853. ;
  854.     and    ax,(bMCRenafifoi SHL 8) + bMCRenafifoo
  855.     or    ah,al            ; ah holds the enable bits
  856. ;
  857. ; do something to the test register
  858. ;
  859. ;;;    mov    dx,MIDITEST
  860. ;;;    xor    dx,[_MVTranslateCode]    ; translated I/O addr
  861. ;;;    mov    al,0FFh
  862. ;;;    out    dx,al
  863. ;
  864. ; setup the MIDI prescale
  865. ;
  866.         mov     dx,MIDIPRESCALE
  867.         xor     dx,[_MVTranslateCode]   ; translated I/O addr
  868.     mov    al,10h            ;
  869.     out    dx,al
  870. ;
  871. ; reset the fifos
  872. ;
  873.     mov    dx,MIDICONTROL
  874.     xor    dx,[_MVTranslateCode]    ; translated I/O addr
  875.     mov    al,bMCRrstfifoi+bMCRrstfifoo
  876.     out    dx,al            ; send the reset bits
  877.     mov    al,ah
  878.     out    dx,al            ; clear reset bits and set enables
  879. ;
  880. ; reset any present status bits
  881. ;
  882.         mov     dx,MIDISTATUS
  883.     xor    dx,[_MVTranslateCode]    ; translated I/O addr
  884.     mov    al,-1            ; reset all midi status bits
  885.     out    dx,al
  886. ;
  887. ; only enable the stuff if we're using interrupts
  888. ;
  889.     test    [ProcessControl],INTINPUT+INTOUTPUT
  890.     jz    enamv_done        ; no interrupts, just exit now...
  891. ;
  892. ; install the interrupt handling now
  893. ;
  894.     cli
  895.  
  896.     lea    ax,MV101_ISR
  897.     call    hook_interrupt        ; insert our routine
  898.  
  899.     sti
  900. ;
  901. enamv_done:
  902.         ret
  903.  
  904. enable_mv101    endp
  905.  
  906. ;
  907. ;   /*\
  908. ;---|*|----====< enable_yamaha >====----
  909. ;---|*|
  910. ;---|*| Enable the Yamaha 3802 tranceiver, and any appropriate interrupts.
  911. ;---|*|
  912. ;---|*| Enable the 3802 Yamaha MIDI device
  913. ;---|*|     AH = FF to enable input interrupts.
  914. ;---|*|     AL = FF to enable output interrupts.
  915. ;---|*|
  916. ;---|*| Exit Conditions:
  917. ;---|*|     AX,BX,CX,DX modified.
  918. ;---|*|
  919. ;   \*/
  920. ;
  921. enable_yamaha    proc      near
  922. ;
  923. ; build the correct mask bits in ah
  924. ;
  925.     and    ax,(RxIRQ SHL 8)+ TxIRQ
  926.     or    al,ah            ; al holds the enable bits
  927.     push    ax            ; save the interrupt enable bits
  928. ;
  929. ; reset the 3802 midi chip
  930. ;
  931.     mov    al, 80h         ; master clear
  932.     mov    [MDctrl], al
  933.     mov    dx, MDSYSCTLR
  934.     out    dx, al
  935.  
  936.     mov    cx, 100
  937. @@:    in    al, dx            ; wait 32 TCLK
  938.     loop    @b
  939.  
  940.     xchg    ax,cx            ; load zero
  941.     out    dx,al            ; flush the reset bit
  942.  
  943.     mov    al, 6
  944.     mov    [MDctrl], al
  945.     out    dx, al            ; 6x
  946.     mov    dx, MDGROUP6        ; 66 = Click counter control
  947.     mov    al, 00000010b        ; Clock=1.0MHz, no click pulse
  948.     out    dx, al
  949.  
  950.     mov    al, 4
  951.     mov    [MDctrl], al
  952.     mov    dx, MDSYSCTLR
  953.     out    dx, al            ; 4x
  954.     mov    dx, MDGROUP4        ; 44 = Tx communication rate
  955.     mov    al, 00001000b        ; CLKM/32 = 31,250 bps
  956.     out    dx, al
  957.  
  958.     mov    al, 2
  959.     mov    [MDctrl], al
  960.     mov    dx, MDSYSCTLR
  961.     out    dx, al            ; 2x
  962.     mov    dx, MDGROUP4        ; 24 = Rx communication rate
  963.     mov    al, 00001000b        ; CLKM/32 = 31,250 bps
  964.     out    dx, al
  965.  
  966.     mov    al, 5
  967.     mov    [MDctrl], al
  968.     mov    dx, MDSYSCTLR
  969.     out    dx, al            ; 5x
  970.     mov    dx, MDGROUP5        ; 55 = FIFO-Tx control
  971.     mov    al, 10000101b        ; TxE
  972.     out    dx, al
  973.  
  974.     mov    al, 8
  975.     mov    [MDctrl], al
  976.     mov    dx, MDSYSCTLR
  977.     out    dx, al            ; 8x
  978.     mov    dx, MDGROUP4        ; 84 = General Timer LSB
  979.     mov    ax, TIMER1
  980.     out    dx, al
  981.     mov    dx, MDGROUP5        ; 85 = General Timer MSB
  982.     xchg    ah, al
  983.     out    dx, al
  984. ;
  985. ; clear the FIFO-Rx
  986. ;
  987.     mov    al, 3            ; 35 = RCR: FIFO-Rx control
  988.     mov    [MDctrl], al        ; bit 7 = clear FIFO-Rx
  989.     mov    dx, MDSYSCTLR        ; bit 6 = clear RxOV flag
  990.     out    dx, al            ; bit 4 = enable MIDI-clock filter
  991.     mov    dx, MDGROUP5        ; bit 3 = clear BRK flag
  992.     mov    al, 11001101b        ; bit 2 = clear RxOL flag
  993.     out    dx, al            ; bit 1 = enable Address-hunter
  994. ;
  995. ; only enable the stuff if we're using interrupts
  996. ;
  997.     test    [ProcessControl],INTINPUT+INTOUTPUT
  998.     jz    enayam_already        ; no interrupts, just exit now...
  999. ;                    ; bit 0 = enable Receiver
  1000. ; initialize the 3802 chip IRQ system
  1001. ;
  1002.         sub     al, al
  1003.     mov    [MDctrl], al
  1004.     mov    dx, MDSYSCTLR
  1005.     out    dx, al            ; 0x
  1006.     mov    dx, MDGROUP5        ; 05 = IRQ mode control
  1007.     mov    al, 0011b        ; VE+VM
  1008.     out    dx, al
  1009. ;
  1010. ; initialize the board and motherboard IRQ systems
  1011. ;
  1012.         cli
  1013.  
  1014.         .errnz  MDGROUP6-MDGROUP5-1
  1015.         inc     dx
  1016.  
  1017.     pop    ax            ; get the interrupt enable bits
  1018.         out     dx, al
  1019.     mov    [ISRenab], al
  1020.  
  1021.         mov     dx, MDGROUP4            ; flush any pending IRQs
  1022.     mov    al, 0ffh
  1023.     out    dx,al
  1024. ;
  1025. ; hook the actual vector
  1026. ;
  1027.     lea    ax,Yamaha_ISR
  1028.         call    hook_interrupt
  1029.  
  1030.         sti
  1031. ;
  1032. enaya_done:
  1033.         ret
  1034. ;
  1035. enayam_already:
  1036.     pop    ax
  1037.     ret
  1038.  
  1039. enable_yamaha    endp
  1040.  
  1041. ;
  1042. ;   /*\
  1043. ;---|*|----====< hook_interrupt >====----
  1044. ;---|*|
  1045. ;---|*| Hook the Pro Audio hardware interrupt,
  1046. ;---|*| and enable the system interrupt.
  1047. ;---|*|
  1048. ;---|*| Entry Conditions:
  1049. ;---|*|     None.
  1050. ;---|*|
  1051. ;---|*| Exit Conditions:
  1052. ;---|*|     AX,BX,CX,DX modified.
  1053. ;---|*|
  1054. ;   \*/
  1055. ;
  1056. hook_interrupt  proc    near
  1057.         push    ds
  1058.     push    es
  1059.  
  1060.     cmp    wptr cs:[OldISR+2],0    ; any segment?
  1061.     jnz    midihooked        ; yes, we've hooked already
  1062.  
  1063.     push    ax            ; save the IRQ offset
  1064.  
  1065.     mov    ax, 3508h        ; DOS : get vector
  1066.     cmp    [_IRQNumb],7        ; 1st IRQ channel?
  1067.     jbe    @F
  1068.     mov    al,70h-8        ; 2nd IRQs start at 70H
  1069.     ;
  1070.     @@:
  1071.     add    al, [_IRQNumb]        ; IRQ
  1072.     push    ax            ; save the IRQ #
  1073.  
  1074.     int    21h            ; fetch the vector
  1075.  
  1076.     mov    wptr cs:[OldISR+0], bx    ; save original value
  1077.     mov    wptr cs:[OldISR+2], es
  1078.  
  1079.     pop    ax
  1080.         pop     dx                      ; get the actual offset
  1081.  
  1082.         push    ds                      ; save ds over the int call
  1083.     push    cs
  1084.     pop    ds            ; ds:dx point to the vector
  1085.     mov    ah, 25h         ; DOS : set vector
  1086.     int    21h
  1087.     pop    ds
  1088. ;
  1089. ; enable the Pro Audio IRQ channel
  1090. ;
  1091.     pushf
  1092.     cli
  1093. ;
  1094. ; address the correct IRQ controller
  1095. ;
  1096.     mov    dx,IRQ1MASKREG
  1097.     cmp    [_IRQNumb],7        ; 1st IRQ controller?
  1098.     jbe    @F            ; yes, continue on...
  1099.     mov    dx,IRQ2MASKREG        ; no, use the 2nd interrupt
  1100.     ;
  1101.     @@:
  1102. ;
  1103. ; Enable the correct IRQ channel
  1104. ;
  1105.         in      al, dx                  ; enable the system IRQ
  1106.     mov    ah, [_IRQMask]
  1107.     not    ah
  1108.     and    al, ah
  1109.     out    dx, al
  1110. ;
  1111. ; Enable the Pro Audio MIDI interrupt
  1112. ;
  1113.     mov    dx, INTRCTLR        ; Enable the PAS. This could signal
  1114.     xor    dx, [_MVTranslateCode]
  1115.     in    al, dx            ; an interrupt immediately.
  1116.     or    al, bICmidi        ; MIDI interrupt enable
  1117.     out    dx, al
  1118.  
  1119.     popf
  1120.     ;
  1121.     midihooked:
  1122.  
  1123.         pop     es
  1124.     pop    ds
  1125.     ret
  1126.  
  1127. hook_interrupt  endp
  1128.  
  1129. ;
  1130. ;   /*\
  1131. ;---|*|----====< void primexmit >====----
  1132. ;---|*|
  1133. ;---|*| Prime the transmitter. If interrupt driven output, make sure the
  1134. ;---|*| outbound FIFO has at least one byte loaded. If polled, send
  1135. ;---|*| the next polled byte.
  1136. ;---|*|
  1137. ;---|*| Entry Conditions:
  1138. ;---|*|    Working registers assumed to hold data.
  1139. ;---|*|
  1140. ;---|*| Exit Conditions:
  1141. ;---|*|    No registers modified.
  1142. ;---|*|
  1143. ;   \*/
  1144. ;
  1145. primexmit    proc    near
  1146. ;
  1147. ; save everything for the caller
  1148. ;
  1149.     pushf                ; save the flags so we can CLI
  1150.     push    ax            ; don't mess with any other registers
  1151.     push    dx
  1152.         push    bx
  1153.     push    cx
  1154. ;
  1155. ; Interrupt driven output is a special case. We just have to prime the pump...
  1156. ;
  1157.     test    [ProcessControl],INTOUTPUT ; interrupt driven output?
  1158.     jnz    prixmints           ; yes, force the xmitter to work
  1159. ;
  1160. prixprimeit:
  1161. ;
  1162. ; This is polled output mode. We just send one byte out. The caller will keep
  1163. ; calling us till the queue is emptied.
  1164. ;
  1165.     cmp    [MIDIoQueueCnt],0    ; any data to send?
  1166.     jz    prixdone        ; no, it's all loaded and gone..
  1167.  
  1168.         mov     bx,[lpoMOQueue]         ; get the out-of-buffer pointer
  1169.     mov    al,[bx]
  1170.     inc    bx
  1171.  
  1172.     cmp    bx,offset oCircularQueue+MAXQUEUE ; wrapped?
  1173.     jnz    @F
  1174.     mov    bx,offset oCircularQueue      ; yes, wrap it...
  1175. ;
  1176. @@:
  1177.     mov    [lpoMOQueue],bx     ; save the new input-to-buffer pointer
  1178.     dec    [MIDIoQueueCnt]     ; add one more into the FIFO
  1179.  
  1180.     call    dosendbyte        ; send it via the polled routines
  1181. ;
  1182. prixdone:
  1183. ;
  1184. ; return with nothing changed
  1185. ;
  1186.         pop     cx
  1187.     pop    bx
  1188.     pop    dx
  1189.     pop    ax
  1190.     popf
  1191.     ret
  1192. ;
  1193. prixmints:
  1194. ;
  1195. ; in case of some MIDI interrupts occuring when we don't expect it, (such
  1196. ; as MIDI in interrupts) this section will be executed without interrupts
  1197. ; to avoid double sending, or sending data from the queue out of order.
  1198. ;
  1199.     cli                ; no ints while we go to prime the pump
  1200. ;
  1201. ; Make sure the transmitter FIFO has data loaded. This guarrantees an interrupt
  1202. ; when the FIFO is empty.
  1203. ;
  1204.     test    [_MVHWVersionBits],bMV101; MV101 version of MIDI?
  1205.     jz    prixyamaha         ; no, go do yamaha
  1206.  
  1207.     mov    dx, MIDIFIFOS        ; get the transmitter FIFO status
  1208.         xor     dx,[_MVTranslateCode]   ; translated I/O addr
  1209.  
  1210.         in      al,dx                   ; get the FIFO output free room count
  1211.     and    al,bMFCofifo        ; isolate the outbound count
  1212.     jnz    prixdone        ; there is data, no need to prime it.
  1213.     jmp    short prixprimeit    ; 16 bytes free - load one more...
  1214. ;
  1215. prixyamaha:
  1216. ;
  1217. ; Yamaha 3802 - we go to TX register set 05 to find the TX empty bit
  1218. ;
  1219.     mov    al, 5            ; reg set 5x is for the xmitter
  1220.     mov    [MDctrl], al
  1221.     mov    dx, MDSYSCTLR
  1222.     out    dx, al            ; 5x
  1223.  
  1224.         mov     dx, MDGROUP4            ; 84 = General Timer LSB
  1225.     in    al,dx
  1226.     test    al,TxEMP        ; is the transmitter empty?
  1227.     jnz    prixprimeit        ; yes, go load another byte
  1228.     jmp    short prixdone        ; no, leave it alone
  1229.  
  1230. primexmit    endp
  1231.  
  1232. ;
  1233. ;   /*\
  1234. ;---|*|----====< unhook_interrupt >====----
  1235. ;---|*|
  1236. ;---|*| If installed, disable the IRQ system, then unhook
  1237. ;---|*| the Pro Audio IRQ handler from the chain.
  1238. ;---|*|
  1239. ;---|*| Entry Conditions:
  1240. ;---|*|    None.
  1241. ;---|*|
  1242. ;---|*| Exit Conditions:
  1243. ;---|*|    AX,BX,CX,DX may be modified.
  1244. ;---|*|
  1245. ;   \*/
  1246. ;
  1247. unhook_interrupt        proc    near
  1248. ;
  1249. ; don't do this if there is no need
  1250. ;
  1251.     cmp    wptr cs:[OldISR+2],0    ; interrupt already unhooked?
  1252.     jz    unhooked        ; yes, just exit
  1253. ;
  1254. ; disable system interrupt for the Pro Audio card
  1255. ;
  1256.     pushf
  1257.         cli
  1258.  
  1259.     test    al,fICintmaskbits    ; any other interrupts enabled
  1260.     jnz    mskint_done        ; yes, leave the system mask alone
  1261.  
  1262.     mov    dx,IRQ1MASKREG
  1263.     cmp    [_IRQNumb],7        ; 1st IRQ controller?
  1264.     jbe    @F            ; yes, continue on...
  1265.     mov    dx,IRQ2MASKREG        ; no, use the 2nd interrupt
  1266.     ;
  1267.     @@:
  1268.     cmp    [_IRQNumb],2        ; hardware IRQ 2?
  1269.     jz    mskint_done        ; yes, never mask it
  1270.  
  1271.     in    al,dx
  1272.     or    al,[_IRQMask]        ; no, kill the system interrupts
  1273.     out    dx,al
  1274. ;
  1275. mskint_done:
  1276.     mov    dx, INTRCTLR        ; disable the Pro Audio MIDI IRQ
  1277.     xor    dx, [_MVTranslateCode]
  1278.     in    al, dx
  1279.     and    al, not bICmidi     ; MIDI interrupt disable
  1280.     out    dx, al
  1281.  
  1282.     popf
  1283. ;
  1284. ; calculate the correct vector and restore it.
  1285. ;
  1286.     mov    ax, 2508h        ; DOS : set vector
  1287.     cmp    [_IRQNumb],7        ; 1st IRQ channel?
  1288.     jbe    @F
  1289.     mov    al,70h-8        ; 2nd IRQs start at 70H
  1290.     ;
  1291.     @@:
  1292.     add    al, [_IRQNumb]        ; IRQ
  1293. ;
  1294. ; do it through DOS...
  1295. ;
  1296.         push    ds
  1297.     lds    dx, cs:[OldISR]
  1298.     int    21h
  1299.     pop    ds
  1300.  
  1301.     mov    wptr cs:[OldISR+2],0    ; flush the segment of the vector
  1302. ;
  1303. unhooked:
  1304.         ret
  1305.  
  1306. unhook_interrupt    endp
  1307.  
  1308. ;
  1309. ;   /*\
  1310. ;---|*|----====< whereirq >====----
  1311. ;---|*|
  1312. ;---|*| This routine queries MVSOUND.SYS for the Pro Audio IRQ. Once
  1313. ;---|*| determined, then an appropriate interrupt mask will be
  1314. ;---|*| generated, and saved for future reference.
  1315. ;---|*|
  1316. ;---|*| Entry Conditions:
  1317. ;---|*|    None.
  1318. ;---|*|
  1319. ;---|*| Exit Conditions:
  1320. ;---|*|    AX,BX,CX,DX may be modified.
  1321. ;---|*|
  1322. ;   \*/
  1323. ;
  1324. whereirq        proc    near
  1325. ;
  1326. ; Do this just once
  1327. ;
  1328.     cmp    [_IRQNumb],-1        ; have we been through here?
  1329.     jnz    IRQdone         ; yes, it's been found
  1330. ;
  1331. ; Call MVSOUND.SYS to get the DMA/IRQ
  1332. ;
  1333.     mov    ax,0bc04h        ; call MVSOUND.SYS for it...
  1334.     int    2fh
  1335. ;
  1336. ; register the IRQ if the call was good
  1337. ;
  1338.     cmp    ax,'MV'                 ; was this a good call?
  1339.     jnz    IRQdone
  1340.  
  1341.     mov    [_IRQNumb],cl        ; save the #
  1342.     mov    ax,1
  1343.     shl    ax,cl
  1344.     or    al,ah
  1345.     mov    [_IRQMask],al        ; save the mask.
  1346. ;
  1347. IRQdone:
  1348.     ret
  1349.  
  1350. whereirq        endp
  1351.  
  1352. ;
  1353. ;------------------------===================================-------------------
  1354. ;------------------------====< MIDI Interrupt Service > ====-------------------
  1355. ;------------------------===================================-------------------
  1356. ;
  1357.  
  1358. ;
  1359. ;   /*\
  1360. ;---|*|----====< MV101_ISR >====----
  1361. ;---|*|
  1362. ;---|*|  ISR service routine for the MV101 MIDI interrupts.
  1363. ;---|*|
  1364. ;   \*/
  1365. ;
  1366. MV101_ISR    proc    far
  1367.     push    ds
  1368.     push    ax
  1369.     push    bx
  1370.     push    cx
  1371.     push    dx
  1372.  
  1373.     mov    ax,@data
  1374.     mov    ds,ax
  1375. ;
  1376. ; first time in, check for a MIDI interrupt
  1377. ;
  1378.     mov    dx,INTRCTLRST
  1379.     xor    dx,[_MVTranslateCode]    ; translate the address
  1380.  
  1381.     in    al,dx            ; get the interrupt status
  1382.     test    al,bISmidi        ; is this our interrupt?
  1383.     jnz    mv_is_midi_int        ; yes, go process it...
  1384.  
  1385.     test    al,fISints        ; are any of these interrupt legit?
  1386.     jjz    midiint_done        ; no, flush this int.
  1387. ;
  1388. ; this was not our interrupt, chain on...
  1389. ;
  1390.     pop    dx
  1391.     pop    cx
  1392.     pop    bx
  1393.         pop     ax
  1394.     pop    ds
  1395.     jmp    dword ptr cs:[OldISR]    ; pass off to the other code.
  1396. ;
  1397. mv_is_midi_int:
  1398. ;
  1399. ; check the receiver for data, or errors
  1400. ;
  1401.     mov    dx,MIDISTATUS
  1402.     xor    dx,[_MVTranslateCode]        ; translate the address
  1403.     in    al,dx
  1404.     mov    ah,al                ; save a copy for xmitter
  1405.  
  1406.     and    al,bMSRframeerr+bMSRififoovr+bMSRofifoovr ; overrun or frame error?
  1407.     jz    mvmidi_int            ; nope
  1408.     out    dx,al                ; clear errors
  1409.  
  1410.     mov    dx,MIDICONTROL
  1411.     xor    dx,[_MVTranslateCode]        ; translate the address
  1412.  
  1413.     in    al,dx
  1414.     or    al,bMCRrstfifoi+bMCRrstfifoo    ; reset FIFO in ptr
  1415.         out     dx,al
  1416.     or    al,NOT(bMCRrstfifoi+bMCRrstfifoo)
  1417.     out    dx,al
  1418. ;
  1419. mvmidi_int:
  1420. ;
  1421. ; get the status once again for the second chance loop
  1422. ;
  1423.         mov     dx,MIDISTATUS
  1424.     xor    dx,[_MVTranslateCode]    ; translate the address
  1425.     in    al,dx
  1426. ;
  1427. ; Only process the interrupt process wanted by the user
  1428. ;
  1429.     test    [ProcessControl],INTINPUT ; interrupt driven input?
  1430.     jz    checktrans        ; no, go check for int driven xmit
  1431.  
  1432.     test    al,bMSRififo        ; any data in input FIFO?
  1433.     jz    checktrans        ; no, go check the transmitter
  1434.  
  1435.     .errnz    MIDIFIFOS-MIDISTATUS-1
  1436.  
  1437.     inc    dx            ; move to the status register
  1438.  
  1439.     in    al,dx
  1440.     mov    cl,al
  1441.     and    cx,bMFCififo        ; get # of bytes in FIFO
  1442.     jnz    @F
  1443.     mov    cx,16
  1444.     ;
  1445.     @@:
  1446.     mov    dx,MIDIDATA        ; move to the data register
  1447.     xor    dx,[_MVTranslateCode]    ; translate the address
  1448.     mov    bx,[lpiMIQueue]     ; get  the input queue pointer
  1449. ;
  1450. mvrxloop:
  1451. ;
  1452. ; read the data off the receiver
  1453. ;
  1454.     in    al,dx            ; fetch the received byte
  1455. ;
  1456. ; MIDI spec requires transmitter send something every 300 msec
  1457. ; Active Sense (FE) is the standard "nothing for you" byte
  1458. ;
  1459.     test    [_MidiInFilter],MF_ACTSENSE ; filter out active sense
  1460.     jz    @F            ; no, keep it...
  1461.     cmp    al, 0FEh        ; Active Sense?
  1462.     je    rxCont            ; ..ignore it
  1463.     ;
  1464.     @@:
  1465.     cmp    [MIDIiQueueCnt],MAXQUEUE; is it full?
  1466.     jle    @F            ; no, save it
  1467.     inc    [_overflow]        ; yes, list it as an error
  1468.     jmp    short mvrxloop
  1469.     ;
  1470.     @@:
  1471.     mov    [bx],al
  1472.     inc    bx
  1473.     inc    [MIDIiQueueCnt]     ; one more in...
  1474.     cmp    bx,offset iCircularQueue+MAXQUEUE
  1475.     jb    rxCont
  1476.     mov    bx,offset iCircularQueue
  1477.     ;
  1478.     rxCont:
  1479.     loop    mvrxloop        ; do all bytes listed in the queue
  1480.     mov    [lpiMIQueue],bx     ; save the input queue pointer
  1481.     jmp    second_check        ; make sure FIFO is empty
  1482. ;
  1483. checktrans:
  1484. ;
  1485. ; If we are using interrupt driven output, load the FIFO now...
  1486. ;
  1487.     test    [ProcessControl],INTOUTPUT; interrupt driven output?
  1488.     jz    second_check          ; no, just exit out
  1489.  
  1490.     ; reset the interrupt now.
  1491.  
  1492.         mov     dx,MIDISTATUS
  1493.     xor    dx,[_MVTranslateCode]    ; translate the address
  1494.     mov    al,bMSRofifo        ; any data in output FIFO?
  1495.     out    dx,al
  1496.  
  1497.         ; check for any outgoing data
  1498.  
  1499.     cmp    [MIDIoQueueCnt],0    ; any queued up data?
  1500.     jz    second_check        ; no, just exit out
  1501.  
  1502.     mov    dx,MIDIFIFOS
  1503.     xor    dx,[_MVTranslateCode]    ; translate the address
  1504.  
  1505.         in      al,dx
  1506.     and    ax,bMFCofifo        ; get # of outgoing bytes
  1507.     mov    cl,4
  1508.     shr    al,cl            ; right hand justify the number
  1509.     xchg    ax,cx
  1510.     cmp    cl,1            ; down to 1 byte free?
  1511.     je    second_check        ; yes, can't load it
  1512.     ja    @F            ; we have 15 or less entries
  1513.     mov    cx,16            ; 16 entires fit, but...
  1514.     ;
  1515.     @@:
  1516.     dec    cx            ; we only load 15...
  1517.     mov    dx,MIDIDATA        ; move to the data register
  1518.     xor    dx,[_MVTranslateCode]    ; translate the address
  1519.     mov    bx,[lpoMOQueue]     ; get  the input queue pointer
  1520.     ;
  1521.     txLoop:
  1522.     mov    al,[bx]         ; pass the next byte
  1523.     out    dx,al
  1524.  
  1525.     inc    bx            ; move the pointer
  1526.     cmp    bx,offset oCircularQueue+MAXQUEUE
  1527.     jb    @F
  1528.     mov    bx,offset oCircularQueue; it wrapped...
  1529.     ;
  1530.     @@:
  1531.     dec    [MIDIoQueueCnt]     ; any queued up data?
  1532.     loopnz    txLoop
  1533.     mov    [lpoMOQueue],bx
  1534. ;
  1535. ; all done with input and output processing. Check for more interrupts
  1536. ;
  1537. second_check:
  1538. ;
  1539. ; in case we received more MIDI data during this routine, check again...
  1540. ;
  1541.         mov     dx,INTRCTLRST
  1542.     xor    dx,[_MVTranslateCode]    ; translate the address
  1543.  
  1544.     in    al,dx            ; get the interrupt status
  1545.     test    al,bISmidi        ; is the interrupt still active?
  1546.     jjnz    mvmidi_int        ; yes, go process it...
  1547. ;
  1548. midiint_done:
  1549.     mov    al,EOI            ; acknowledge the interrupt.
  1550.     cmp    [_IRQNumb],7
  1551.     jbe    @F
  1552.     out    IRQ2ACKREG, al        ; ack the 2nd IRQ controller
  1553.     ;
  1554.     @@:
  1555.     out    IRQ1ACKREG, al        ; ack the 1st IRQ controller
  1556.  
  1557.     ToggleMV101mask         ; make sure the line stays active
  1558. ;
  1559. busy_exit:
  1560.         pop     dx
  1561.     pop    cx
  1562.     pop    bx
  1563.         pop     ax
  1564.     pop    ds
  1565.         iret
  1566.  
  1567. MV101_ISR    endp
  1568.  
  1569. ;
  1570. ;   /*\
  1571. ;---|*|----====< Yamaha_ISR >====----
  1572. ;---|*|
  1573. ;---|*| ISR service routine for the Yamaha 3802 interrupts.
  1574. ;---|*|
  1575. ;   \*/
  1576. ;
  1577. Yamaha_ISR    proc    far
  1578.     push    ds            ; minimal save
  1579.     push    dx
  1580.     push    ax
  1581.  
  1582.     mov    ax, @data        ; establish our DS
  1583.     mov    ds, ax
  1584.  
  1585.     mov    dx, INTRCTLRST
  1586.     in    al, dx            ; acknowledge interrupt
  1587.     test    al, bICmidi        ; our MIDI interrupt?
  1588.     jnz    isourint        ; yes, go do it...
  1589.  
  1590.     pushf
  1591.     call    dword ptr cs:[OldISR]    ; perform the old interrupt
  1592.     jmp    WOOPS_exit
  1593. ;
  1594. isourint:
  1595. ;
  1596. ; we can now process all MIDI interrupts here
  1597. ;
  1598.     push    es
  1599.     push    di
  1600.         cld                             ; fatal to assume
  1601. ;
  1602. ; We will only process interrupt generated input if ProcessControl says so.
  1603. ;
  1604.     test    [ProcessControl],INTINPUT ; Int input?
  1605.     jz    emptyRX           ; polled, check each h/w
  1606. ;
  1607. ; Check for Rx IRQ (means FIFO-Rx went non-empty) empty the FIFO
  1608. ;
  1609.     mov    dx, MDSYSSTAT        ; IRQ Status
  1610.     in    al, dx
  1611.     and    al, RxIRQ        ; FIFO-RX non-empty?
  1612.     jz    emptyRX         ; ..jump if not
  1613.  
  1614.     .errnz    MDIRQCLR-MDSYSSTAT-1
  1615.  
  1616.     inc    dx
  1617.         out     dx,al                   ; flush it...
  1618. ;
  1619. ; get the input queue & load'er up!
  1620. ;
  1621.         mov     ax,ds
  1622.     mov    es,ax
  1623.     mov    di,lpiMIQueue        ; get the input to the queue
  1624.    ;
  1625.    rxISR_05:
  1626.     mov    al, 3            ; 3x
  1627.     mov    dx, MDSYSCTLR
  1628.     out    dx, al
  1629.  
  1630.         mov     dx, MDGROUP4            ; 34 = FIFO-Rx status
  1631.     in    al, dx
  1632.     test    al, RxRDY        ; RxRDY bit?
  1633.     jz    rxISR_10        ; ..jump if FIFO empty
  1634.  
  1635.     mov    dx, MDGROUP6        ; 36 = FIFO-Rx data
  1636.     in    al, dx            ; fetch datum
  1637. ;
  1638. ; Eliminate some overhead! The    MIDI spec requires transmitter send something
  1639. ; every 300 msec. Active Sense (FE) is the standard "nothing for you" byte
  1640. ;
  1641.     test    [_MidiInFilter],MF_ACTSENSE ; filter out active sense
  1642.     jz    @F                ; no, keep it...
  1643.     cmp    al, ACTV_SENSE            ; Active Sense?
  1644.     je    rxISR_05            ; ..ignore it
  1645.     ;
  1646.     @@:
  1647.     cmp    [MIDIiQueueCnt],MAXQUEUE; is it full?
  1648.     jle    @F            ; no, save it
  1649.     inc    _overflow
  1650.         jmp     short rxISR_05
  1651.     ;
  1652.     @@:
  1653.         stosb
  1654.     inc    [MIDIiQueueCnt]     ; one more in...
  1655.     cmp    di,offset iCircularQueue+MAXQUEUE
  1656.     jb    rxISR_05
  1657.     mov    di,offset iCircularQueue
  1658.  
  1659.     jmp    rxISR_05
  1660.    ;
  1661.    rxISR_10:
  1662.     mov    [lpiMIQueue],di     ; get the input to the queue
  1663. ;
  1664. emptyRX:
  1665. ;
  1666. ; Check for Transmitter Empyt IRQ here
  1667. ;
  1668.     test    [ProcessControl],INTOUTPUT ; Int output?
  1669.     jz    endMIDIint           ; no, exit out...
  1670.  
  1671.         mov     dx, MDSYSSTAT           ; IRQ Status
  1672.     in    al, dx
  1673.     and    al, TxIRQ        ; FIFO-Tx became empty?
  1674.     jz    endMIDIint        ; ..jump if not
  1675.  
  1676.         .errnz  MDIRQCLR-MDSYSSTAT-1
  1677.  
  1678.     inc    dx
  1679.         out     dx,al                   ; flush it...
  1680. ;
  1681. ; output any data till done.
  1682. ;
  1683.     cmp    [MIDIoQueueCnt],0    ; any data in the queue?
  1684.     jz    endMIDIint        ; ..jump if not
  1685.  
  1686.         mov     di,lpoMOQueue           ; get the pointer to the queue
  1687.     mov    dx, MDSYSCTLR        ; index to Xmitter
  1688.     mov    al,5
  1689.     out    dx,al
  1690. ;
  1691. ytxLoop:
  1692.     mov    dx, MDGROUP4        ; 54 = FIFO-Tx status
  1693.     in    al, dx
  1694.     test    al, TxRDY        ; TxRDY bit?
  1695.     jz    ytxDone         ; ..jump if FIFO full
  1696.  
  1697.     mov    dx, MDGROUP6        ; 56 = FIFO-Tx data
  1698.     mov    al, [di]
  1699.         out     dx, al                  ; ship datum
  1700.  
  1701.     inc    di            ; move the pointer
  1702.     cmp    di,offset oCircularQueue+MAXQUEUE
  1703.     jb    @F
  1704.     mov    di,offset oCircularQueue; it wrapped...
  1705.     ;
  1706.     @@:
  1707.     dec    [MIDIoQueueCnt]     ; any queued up data?
  1708.     jnz    ytxLoop         ; do as much as possible
  1709. ;
  1710. ytxDone:
  1711.     mov    [lpoMOQueue],di     ; save the ending pointer
  1712. ;
  1713. endMIDIint:
  1714. ;
  1715. ; all int handling is done now, so restore the state & exit home...
  1716. ;
  1717.         pop     di
  1718.     pop    es
  1719.  
  1720.         mov     al, [MDctrl]
  1721.         mov     dx, MDSYSCTLR
  1722.         out     dx, al                  ; restore incoming state
  1723. ;
  1724. WOOPS_reenter:
  1725. ;
  1726. ; flush the data ready IRQ
  1727. ;
  1728.     mov    al,EOI            ; acknowledge at the system level
  1729.     cmp    _IRQNumb,7
  1730.     jbe    @F
  1731.     out    IRQ2ACKREG, al        ; ack the 2nd IRQ controller
  1732.     ;
  1733.     @@:
  1734.     out    IRQ1ACKREG, al        ; ack the 1st IRQ controller
  1735.  
  1736.     ToggleMV101mask         ; make sure the MV101 can generate ints
  1737. ;
  1738. WOOPS_exit:
  1739.         pop     ax
  1740.         pop     dx
  1741.         pop     ds
  1742.     iret
  1743.  
  1744. Yamaha_ISR    endp
  1745.  
  1746. ;   /*\
  1747. ;---|*| end of MIDIA.ASM
  1748. ;   \*/
  1749.  
  1750.     end
  1751.  
  1752.