home *** CD-ROM | disk | FTP | other *** search
/ Audio 4.94 - Over 11,000 Files / audio-11000.iso / msdos / sndbords / proaudio / pas_sdk1 / pas / subs / mvsound / mvsound.asm < prev    next >
Assembly Source File  |  1992-09-24  |  51KB  |  2,085 lines

  1. ;$Author:   DCODY  $
  2. ;$Date:   24 Sep 1992 08:54:22  $
  3. ;$Header:   X:/sccs/mvsound/mvsound.asv   1.6   24 Sep 1992 08:54:22   DCODY  $
  4. ;$Log:   X:/sccs/mvsound/mvsound.asv  $
  5. ;  
  6. ;     Rev 1.6   24 Sep 1992 08:54:22   DCODY
  7. ;  changed MVGetHardware to mvGetHardware
  8. ;  
  9. ;     Rev 1.5   12 Aug 1992 17:13:18   DCODY
  10. ;  made call to mvgethardware use a zero (0) parameter to use the current base.
  11. ;  
  12. ;     Rev 1.4   17 Jul 1992 14:18:22   DCODY
  13. ;  moved TheDMAchannel and TheIRQchannel out to another module. Made the
  14. ;  hardware I/O relocatable. Made initmvsound recallable without ill effects.
  15. ;  
  16. ;     Rev 1.3   09 Jul 1992 10:07:50   DCODY
  17. ;  corrected MV101 bit test and jumps
  18. ;  
  19. ;     Rev 1.2   26 Jun 1992 14:13:48   DCODY
  20. ;  added the parameter to GetHWVersion call
  21. ;  
  22. ;     Rev 1.1   23 Jun 1992 17:06:04   DCODY
  23. ;  PAS2 update
  24. ;  
  25. ;     Rev 1.0   15 Jun 1992 09:43:46   BCRANE
  26. ;  Initial revision.
  27. ;$Logfile:   X:/sccs/mvsound/mvsound.asv  $
  28. ;$Modtimes$
  29. ;$Revision:   1.6  $
  30. ;$Workfile:   mvsound.asm  $ 
  31.  
  32.         page    64,131
  33.     Title    MVSOUND  --  Pro Audio Spectrum Sound Support Code
  34.  
  35. ;   /*\
  36. ;---|*|----====< MVSOUND >====----
  37. ;---|*|
  38. ;---|*|  This module contains the code for supporting PCM I/O.
  39. ;---|*|
  40. ;---|*|  Media Vision, Inc. Copyright (c) 1991,1992. All Rights Reserved.
  41. ;---|*|
  42. ;   \*/
  43.  
  44. ;
  45. ; The following set of equates are used to control what routines are compiled
  46. ; by doing this, MVSOUND.ASM can contain all the necessary code in one file,
  47. ; but generate separate, linkable objects with just the necessary code.
  48. ;
  49. ALLOBJS     = 0     ; individual objects are being built
  50. DATAOBJ     = 0     ; data code to be compiled
  51. MISC1OBJ    = 0     ; minimum code needed from the library
  52. MISC2OBJ    = 0     ; other miscellaneous code
  53. PCMOBJ        = 0     ; PCM code to be compiled
  54.  
  55. ifdef BUILDDATA
  56.   DATAOBJ   = 1     ; data code to be compiled
  57. endif
  58.  
  59. ifdef BUILDMISC1
  60.   MISC1OBJ  = 1     ; misc module #1 code to be compiled
  61. endif
  62.  
  63. ifdef BUILDMISC2
  64.   MISC2OBJ  = 1     ; misc module #2 code to be compiled
  65. endif
  66.  
  67. ifdef BUILDPCM
  68.   PCMOBJ    = 1     ; data code to be compiled
  69. endif
  70.  
  71. ifdef BUILDALL
  72.   ALLOBJS   = 1     ; all objects are being built
  73.   DATAOBJ   = 1     ; data code to be compiled
  74.   MISC1OBJ  = 1     ; miscellaneous code to be compiled
  75.   MISC2OBJ  = 1     ; miscellaneous code to be compiled
  76.   PCMOBJ    = 1     ; PCM code to be compiled
  77. endif
  78.  
  79.     .xlist
  80.     include model.inc
  81.         include masm.inc
  82.     include target.inc
  83.     include state.inc
  84.     include common.inc
  85.     .list
  86.  
  87. ;
  88. ; structure for pointing to the above table of DMA addresses
  89. ;
  90.  
  91. dmaaddr struc
  92. _dmach        db    ?    ; DMA channel selected
  93. _dmardstat      db      ?       ; DMA read status
  94. _dmawrcntrl    db    ?    ; DMA write command register
  95. _dmawreq    db    ?    ; DMA write request register
  96. _dmawrsmr    db    ?    ; DMA write single mask register
  97. _dmawrmode    db    ?    ; DMA write mode register
  98. _dmaclear    db    ?    ; DMA clear low/high flip-flop
  99. _dmardtemp    db    ?    ; DMA read temp register
  100. _dmawrclr    db    ?    ; DMA write master clear
  101. _dmaclrmsk    db    ?    ; DMA clear mask register
  102. _dmawrall    db    ?    ; DMA write all mask register bits
  103. dmaaddr ends
  104.  
  105. ;
  106. ;---------------------------========================---------------------------
  107. ;---------------------------====< DATA SECTION >====---------------------------
  108. ;---------------------------========================---------------------------
  109. ;
  110. if MODELSIZE eq 0
  111.     .code
  112. else
  113.     .data
  114. endif
  115.  
  116. if DATAOBJ                              ; include if we are building DATA.OBJ
  117.  
  118. ;
  119. ; These variables are DMA/Buffer control variables
  120. ;
  121. TheIRQMask    db    INT7MSK     ; 8259 interrupt mask
  122.  
  123. TheDMAMode    db    00h        ; 44h for input, 48h for output
  124. LinearPtr    dd    0        ; holds linear address
  125. SegmentedPtr    dd    0        ; holds segmented address (real mode)
  126. DMABuffLength    dw    0        ; DMA Length (0 based) (MUST BE EVEN!)
  127. DMABuffDivides    db    0        ; # of splits in the DMA buffer
  128.  
  129. TheSampleRate    dd    0        ; 3k through 88k
  130. StereoMono    db    0        ; ff for mono, 00 for stereo
  131. PCMDirection    db    0        ; bit mask for the DMA controller
  132. SampleSize    db    0        ; sample size: 0=8,1=12,2=16
  133.  
  134.     public    DMAAutoInit        ; TRUE(0ffh) or FALSE(000h)
  135. DMAAutoInit    db    0ffh        ; to allow auto-init on DMA access
  136.  
  137. UserRoutine     dd      0               ; User Code
  138.  
  139. StatusWord      dw      0               ; Holds current status:
  140. ;                    ;   0 = inactive, available
  141. ;                    ;   1 = currently playing
  142. ;                    ;   2 = currently recording
  143.  
  144. OldIRQRoutine   dd      0               ; holds the original routine
  145.  
  146. polledmask    equ    bICsamprate+bICsampbuff ; polled mask
  147. dmamask     equ    bICsampbuff        ; dma mask
  148.  
  149. DMAOUTPUT    equ    0+dmamask    ; DMA is used to drive the output
  150. POLLEDOUTPUT    equ    0+polledmask    ; Polling routine drives output
  151. DMAINPUT    equ    1+dmamask    ; DMA is used to read input
  152. POLLEDINPUT    equ    1+polledmask    ; Polling routine reads input
  153. TypeOfSetup    db    0        ; polled/dma interrupt masks & stuff..
  154.  
  155.     public    NumberOfInterrupts
  156. NumberOfInterrupts      dw      0       ; number of interrupts that have occured
  157. ;
  158. ; These variables direct our code to the proper DMA channel
  159. ;
  160. OurDMAPageReg    dw    CH1PAGEREG    ; default to DMA channel 1 page reg
  161. OurDMAddress    dw    DMAC1ADDR    ; default to DMA channel 1 address reg
  162.  
  163. ;
  164. ; table of address pointers to the various DMA 2 addresses
  165. ;
  166.         public  DMA1AddrTable
  167. DMA1AddrTable    label    byte
  168.     db    DEFAULTDMA    ; DMA channel selected
  169.         db      DMARDSTAT       ; DMA read status
  170.     db    DMAWRCNTRL    ; DMA write command register
  171.     db    DMAWREQ     ; DMA write request register
  172.     db    DMAWRSMR    ; DMA write single mask register
  173.     db    DMAWRMODE    ; DMA write mode register
  174.     db    DMACLEAR    ; DMA clear low/high flip-flop
  175.     db    DMARDTEMP    ; DMA read temp register
  176.     db    DMAWRCLR    ; DMA write master clear
  177.     db    DMACLRMSK    ; DMA clear mask register
  178.     db    DMAWRALL    ; DMA write all mask register bits
  179. ;
  180. ; table of address pointers to the various DMA 2 addresses
  181. ;
  182.     public    DMA2AddrTable
  183. DMA2AddrTable   label   byte
  184.         db      DEFAULTDMA      ; DMA channel selected
  185.     db    DMA2RDSTAT    ; DMA read status
  186.     db    DMA2WRCNTRL    ; DMA write command register
  187.     db    DMA2WREQ    ; DMA write request register
  188.     db    DMA2WRSMR    ; DMA write single mask register
  189.     db    DMA2WRMODE    ; DMA write mode register
  190.     db    DMA2CLEAR    ; DMA clear low/high flip-flop
  191.     db    DMA2RDTEMP    ; DMA read temp register
  192.     db    DMA2WRCLR    ; DMA write master clear
  193.     db    DMA2CLRMSK    ; DMA clear mask register
  194.     db    DMA2WRALL    ; DMA write all mask register bits
  195.  
  196.     public    DMAPointer
  197. DMAPointer      dw      offset DMA1AddrTable    ; default to channel 1 table
  198. ;
  199. ; working variables
  200. ;
  201. ;
  202.     public    TheIRQMask        ; 8259 interrupt mask
  203.     public    TheDMAMode        ; 55h for input, 59h for output
  204.     public    LinearPtr        ; holds linear address
  205.     public    SegmentedPtr        ; holds segmented address (real mode)
  206.     public    DMABuffLength        ; DMA Length (0 based) (MUST BE EVEN!)
  207.     public    DMABuffDivides        ; # of splits in the DMA buffer
  208.     public    TheSampleRate        ; 3k through 88k
  209.     public    StereoMono        ; ff for mono, 00 for stereo
  210.     public    PCMDirection        ; bit mask for the DMA controller
  211.     public    SampleSize        ; sample size: 0=8,1=12,2=16
  212.     public    DMAAutoInit        ; TRUE/FALSE flag for DMA autoinit bit
  213.     public    UserRoutine        ; User Code
  214.     public    StatusWord        ; Holds current status:
  215.     public    OldIRQRoutine        ; holds the original routine
  216. polledmask    equ    bICsamprate+bICsampbuff ; polled mask
  217. dmamask     equ    bICsampbuff        ; dma mask
  218. DMAOUTPUT    equ    0+dmamask    ; DMA is used to drive the output
  219. POLLEDOUTPUT    equ    0+polledmask    ; Polling routine drives output
  220. DMAINPUT    equ    1+dmamask    ; DMA is used to read input
  221. POLLEDINPUT    equ    1+polledmask    ; Polling routine reads input
  222.     public    TypeOfSetup        ; polled/dma interrupt masks & stuff..
  223.     public    NumberOfInterrupts    ; number of interrupts that have occured
  224.     public    OurDMAPageReg        ; default to DMA channel 1 page reg
  225.     public    OurDMAddress        ; default to DMA channel 1 address reg
  226.  
  227. else    ; not building DATA.OBJ, declare all publics
  228.  
  229.     extrn    DMAPointer    :word    ; pointer to the DMA address table
  230.     extrn    DMA1AddrTable    :byte    ; 1st DMA controller table
  231.     extrn    DMA2AddrTable    :byte    ; 2nd DMA controller table
  232.     extrn    TheIRQMask    :byte    ; 8259 interrupt mask
  233.     extrn    TheDMAMode    :byte    ; 55h for input, 59h for output
  234.     extrn    LinearPtr    :dword    ; holds linear address
  235.     extrn    SegmentedPtr    :dword    ; holds segmented address (real mode)
  236.     extrn    DMABuffLength    :word    ; DMA Length (0 based) (MUST BE EVEN!)
  237.     extrn    DMABuffDivides    :byte    ; # of splits in the DMA buffer
  238.     extrn    TheSampleRate    :dword    ; 3k through 88k
  239.     extrn    StereoMono    :byte    ; ff for mono, 00 for stereo
  240.     extrn    PCMDirection    :byte    ; bit mask for the DMA controller
  241.     extrn    SampleSize    :byte    ; sample size: 0=8,1=12,2=16
  242.     extrn    DMAAutoInit    :byte    ; TRUE/FALSE flag for DMA autoinit bit
  243.     extrn    UserRoutine    :dword    ; User Code
  244.     extrn    StatusWord    :word    ; Holds current status:
  245.     extrn    OldIRQRoutine    :dword    ; holds the original routine
  246.     extrn    TypeOfSetup    :byte    ; polled/dma interrupt masks & stuff..
  247.     extrn    NumberOfInterrupts:word ; number of interrupts that have occured
  248.     extrn    OurDMAPageReg    :word    ; default to DMA channel 1 page reg
  249.     extrn    OurDMAddress    :word    ; default to DMA channel 1 address reg
  250.  
  251.  
  252. polledmask    equ    bICsamprate+bICsampbuff ; polled mask
  253. dmamask     equ    bICsampbuff        ; dma mask
  254. DMAOUTPUT    equ    0+dmamask    ; DMA is used to drive the output
  255. POLLEDOUTPUT    equ    0+polledmask    ; Polling routine drives output
  256. DMAINPUT    equ    1+dmamask    ; DMA is used to read input
  257. POLLEDINPUT    equ    1+polledmask    ; Polling routine reads input
  258. SHADOWTABLELEN  equ     28              ; 28 entries in the shadow data table
  259.  
  260. endif
  261.  
  262.     extrn    TheDMAChannel      :byte ; defaults to channel 1
  263.     extrn    TheIRQChannel      :byte ; defaults to IRQ 7
  264.  
  265.         extrn   mvhwShadowPointer :dword; a common variable for all
  266.     extrn    _MVHWVersionBits  :word ; hardware state bits
  267.     extrn    _MVTranslateCode   :word
  268.  
  269.     .code
  270.  
  271.     externADDR    MVInitStatePtr        ; pointer to the state table init code
  272.     externADDR    mvGetHWVersion        ; returns the hardware bits
  273. ;
  274. ; TEXT SEGMENT externals for the different modules
  275. ;
  276.  
  277. if PCMOBJ AND (NOT ALLOBJS)        ; added for independent PCMOBJ module
  278.     externADDR    SelectIRQ        ; PCM uses "SelectIRQ"
  279.     externADDR    _unloadirqvector    ; PCM uses "_unloadirqvector"
  280.     externADDR    _getirqoffset        ; PCM uses "_getirqoffset"
  281. endif
  282.  
  283. ;
  284. ;---------------------------========================---------------------------
  285. ;---------------------------====< CODE SECTION >====---------------------------
  286. ;---------------------------========================---------------------------
  287. ;
  288. ;   /*\
  289. ;---|*|
  290. ;---|*|---------------====< Prototypes >====---------------
  291. ;---|*|
  292. ;---|*| void far *DMABuffer(char far *, int, int )
  293. ;---|*|
  294. ;---|*|     Passes in a pointer and length to the buffer.
  295. ;---|*|     Also flushes the buffer. Returns 0 or true DMA buffer ptr.
  296. ;---|*|
  297. ;---|*| int EnablePCMPlay()
  298. ;---|*|
  299. ;---|*|     Sets up the PCM hardware for polled output
  300. ;---|*|
  301. ;---|*| int EnablePCMRecord()
  302. ;---|*|
  303. ;---|*|     Sets up the PCM hardware for polled input
  304. ;---|*|
  305. ;---|*| char huge *FindDMABuffer(char huge *, int )
  306. ;---|*|
  307. ;---|*|     Takes a memory address & return the next 64k boundary
  308. ;---|*|
  309. ;---|*| MVState far *InitMVSound()
  310. ;---|*|
  311. ;---|*|     Initializes the int 2F interface & some global variables.
  312. ;---|*|
  313. ;---|*| int InitPCM()
  314. ;---|*|
  315. ;---|*|     Initializes the PCM code.
  316. ;---|*|
  317. ;---|*| void PausePCM()
  318. ;---|*|
  319. ;---|*|     Temporarily stops the PCM I/O by disabling the timers
  320. ;---|*|
  321. ;---|*| int PCMInfo( long ,int, int, int )
  322. ;---|*|
  323. ;---|*|     Sets up the transfer rate & stereo/mono/compression/data size
  324. ;---|*|
  325. ;---|*| int PCMPlay()
  326. ;---|*|
  327. ;---|*|     Starts the DMA feeding the DAC
  328. ;---|*|
  329. ;---|*| int PCMRecord()
  330. ;---|*|
  331. ;---|*|     Starts the DMA reading the ADC
  332. ;---|*|
  333. ;---|*| void RemovePCM()
  334. ;---|*|
  335. ;---|*|     kills the PCM code.
  336. ;---|*|
  337. ;---|*| void ResumePCM()
  338. ;---|*|
  339. ;---|*|     Restarts the PCM I/O by enabling the timers
  340. ;---|*|
  341. ;---|*| int SelectDMA( int )
  342. ;---|*|
  343. ;---|*|     Selects the DMA channel 1, or 3
  344. ;---|*|
  345. ;---|*| int SelectIRQ( int )
  346. ;---|*|
  347. ;---|*|     Selects the IRQ line for DMA control
  348. ;---|*|
  349. ;---|*| void StopPCM()
  350. ;---|*|
  351. ;---|*|     Turn off the PCM timers, interrupts, and state machine.
  352. ;---|*|
  353. ;---|*| void UserFunc((*long)())
  354. ;---|*|
  355. ;---|*|     Call back routine when Half way buffer is full/empty.
  356. ;---|*|
  357. ;   \*/
  358.  
  359. if PCMOBJ
  360.  
  361. ;   /*\
  362. ;---|*|------====< void far * DMABuffer( char far *, int, int ) >====------
  363. ;---|*|
  364. ;---|*| Passes in a pointer and length to the buffer
  365. ;---|*|
  366. ;---|*| Entry Conditions:
  367. ;---|*|     dParm1 points to DMA buffer
  368. ;---|*|     wParm3 points to the length (wParm3 * 1024 is the total length )
  369. ;---|*|     wParm4 is the # of divisions of the DMA buffer
  370. ;---|*|
  371. ;---|*| Exit Conditions:
  372. ;---|*|     DX:AX = 0 - bad buffer
  373. ;---|*|     DX:AX = returns buffer pointer
  374. ;---|*|
  375. ;   \*/
  376.  
  377.     public    DMABuffer
  378. DMABuffer    proc
  379.         push    bp
  380.     mov    bp,sp
  381.     push    es
  382.     push    di
  383.  
  384.     mov    cx,wParm3        ; get the dma size (4/8/16/32/64)
  385.     cmp    cx,64            ; too high?
  386.     ja    dmabbad         ; yes, bomb out
  387.  
  388.         mov     ax,1024
  389.     cwd
  390.     mul    cx            ; get the length - 1
  391.     dec    ax
  392.     mov    [DMABuffLength],ax    ; and save for later use
  393.  
  394.     les    di,dParm1        ; get the far pointer to the buffer
  395.  
  396.         mov     ax,di
  397.     mov    bx,es            ; convert it to a linear address
  398.     mov    dx,es
  399.     mov    cl,4
  400.     rol    dx,cl
  401.     and    dx,000fh
  402.     shl    bx,cl            ; add offset portion of seg to offset
  403.     add    ax,bx
  404.     jc    dmabbad         ; bad if extends over a 64k boundary
  405.  
  406.     mov    wptr [LinearPtr+0],ax    ; save the linear address
  407.     mov    wptr [LinearPtr+2],dx
  408.     mov    wptr [SegmentedPtr+0],di
  409.     mov    wptr [SegmentedPtr+2],es
  410.  
  411.     mov    bx,wParm4        ; get the # of DMA buffer divisions
  412.     mov    [DMABuffDivides],bl
  413.  
  414.     push    ax            ; save the buffer offset
  415.  
  416.     mov    cx,[DMABuffLength]    ; get the clearing length
  417.         mov     al,80h                  ; PCM silent code
  418.     cld
  419.     rep stosb            ; flush the buffer length...
  420.     stosb                ; + 1
  421.  
  422.     mov    dx,es
  423.         pop     ax                      ; return dx:ax
  424.     jmp    short dmabdone
  425. ;
  426. dmabbad:
  427.     sub    ax,ax
  428.     cwd
  429. ;
  430. dmabdone:
  431.         pop     di
  432.     pop    es
  433.     pop    bp
  434.     ret
  435.  
  436. DMABuffer    endp
  437.  
  438.  
  439. ;   /*\
  440. ;---|*|---------------====< EnablePCMPlay() >====---------------
  441. ;---|*|
  442. ;---|*| Enabled the DAC hardware for polled output (no interrupts)
  443. ;---|*|
  444. ;---|*| Entry Conditions:
  445. ;---|*|     None
  446. ;---|*|
  447. ;---|*| Exit Conditions:
  448. ;---|*|     AX =  0 good start
  449. ;---|*|     AX = -1 not started, problem occured
  450. ;   \*/
  451.  
  452.     public    EnablePCMPlay
  453. EnablePCMPlay    proc
  454.     push    es
  455.  
  456.     mov    ax,wptr [TheSampleRate+0] ; Validate the sample rate
  457.     or    ax,wptr [TheSampleRate+2]
  458.     jz    enaPCMPlay_bad          ; zero sample rate, bomb out...
  459.  
  460.     call    FFAR ptr EnablePlaying      ; go for it...
  461.     mov    ax,0
  462.     jmp    short enaPCMPlay_exit
  463. ;
  464. enaPCMPlay_bad:
  465.     mov    ax,-1
  466. ;
  467. enaPCMPlay_exit:
  468.     pop    es
  469.         ret
  470.  
  471. EnablePCMPlay    endp
  472.  
  473.  
  474. ;   /*\
  475. ;---|*|---------------====< EnablePCMRecord() >====---------------
  476. ;---|*|
  477. ;---|*| Enabled the ADC hardware for polled input (no interrupts)
  478. ;---|*|
  479. ;---|*| Entry Conditions:
  480. ;---|*|     None
  481. ;---|*|
  482. ;---|*| Exit Conditions:
  483. ;---|*|     AX =  0 recording has started
  484. ;---|*|     AX = -1 recording did not start
  485. ;---|*|
  486. ;   \*/
  487.  
  488.     public    EnablePCMRecord
  489. EnablePCMRecord proc
  490.         push    es
  491.  
  492.     mov    ax,wptr [TheSampleRate+0] ; Validate the sample rate
  493.     or    ax,wptr [TheSampleRate+2]
  494.     jz    enaPCMRec_bad
  495.  
  496.     call    FFAR ptr EnableRecording  ; go for it...
  497.     mov    ax,0
  498.     jmp    short enaPCMRec_exit
  499. ;
  500. enaPCMRec_bad:
  501.     mov    ax,-1
  502. ;
  503. enaPCMRec_exit:
  504.     pop    es
  505.         ret
  506.  
  507. EnablePCMRecord endp
  508.  
  509.  
  510. ;   /*\
  511. ;---|*|------====< char far *FindDMABuffer(char far *,int ) >====------
  512. ;---|*|
  513. ;---|*| Finds the next 64k boundary starting with dParm1 address
  514. ;---|*|
  515. ;---|*| Entry Conditions:
  516. ;---|*|     dParm1 points to a buffer twice the size needed for the DMA
  517. ;---|*|     wParm2 is the size of the DMA buffer (4/8/16/32/64)
  518. ;---|*|
  519. ;---|*| Exit Conditions:
  520. ;---|*|     DX:AX = returns buffer pointer on a 64k boundary
  521. ;---|*|     DX:AX = 0 if boundary wraps beyond 1 meg.
  522. ;---|*|
  523. ;   \*/
  524.  
  525.     public    FindDMABuffer
  526. FindDMABuffer    proc
  527.     push    bp
  528.     mov    bp,sp
  529.  
  530.     sub    ax,ax            ; default to bad...
  531.     cwd
  532.  
  533.         mov     cx,wParm3               ; get the length
  534.     cmp    cx,64            ; 64k buffer requested?
  535.     ja    fdb_exit        ; too high, exit
  536.     jz    fdb_64k         ; yes, special case it...
  537.     cmp    cl,4
  538.     jb    fdb_exit        ; too low, exit
  539.  
  540.     mov    ax,1024         ; calculate the length of the DMA buffer
  541.     mul    cx
  542.     mov    bx,ax            ; bx holds the length
  543.  
  544.     mov    dx,wptr dParm1+2
  545.     mov    ax,dx            ; accumulate the offset in ax
  546.     and    ax,0fffh        ; get the offset portion of the segment
  547.     and    dx,0f000h        ; make DX a 64k segment register
  548.         mov     cl,4
  549.     shl    ax,cl            ; make the segment an offset
  550.     add    ax,wptr dParm1+0    ; accumulate the rest of the offset
  551.     add    bx,ax            ; does the buffer cross a 64k boundary?
  552.     cmc                ; carry set if 64k crossing
  553.     sbb    bx,bx            ; bx = ffff if no crossing, 0 if crossed
  554.     and    ax,bx            ; clear ax if crossed
  555.     not    bx            ; bx = ffff if crossed, 0000 if not
  556.     and    bx,1000h
  557.     add    dx,bx            ; advance dx if we crossed a 64k boundary
  558.     jmp    short fdb_exit
  559. ;
  560. fdb_64k:
  561.     mov    dx,wptr dParm1+2    ; get the segment
  562.         sub     ax,ax                   ; offset is zero
  563.     and    dx,0f000h        ; find the next segment
  564.     add    dx,1000h        ; move to next segment
  565.     jnc    fdb_exit        ; if doesn't wraps past 1 meg, it's good
  566.         cwd                             ; bad, flush it...
  567. ;
  568. fdb_exit:
  569.     pop    bp
  570.     ret
  571.  
  572. FindDMABuffer    endp
  573. ;
  574. endif    ; PCMOBJ
  575. if MISC1OBJ
  576.  
  577. ;
  578. ;   /*\
  579. ;---|*|---------------====< InitMVSound() >====---------------
  580. ;---|*|
  581. ;---|*| Initializes this body of code. It will try to find the int 2F DOS
  582. ;---|*| interface to the MVPROAS device. Once found, the new state table
  583. ;---|*| pointer will be loaded.
  584. ;---|*|
  585. ;---|*| Entry Conditions:
  586. ;---|*|     None
  587. ;---|*|
  588. ;---|*| Exit Conditions:
  589. ;---|*|     DX:AX point to the state table
  590. ;   \*/
  591.  
  592.     public    InitMVSound
  593. InitMVSound    proc
  594.     push    es
  595.     push    di
  596.     mov    ax,ds
  597.     mov    es,ax
  598. ;
  599. ; find the hardware. Should be installed for this to run
  600. ;
  601.     call    MVInitStatePtr        ; initialize the state table ptr
  602.  
  603.     cmp    _MVHWVersionBits,-1    ; initialized yet?
  604.     jnz    @F            ; yes, continue on...
  605.     mov    ax,USE_ACTIVE_ADDR    ; pass in the base address
  606.     push    ax
  607.     call    mvGetHWVersion        ; no, checkout the hardware
  608.     pop    ax
  609.     ;
  610.     @@:
  611.     mov    ax,wptr [mvhwShadowPointer+0]
  612.     mov    dx,wptr [mvhwShadowPointer+2]
  613.  
  614.     pop    di
  615.     pop    es
  616.     ret
  617.  
  618. InitMVSound    endp
  619. ;
  620. endif    ; MISC1OBJ
  621. if    PCMOBJ
  622. ;
  623. ;   /*\
  624. ;---|*|---------------====< InitPCM() >====---------------
  625. ;---|*|
  626. ;---|*| Initializes the PCM code
  627. ;---|*|
  628. ;---|*| Entry Conditions:
  629. ;---|*|     None
  630. ;---|*|
  631. ;---|*| Exit Conditions:
  632. ;---|*|     AX =  Version of this Code
  633. ;   \*/
  634.  
  635.     public    InitPCM
  636. InitPCM proc
  637.     push    es
  638.  
  639.     mov    [TypeOfSetup],polledmask    ; flushes both interrupts
  640.                         ; for upcoming calls
  641.     mov    al,TheDMAChannel        ; initialize the DMA now...
  642.     cbw
  643.     push    ax
  644.     call    FFAR ptr SelectDMA
  645.     pop    ax
  646.  
  647.     mov    al,TheIRQChannel        ; initialize the IRQ now...
  648.     cbw
  649.     push    ax
  650.     call    FFAR ptr SelectIRQ        ; also removes the IRQ
  651.     pop    ax
  652.  
  653.         call    FFAR ptr StopPCM                ; kill the Audio Spectrum board
  654.  
  655.     mov    dx,INTRCTLRST            ; flush any pending PCM irq
  656.     xor    dx,[_MVTranslateCode]        ; xlate the board address
  657.     out    dx,al
  658.  
  659.     sub    ax,ax
  660.     mov    [TypeOfSetup],al        ; unknown type
  661.  
  662.     mov    wptr [UserRoutine+0],ax
  663.     mov    wptr [UserRoutine+2],ax
  664.  
  665.     mov    wptr [LinearPtr+0],ax
  666.     mov    wptr [LinearPtr+2],ax
  667.     mov    wptr [SegmentedPtr+0],ax
  668.         mov     wptr [SegmentedPtr+2],ax
  669.  
  670.     mov    wptr [DMABuffLength],ax
  671.  
  672.     not    al
  673.     mov    [StereoMono],al         ; mono
  674.  
  675.     mov    ax,11025
  676.     cwd
  677.  
  678.     call    FFAR ptr _calcsamplerate    ; setup the default rate
  679.     mov    wptr [TheSampleRate+0],ax
  680.     mov    wptr [TheSampleRate+2],dx
  681.  
  682.     mov    ax,0003h            ; for compatibility, version 00.03
  683.  
  684.     pop    es
  685.     ret
  686.  
  687. InitPCM endp
  688. ;
  689. endif    ; PCMOBJ
  690. if PCMOBJ
  691. ;
  692. ;
  693. ;   /*\
  694. ;---|*|---------------====< PausePCM >====---------------
  695. ;---|*|
  696. ;---|*| Turn off the h/w timer enables to effectively stop pcm temporarily.
  697. ;---|*|
  698. ;---|*| Entry Conditions:
  699. ;---|*|     None
  700. ;---|*|
  701. ;---|*| Exit Conditions:
  702. ;---|*|     Nothing
  703. ;---|*|
  704. ;   \*/
  705. ;
  706.     public    PausePCM
  707. PausePCM    proc
  708.     push    es
  709.     push    di
  710. ;
  711. ; Setup the audio filter sample bits
  712. ;
  713.     les    di,[mvhwShadowPointer]
  714.         mov     dx,AUDIOFILT
  715.     xor    dx,[_MVTranslateCode]       ; xlate the board address
  716.  
  717.         disable
  718.  
  719.         mov     al,es:[di._audiofilt]
  720.     and    al,not bFIsrate        ; flush the enable bits
  721.     mov    es:[di._audiofilt],al
  722.     out    dx,al
  723.  
  724.     enable
  725.  
  726.         pop     di
  727.     pop    es
  728.     ret
  729.  
  730. PausePCM    endp
  731.  
  732. ;
  733. ;   /*\
  734. ;---|*|---------------====< PCMInfo ( long, int, int, int ) >====---------------
  735. ;---|*|
  736. ;---|*| Selects xfer rate & stereo/mono
  737. ;---|*|
  738. ;---|*| Entry Conditions:
  739. ;---|*|     Parm #1 (wParm1, wParm2) is the rate
  740. ;---|*|     Parm #2 (wParm3)         is the stereo(1) or mono (0)
  741. ;---|*|     Parm #3 (wParm4)         is the compression flag
  742. ;---|*|     Parm #4 (wParm5)         is the data size (8/12/16 bits per sample)
  743. ;---|*|
  744. ;---|*| Exit Conditions:
  745. ;---|*|     AX =  0, good data
  746. ;---|*|     AX = -1, bum transfer rate
  747. ;---|*|
  748. ;   \*/
  749.  
  750.     public    PCMInfo
  751. PCMInfo     proc
  752.     push    bp
  753.     mov    bp,sp
  754.  
  755.     mov    al,wParm4+2        ; get the data size
  756.     cbw
  757.     cmp    al,8            ; 8 bit channel?
  758.     jz    @F
  759.  
  760.         inc     ah
  761.     cmp    al,12            ; 12 bit channel
  762.     jz    @F
  763.  
  764.     inc    ah
  765.     cmp    al,16            ; 16 bit channel?
  766.     jnz    pcinf_bad        ; no, bomb out...
  767.     ;
  768.     @@:
  769.     mov    [SampleSize],ah
  770.  
  771.         mov     cx,wParm3               ; get the stereo flag
  772.     shr    cx,1
  773.     jnz    pcinf_bad        ; exit bad if not zero
  774.  
  775.     cmc                ; set for mono, cleared for stereo
  776.     sbb    cx,cx            ; make a full bit mask
  777.     mov    [StereoMono],cl     ; save only valid values
  778.  
  779.         mov     ax,dParm1+0             ; get the sample rate
  780.     mov    dx,dParm1+2
  781.  
  782.     or    cx,cx            ; is it mono?
  783.     jnz    @F            ; yes, skip the doubling
  784.     shl    ax,1            ; no, stereo, so double the sample rate
  785.     adc    dx,dx
  786.     ;
  787.     @@:
  788.     call    FFAR ptr _calcsamplerate
  789.     jc    pcinf_bad
  790.     mov    wptr [TheSampleRate+0],ax
  791.     mov    wptr [TheSampleRate+2],dx
  792.  
  793.     sub    ax,ax
  794.     jmp    short pcinf_exit
  795. ;
  796. pcinf_bad:
  797.     mov    ax,-1
  798. ;
  799. pcinf_exit:
  800.         pop     bp
  801.     ret
  802.  
  803. PCMInfo     endp
  804. ;
  805. ;
  806. ;   /*\
  807. ;---|*|---------------====< PCMPlay() >====---------------
  808. ;---|*|
  809. ;---|*| Starts the DMA feeding the DAC
  810. ;---|*|
  811. ;---|*| Entry Conditions:
  812. ;---|*|     None
  813. ;---|*|
  814. ;---|*| Exit Conditions:
  815. ;---|*|     AX =  0 good start
  816. ;---|*|     AX = -1 not started, problem occured
  817. ;   \*/
  818.  
  819.     public    PCMPlay
  820. PCMPlay proc
  821.     push    es
  822.  
  823.     les    ax,LinearPtr          ; Validate the buffer pointer
  824.     mov    bx,es
  825.     or    ax,bx
  826.     jz    PCMPlay_bad
  827.  
  828.     mov    ax,[DMABuffLength]      ; Validate the buffer count
  829.     or    ax,ax
  830.     jz    PCMPlay_bad
  831.  
  832.     mov    ax,wptr [TheSampleRate+0] ; Validate the sample rate
  833.     or    ax,wptr [TheSampleRate+2]
  834.     jz    PCMPlay_bad          ; zero sample rate, bomb out...
  835.  
  836.     call    FFAR ptr StartPlaying      ; go for it...
  837.     sub    ax,ax
  838.     jmp    short PCMPlay_exit
  839. ;
  840. PCMPlay_bad:
  841.     mov    ax,-1
  842. ;
  843. PCMPlay_exit:
  844.     pop    es
  845.         ret
  846.  
  847. PCMPlay endp
  848. ;
  849. ;
  850. ;   /*\
  851. ;---|*|---------------====< PCMRecord() >====---------------
  852. ;---|*|
  853. ;---|*| Starts the DMA reading the ADC
  854. ;---|*|
  855. ;---|*| Entry Conditions:
  856. ;---|*|     None
  857. ;---|*|
  858. ;---|*| Exit Conditions:
  859. ;---|*|     AX =  0 recording has started
  860. ;---|*|     AX = -1 recording did not start
  861. ;---|*|
  862. ;   \*/
  863.  
  864.     public    PCMRecord
  865. PCMRecord proc
  866.         push    es
  867.  
  868.     les    ax,LinearPtr          ; Validate the buffer pointer
  869.     mov    bx,es
  870.     or    ax,bx
  871.     jz    PCMRec_bad
  872.  
  873.     mov    ax,[DMABuffLength]      ; Validate the buffer count
  874.     or    ax,ax
  875.     jz    PCMRec_bad
  876.  
  877.     mov    ax,wptr [TheSampleRate+0] ; Validate the sample rate
  878.     or    ax,wptr [TheSampleRate+2]
  879.     jz    PCMRec_bad
  880.  
  881.     call    FFAR ptr StartRecording   ; go for it...
  882.     mov    ax,0
  883.     jmp    short PCMRec_exit
  884. ;
  885. PCMRec_bad:
  886.     mov    ax,-1
  887. ;
  888. PCMRec_exit:
  889.     pop    es
  890.         ret
  891.  
  892. PCMRecord    endp
  893. ;
  894. ;
  895. ;   /*\
  896. ;---|*|---------------====< RemovePCM () >====---------------
  897. ;---|*|
  898. ;---|*| Remove our code from the system
  899. ;---|*|
  900. ;---|*| Entry Conditions:
  901. ;---|*|     None
  902. ;---|*|
  903. ;---|*| Exit Conditions:
  904. ;---|*|     None
  905. ;   \*/
  906.  
  907.     public    RemovePCM
  908. RemovePCM proc
  909.  
  910.     call    FFAR ptr StopPCM        ; kill the Audio Spectrum board
  911.  
  912.         mov     dx,INTRCTLRST                   ; flush any pending PCM irq
  913.         xor     dx,[_MVTranslateCode]           ; xlate the board address
  914.         out     dx,al
  915.  
  916.     call    FFAR ptr _unloadirqvector    ; restore the original vector
  917.  
  918.         ret
  919.  
  920. RemovePCM endp
  921. ;
  922. ;
  923. ;   /*\
  924. ;---|*|---------------====< ResumePCM >====---------------
  925. ;---|*|
  926. ;---|*| Turn on the h/w from making interrupt and DMA requests. This assumes
  927. ;---|*| the hardware has already been setup and is ready to go...
  928. ;---|*|
  929. ;---|*| Entry Conditions:
  930. ;---|*|     None
  931. ;---|*|
  932. ;---|*| Exit Conditions:
  933. ;---|*|     Nothing
  934. ;---|*|
  935. ;   \*/
  936. ;
  937.     public    ResumePCM
  938. ResumePCM    proc
  939.     push    es
  940.     push    di
  941. ;
  942. ; Setup the audio filter sample bits
  943. ;
  944.     les    di,[mvhwShadowPointer]
  945.     call    FFAR ptr _ASloadtimer0
  946.  
  947.         disable
  948.  
  949.         mov     dx,AUDIOFILT
  950.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  951.     mov    al,es:[di._audiofilt]
  952.     or    al,bFIsrate        ; enable sample rate and buffer timers
  953.     mov    es:[di._audiofilt],al
  954.     out    dx,al
  955.  
  956.     enable
  957.  
  958.         pop     di
  959.     pop    es
  960.     ret
  961.  
  962. ResumePCM       endp
  963. ;
  964. ;
  965. ;
  966. ;   /*\
  967. ;---|*|---------------====< SelectDMA( int ) >====---------------
  968. ;---|*|
  969. ;---|*| Selects the DMA channel 0 - 7, excluding 4
  970. ;---|*|
  971. ;---|*| Entry Conditions:
  972. ;---|*|     wParm1 points to DMA number (0, 1, 2, 3, 5, 6, 7 )
  973. ;---|*|
  974. ;---|*| Exit Conditions:
  975. ;---|*|     AX =  0, good buffer, all okay
  976. ;---|*|     AX = -1, good buffer, all okay
  977. ;---|*|
  978. ;   \*/
  979.  
  980.         public  SelectDMA
  981. SelectDMA    proc
  982.     push    bp
  983.     mov    bp,sp
  984.  
  985.         mov     ax,wParm1               ; get the DMA #
  986.  
  987.     and    ax,0111b        ; save the channels
  988.  
  989.         mov     bx,ax                   ; get some of the I/O addreses
  990.     shl    bx,1            ; into DX
  991.     jnz    seldma_02        ; not channel 0, go use it...
  992.     push    sp            ; 8088/86 class machine?
  993.     pop    cx
  994.     cmp    cx,sp
  995.     jnz    seldma_bad        ; yes, can't do channel 0 dma
  996.     ;
  997.     seldma_02:
  998.         mov     dx,cs:[dmatable+bx]
  999.     or    dx,dx            ; valid entry?
  1000.     jz    seldma_bad        ; no, bomb out...
  1001.  
  1002.         mov     TheDMAChannel,al        ; select the channel.
  1003.     mov    bptr OurDMAPageReg,dh    ; ...the page register,
  1004.     mov    bptr OurDMAddress,dl    ; ...the address register,
  1005.  
  1006.     lea    bx,DMA1AddrTable    ; get the DMA channel addresses
  1007.     cmp    al,4
  1008.     jl    seldma_05
  1009.     lea    bx,DMA2AddrTable    ; get the DMA channel addresses
  1010.     sub    al,4            ; make it zero based
  1011.     ;
  1012.     seldma_05:
  1013.     mov    [bx._dmach],al        ; save the adjusted dma channel #
  1014.     mov    [DMAPointer],bx     ; save the pointer to all DMA addrs
  1015.     sub    ax,ax
  1016.     pop    bp
  1017.     ret
  1018. ;
  1019. seldma_bad:
  1020.     mov    ax,-1
  1021.     pop    bp
  1022.     ret
  1023. ;
  1024. ; dma channels, etc
  1025. ;
  1026. dmatable    label    word
  1027.     dw    (CH0PAGEREG SHL 8) + DMAC0ADDR
  1028.         dw      (CH1PAGEREG SHL 8) + DMAC1ADDR
  1029.     dw    (CH2PAGEREG SHL 8) + DMAC2ADDR
  1030.     dw    (CH3PAGEREG SHL 8) + DMAC3ADDR
  1031.         dw      0
  1032.     dw    (CH5PAGEREG SHL 8) + DMA2C5ADDR
  1033.     dw    (CH6PAGEREG SHL 8) + DMA2C6ADDR
  1034.     dw    (CH7PAGEREG SHL 8) + DMA2C7ADDR
  1035.  
  1036. SelectDMA       endp
  1037.  
  1038. endif    ; PCMOBJ
  1039. if MISC2OBJ
  1040.  
  1041. ;   /*\
  1042. ;---|*|---------------====< SelectIRQ( int ) >====---------------
  1043. ;---|*|
  1044. ;---|*| Selects the IRQ line for DMA control
  1045. ;---|*|
  1046. ;---|*| Entry Conditions:
  1047. ;---|*|     wParm1 points to IRQ number (3,5,6,7)
  1048. ;---|*|
  1049. ;---|*| Exit Conditions:
  1050. ;---|*|     AX =  0, good buffer, all okay
  1051. ;---|*|     AX = -1, bad IRQ #
  1052. ;---|*|
  1053. ;   \*/
  1054.  
  1055.         public  SelectIRQ
  1056. SelectIRQ    proc
  1057.     push    bp
  1058.     mov    bp,sp
  1059.  
  1060.     call    FFAR ptr _unloadirqvector ; attempt to restore original vector
  1061.  
  1062.     sub    ax,ax            ; flush ax for a bad return
  1063.  
  1064.     mov    cx,wParm1        ; get the irq # (2-7,10-12,14-15)
  1065.     and    cl,0fh            ; save only the valid bits
  1066.     mov    bx,01
  1067.     shl    bx,cl
  1068.  
  1069.     and    bx,1001110010111100b    ; save the mask bit only if the irq
  1070.         jz      seirqbad                ; is a valid selection
  1071.  
  1072.     mov    TheIRQChannel,cl    ; save the channel number
  1073.  
  1074.     cmp    cl,8            ; 2nd interrupt controller?
  1075.     jb    @F            ; no, skip
  1076.     xchg    bh,bl
  1077.     ;
  1078.     @@:
  1079.     mov    TheIRQMask,bl
  1080.     call    FFAR ptr _loadirqvector ; load the new vector
  1081.     mov    ax,1
  1082. ;
  1083. seirqbad:
  1084.     dec    ax
  1085.     pop    bp
  1086.     ret
  1087.  
  1088. SelectIRQ       endp
  1089. ;
  1090. endif    ; MISC2OBJ
  1091. if PCMOBJ
  1092.  
  1093. ;
  1094. ;   /*\
  1095. ;---|*|--------------------====< void StopPCM() >====--------------------
  1096. ;---|*|
  1097. ;---|*| Turn off the PCM timers, interrupts, and state machine.
  1098. ;---|*|
  1099. ;---|*| Entry Conditions:
  1100. ;---|*|
  1101. ;---|*| Exit  Conditions:
  1102. ;---|*|
  1103. ;---|*|
  1104. ;   \*/
  1105.  
  1106.     public    StopPCM
  1107. StopPCM proc
  1108.     push    es
  1109.     push    di
  1110.     les    di,[mvhwShadowPointer]
  1111. ;
  1112. ; clear the audio filter sample bits
  1113. ;
  1114.     mov    dx,AUDIOFILT
  1115.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1116.     disable             ; drop dead...
  1117.     mov    al,es:[di._audiofilt]    ; get the state
  1118.     and    al,not (bFIsrate+bFIsbuff) ; flush the sample timer bits
  1119.     mov    es:[di._audiofilt],al    ; save the new state
  1120.     out    dx,al
  1121. ;
  1122. ; clear the PCM enable bit
  1123. ;
  1124.     mov    al,es:[di._crosschannel]; get the current cross channel
  1125.     and    al,not bCCenapcm    ; clear the PCM enable bit
  1126.     or    al,bCCdac
  1127.         mov     dx,CROSSCHANNEL
  1128.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1129.     out    dx,al            ; end to the hardware
  1130.     mov    es:[di._crosschannel],al
  1131. ;
  1132. ; disable the 16 bit stuff
  1133. ;
  1134.     test    [_MVHWVersionBits],bMV101  ; 101 chip?
  1135.     jz    stpc02               ; no, don't touch this...
  1136.     mov    dx,SYSCONFIG2
  1137.     xor    dx,[_MVTranslateCode]       ; xlate the board address
  1138.     in    al,dx
  1139.     and    al,not bSC216bit+bSC212bit ; flush the 16 bit stuff
  1140.     out    dx,al
  1141.     ;
  1142.     stpc02:
  1143. ;
  1144. ; clear the appropriate Interrupt Control Register bit
  1145. ;
  1146.     mov    ah,TypeOfSetup
  1147.     and    ah,bICsamprate+bICsampbuff
  1148.     not    ah
  1149.     mov    dx,INTRCTLR
  1150.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1151.     in    al,dx
  1152.     and    al,ah            ; kill sample timer interrupts
  1153.     out    dx,al
  1154.     mov    es:[di._intrctlr],al
  1155. ;
  1156. ; clear the system interrupt mask only if no other ints are used
  1157. ;
  1158.     test    al,fICintmaskbits XOR (bICsamprate+bICsampbuff)
  1159.     jnz    stpc10
  1160. ;
  1161. ; select the correct IRQ controller, then mask it...
  1162. ;
  1163.     cmp    TheIRQChannel,2     ; Chained IRQ channel?
  1164.     jz    stpc10            ; yes, leave it open...
  1165.  
  1166.         mov     dx,IRQ1MASKREG
  1167.     cmp    TheIRQChannel,8     ; 2nd IRQ controller?
  1168.     jl    stpc05
  1169.     mov    dl,IRQ2MASKREG
  1170.     ;
  1171.     stpc05:
  1172.     in    al,dx
  1173.     or    al,[TheIRQMask]
  1174.     out    dx,al
  1175.     enable                ; start again...
  1176. ;
  1177. stpc10:
  1178.     call    FFAR ptr KillDMA    ; stop the DMA too...
  1179.  
  1180.     mov    [StatusWord],0        ; inactive, available
  1181.  
  1182.     pop    di
  1183.     pop    es
  1184.     ret
  1185.  
  1186. StopPCM endp
  1187.  
  1188. ;
  1189. ;   /*\
  1190. ;---|*|---------------====< UserFunc((*long)()) >====---------------
  1191. ;---|*|
  1192. ;---|*| Call back routine when Half way buffer is full/empty.
  1193. ;---|*|
  1194. ;---|*| Entry Conditions:
  1195. ;---|*|     dParm1 points to the user routine
  1196. ;---|*|
  1197. ;---|*| Exit Conditions:
  1198. ;---|*|     Nothing
  1199. ;---|*|
  1200. ;   \*/
  1201.  
  1202.     public    UserFunc
  1203. UserFunc proc
  1204.     push    bp
  1205.     mov    bp,sp
  1206.  
  1207.         push    es
  1208.  
  1209.     les    ax,dParm1        ; get the routine
  1210.     mov    dx,es
  1211.     or    dx,ax
  1212.     jz    usfu_bad
  1213.  
  1214.     mov    wptr [UserRoutine+0],ax
  1215.     mov    wptr [UserRoutine+2],es
  1216. ;
  1217. usfu_bad:
  1218.     pop    es
  1219.     pop    bp
  1220.     ret
  1221.  
  1222. UserFunc endp
  1223.  
  1224. endif    ; PCMOBJ
  1225.  
  1226. ;
  1227. ;
  1228. ;----------------------------========================--------------------------
  1229. ;----------------------------========================--------------------------
  1230. ;----------------------------========================--------------------------
  1231. ;
  1232. ;
  1233. ;            PPPPPPPP      CCCCCC   MMM     MMM
  1234. ;            PPPPPPPP     CCCCCCC   MMMM    MMMM
  1235. ;            PPP   PPP   CCC        MMMMM   MMMMM
  1236. ;            PPP   PPP   CCC        MMMMMM MMMMMM
  1237. ;            PPPPPPPP    CCC        MMM MMMMM MMM
  1238. ;            PPPPPPPP    CCC        MMM  MMM  MMM
  1239. ;            PPP        CCC        MMM   M     MMM
  1240. ;            PPP        CCC        MMM     MMM
  1241. ;            PPP         CCCCCCC   MMM     MMM
  1242. ;            PPP          CCCCCC   MMM     MMM
  1243. ;
  1244. ;     rrrrr      oooo     uu  uu  tttttt  iiiiii  nn  nn   eeeee   sssss
  1245. ;     rr  rr  oo  oo  uu  uu    tt       ii     nnn nn  ee     ss
  1246. ;     rrrrrr  oo  oo  uu  uu    tt       ii     nnnnnn  eeeeee   ssss
  1247. ;     rr rr     oo  oo  uu  uu    tt       ii     nn nnn  ee         ss
  1248. ;     rr  rr   oooo      uuuuuu   tt     iiiiii  nn  nn   eeeee  sssss
  1249. ;
  1250. ;
  1251. ;
  1252. ;----------------------------========================--------------------------
  1253. ;----------------------------========================--------------------------
  1254. ;----------------------------========================--------------------------
  1255.  
  1256. if PCMOBJ
  1257.  
  1258. ;
  1259. ;----------------------------====< _ASloadtimer0 >====-------------------------
  1260. ;
  1261. ;
  1262. ; Setup the Sample Timer (T0 & square wave output)
  1263. ;
  1264. ;   Entry Conditions:
  1265. ;    ES:DI point to the state table.
  1266. ;   Exit Conditions:
  1267. ;    The timer is loaded with the new sample rate
  1268. ;
  1269.     public    _ASloadtimer0
  1270. _ASloadtimer0    proc
  1271.  
  1272.         mov     al,00110110b            ; 36h Timer 0 & square wave
  1273.     mov    dx,TMRCTLR
  1274.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1275.  
  1276.     pushf
  1277.     cli
  1278.  
  1279.     out    dx,al            ; setup the mode, etc
  1280.         mov     es:[di._tmrctlr],al
  1281.  
  1282.     mov    ax,es:[di._samplerate]    ; pre-calculated & saved in prior code
  1283.     mov    dx,SAMPLERATE
  1284.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1285.     out    dx,al            ; output the timer value
  1286.  
  1287.         pause
  1288.  
  1289.         xchg    ah,al
  1290.     out    dx,al
  1291.  
  1292.         popf
  1293.     ret
  1294.  
  1295. _ASloadtimer0   endp
  1296.  
  1297. ;
  1298. ;----------------------------====< _ASloadtimer1 >====-------------------------
  1299. ;
  1300.         public  _ASloadtimer1
  1301. _ASloadtimer1   proc
  1302.     push    es
  1303.     push    di
  1304.     les    di,[mvhwShadowPointer]
  1305.  
  1306.         push    dx                      ; do not disturb any register
  1307.     push    ax
  1308.  
  1309.         mov     al,01110100b            ; 74h Timer 1 & rate generator
  1310.     mov    dx,TMRCTLR
  1311.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1312.  
  1313.         disable
  1314.  
  1315.         out     dx,al
  1316.     mov    es:[di._tmrctlr],al    ; local timer control register
  1317.  
  1318.     pop    ax
  1319.  
  1320.         mov     dx,SAMPLECNT
  1321.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1322.     mov    es:[di._samplecnt],ax
  1323.  
  1324.         out     dx,al
  1325.         pause
  1326.     xchg    ah,al
  1327.     out    dx,al
  1328.  
  1329.     enable
  1330.  
  1331.     xchg    ah,al
  1332.  
  1333.     pop    dx
  1334.     pop    di
  1335.     pop    es
  1336.     ret
  1337.  
  1338. _ASloadtimer1    endp
  1339. ;
  1340. ;
  1341. ;--------------------------====< _calcsamplerate >====-------------------------
  1342. ;
  1343. ;  Calculate the H/W timer value (internal routine)
  1344. ;
  1345. ; Entry Conditions:
  1346. ;    DX:AX hold the users requested sample rate
  1347. ;
  1348. ; Exit Conditions:
  1349. ;    carry SET if bad value
  1350. ;    No registers modified
  1351. ;
  1352. ;
  1353.     public    _calcsamplerate
  1354. _calcsamplerate proc
  1355.     push    es
  1356.     push    di
  1357.     les    di,[mvhwShadowPointer]
  1358.  
  1359.     push    ax
  1360.     push    bx
  1361.     push    cx
  1362.     push    dx
  1363. ;
  1364. ; make sure sample rate does not exceed 88200
  1365. ;
  1366.         mov     cx,ax                   ; do 32 bit subtraction
  1367.     sub    cx,05888H+1        ; 157C0 is decimal 88200
  1368.     mov    cx,dx            ; too high?
  1369.     sbb    cx,00001H        ;  over 88200 khz is bad
  1370.     jnc    CaSaRa_bad        ; bomb out greater than 88200
  1371. ;
  1372. ; load 1193180 in bx:cx for 32x32 bit division
  1373. ;
  1374.     mov    bx,0012h
  1375.     mov    cx,34dch        ; load bx:cx with 1193180
  1376.  
  1377.     xchg    bx,dx            ; dx:ax = 1193180
  1378.     xchg    cx,ax            ; bx:cx = sample rate
  1379. ;
  1380. ; since we don't have 32x32 bit division, we'll cheat here. No great loss.
  1381. ;
  1382.     or    bx,bx            ; is value over 64k?
  1383.     jz    @F            ; no, continue on...
  1384.     shr    bx,1            ; yes, divide all by 2
  1385.     rcr    cx,1            ; to allow division of 32x16 bits
  1386.     shr    dx,1
  1387.     rcr    ax,1
  1388. ;
  1389. @@:
  1390.     div    cx
  1391.     mov    es:[di._samplerate],ax    ; save just the low order
  1392.     clc
  1393.     jmp    short CaSaRa_exit
  1394. ;
  1395. CaSaRa_bad:
  1396.     stc
  1397. ;
  1398. CaSaRa_exit:
  1399.     pop    dx
  1400.     pop    cx
  1401.     pop    bx
  1402.     pop    ax
  1403.  
  1404.         pop     di
  1405.     pop    es
  1406.     ret
  1407.  
  1408. _calcsamplerate endp
  1409. ;
  1410. ;
  1411. ;----------------------------====< EnableRecording >====-----------------------
  1412. ;
  1413.     public    EnableRecording
  1414. EnableRecording  proc
  1415. ;
  1416. ; Save the type of setup. It contains the interrupt masks needed
  1417. ;
  1418.     mov    [TypeOfSetup],POLLEDINPUT
  1419.     mov    [PCMDirection],0    ; bit 6 is cleared (DAC enable)
  1420. ;
  1421. ; enable the onboard sampling timers, disable interrupts
  1422. ;
  1423.     call    FFAR ptr SetupPCMPolledIO ; Setup the MV Hardware
  1424.     mov    StatusWord,2        ; set the global status word
  1425.         ret
  1426.  
  1427. EnableRecording  endp
  1428. ;
  1429. ;
  1430. ;----------------------------====< EnablePlaying >====-------------------------
  1431. ;
  1432.     public    EnablePlaying
  1433. EnablePlaying    proc
  1434. ;
  1435. ; Save the type of setup. It contains the interrupt masks needed
  1436. ;
  1437.     mov    [TypeOfSetup],POLLEDOUTPUT
  1438.         mov     [PCMDirection],bCCdac   ; bit d6 of interrupt control register
  1439. ;
  1440. ; enable the onboard sampling timers, etc.
  1441. ;
  1442.     call    FFAR ptr SetupPCMPolledIO ; Setup the MV Hardware
  1443.     mov    StatusWord,1        ; set the global status word
  1444.  
  1445.         ret
  1446.  
  1447. EnablePlaying     endp
  1448. ;
  1449. endif    ; PCMOBJ
  1450. if MISC2OBJ
  1451. ;
  1452. ;---------------------------====< _getirqoffset >====--------------------------
  1453. ;
  1454. ; takes the IRQ # & converts to offset in vector table
  1455. ;
  1456. ;
  1457.     public    _getirqoffset
  1458. _getirqoffset   proc
  1459.         sub     bh,bh
  1460.     shl    bx,1
  1461.     mov    bx,cs:[irqoffsets+bx]
  1462.     ret
  1463.  
  1464. irqoffsets    label    word
  1465.     dw    (8+0)*4         ; IRQ 0 clock timer
  1466.     dw    (8+1)*4         ; IRQ 1 keyboard
  1467.     dw    (8+2)*4         ; IRQ 2 available
  1468.     dw    (8+3)*4         ; IRQ 3 COM2
  1469.     dw    (8+4)*4         ; IRQ 4 COM1
  1470.     dw    (8+5)*4         ; IRQ 5 available
  1471.     dw    (8+6)*4         ; IRQ 6 floppy controller
  1472.     dw    (8+7)*4         ; IRQ 7 LPT
  1473.     dw    (70h+0)*4        ; IRQ 8 real time clock
  1474.     dw    (70h+1)*4        ; IRQ 9 Re-Directed IRQ2
  1475.     dw    (70h+2)*4        ; IRQ a available
  1476.     dw    (70h+3)*4        ; IRQ b available
  1477.     dw    (70h+4)*4        ; IRQ c available
  1478.     dw    (70h+5)*4        ; IRQ d coprocessor
  1479.     dw    (70h+6)*4        ; IRQ e Hard Disk
  1480.     dw    (70h+7)*4        ; IRQ f available
  1481.  
  1482. _getirqoffset   endp
  1483. ;
  1484. endif    ; MISC2OBJ
  1485. if PCMOBJ
  1486. ;
  1487. ;------------------------------====< KillDMA >====-----------------------------
  1488. ;
  1489. ; KillDMA  -- flush our settings
  1490. ;
  1491. ; Entry Conditions:
  1492. ;
  1493. KillDMA proc
  1494.     push    es
  1495.     push    di
  1496.  
  1497.         cmp     StatusWord,0            ; is there any activity?
  1498.     jz    kidm_none
  1499.  
  1500.     mov    di,[DMAPointer]     ; get the DMA pointer
  1501.         sub     dx,dx                   ; clear out the high byte
  1502. ;
  1503. ; mask out the DMA to stop it
  1504. ;
  1505.     disable
  1506.     mov    al,[di._dmach]        ; get the adjusted dma channel #
  1507.         or      al,0100b                ; disable the DMA
  1508.     mov    dl,[di._dmawrsmr]
  1509.     out    dx,al
  1510. ;
  1511. ; remove control on the DRQ line
  1512. ;
  1513.         les     di,[mvhwShadowPointer]
  1514.  
  1515.         mov     al,es:[di._crosschannel]; get the state
  1516.         mov     dx,CROSSCHANNEL
  1517.         xor     dx,[_MVTranslateCode]           ; xlate the board address
  1518.     and    al,not bCCdrq        ; clear the DRQ bit
  1519.     out    dx,al
  1520.  
  1521.         mov     es:[di._crosschannel],al; and save the new state
  1522.     enable
  1523. ;
  1524. kidm_none:
  1525.     pop    di
  1526.     pop    es
  1527.     ret
  1528.  
  1529. KillDMA endp
  1530. ;
  1531. endif    ; PCMOBJ
  1532. if PCMOBJ
  1533. ;
  1534. ;------------------------------====< LoadDMA >====-----------------------------
  1535. ;
  1536. ; LoadDMA  -- Load the DMA controller to read/write data to the MV board
  1537. ;
  1538. ; Entry Conditions:
  1539. ;
  1540. ;
  1541.     public    LoadDMA
  1542. LoadDMA proc
  1543.     push    es
  1544.     push    di
  1545.     push    si
  1546.  
  1547.         les     di,[mvhwShadowPointer]
  1548.  
  1549.     mov    si,[DMAPointer]     ; point to the DMA controller table
  1550.     sub    dx,dx            ; clear out the high byte
  1551. ;
  1552. ; kill the dma until all programming is done
  1553. ;
  1554.     mov    al,[si._dmach]        ; get the adjusted dma channel #
  1555.         or      al,0100b                ; causes all DMA to be suspended
  1556.     mov    dl,[si._dmawrsmr]
  1557.     out    dx,al
  1558. ;
  1559. ; program the mode
  1560. ;
  1561.         mov     al,[TheDMAmode]         ; get the app's desired mode
  1562.     or    al,[si._dmach]        ; merge the adjusted dma channel #
  1563.     mov    dl,[si._dmawrmode]
  1564.         out     dx,al
  1565. ;
  1566. ; adjust the address for a 16 bit channel
  1567. ;
  1568.     mov    ax,wptr [LinearPtr+2]    ; get the page #
  1569. ;
  1570. ; setup the page register
  1571. ;
  1572.     mov    dx,[OurDMAPageReg]
  1573.     out    dx,al
  1574.     mov    bl,al
  1575. ;
  1576. ; reset the flip-flop, then output the address, then count
  1577. ;
  1578.     mov    dl,[si._dmaclear]    ; dh is still clear...
  1579.         out     dx,al                   ; flush...
  1580.  
  1581.     mov    ax,wptr [LinearPtr+0]    ; get the low 16 bits
  1582.     cmp    si,offset DMA1AddrTable ; 1st DMA controller?
  1583.     jz    @F            ; yes, continue on...
  1584.     shr    bl,1            ; no, divide the buffer in half
  1585.     rcr    ax,1            ; by shifting 17 bits
  1586.     ;
  1587.     @@:
  1588.     mov    dx,[OurDMAddress]
  1589.     out    dx,al
  1590.     pause
  1591.     xchg    ah,al
  1592.     out    dx,al
  1593.  
  1594.     mov    ax,[DMABuffLength]
  1595.     cmp    si,offset DMA1AddrTable ; is this the 2nd dma controller?
  1596.     jz    lodma03         ; no, use the full length
  1597.     shr    ax,1
  1598.         inc     dx                      ; move to next port address
  1599.     ;
  1600.     lodma03:
  1601.     inc    dx            ; move to next port address
  1602.     out    dx,al
  1603.     pause
  1604.     xchg    ah,al
  1605.     out    dx,al
  1606. ;
  1607. ; before we enable the DMA, let's make sure the DRQ is controlled, not floating
  1608. ;
  1609.     mov    al,es:[di._crosschannel]; get the state
  1610.         mov     dx,CROSSCHANNEL
  1611.         xor     dx,[_MVTranslateCode]           ; xlate the board address
  1612.     or    al,bCCdrq        ; set the DRQ bit to control it
  1613.     out    dx,al
  1614.     mov    es:[di._crosschannel],al; and save the new state
  1615. ;
  1616. ; re-enable the dma now that all programming is done
  1617. ;
  1618.     mov    al,[si._dmach]        ; get the adjusted dma channel #
  1619.         sub     dx,dx                   ; clear dh
  1620.     mov    dl,[si._dmawrsmr]
  1621.     out    dx,al            ; & let'er loose (not moving though...)
  1622. ;
  1623. ; all done, return home...
  1624. ;
  1625.     pop    si
  1626.     pop    di
  1627.     pop    es
  1628.     ret
  1629.  
  1630. LoadDMA endp
  1631. ;
  1632. endif    ; PCMOBJ
  1633. if MISC2OBJ
  1634. ;
  1635. ;--------------------------====< _loadirqvector >====--------------------------
  1636. ;
  1637. ; Restore the original vector
  1638. ;
  1639. ; Entry Conditions:
  1640. ;
  1641. ; Exit Conditions:
  1642. ;     Nothing
  1643.  
  1644.     public    _loadirqvector
  1645. _loadirqvector  proc
  1646.     push    es
  1647.  
  1648.         les     ax,OldIRQRoutine
  1649.     mov    bx,es
  1650.     or    bx,ax
  1651.     jnz    @F
  1652.  
  1653.     lea    ax,OurIntVector
  1654.     mov    dx,cs
  1655.  
  1656.     mov    bl,[TheIRQChannel]
  1657.     call    FFAR ptr _getirqoffset
  1658.  
  1659.     push    ds
  1660.     sub    cx,cx
  1661.     mov    ds,cx
  1662.  
  1663.     disable
  1664.     xchg    ds:[bx+0],ax
  1665.     xchg    ds:[bx+2],dx
  1666.     enable
  1667.  
  1668.     pop    ds
  1669.  
  1670.     mov    wptr [OldIRQRoutine+0],ax
  1671.     mov    wptr [OldIRQRoutine+2],dx
  1672. ;
  1673. @@:
  1674.     pop    es
  1675.     ret
  1676.  
  1677. _loadirqvector    endp
  1678. ;
  1679. endif    ; MISC2OBJ
  1680. if MISC2OBJ
  1681. ;
  1682. ;---------------------------====< OurIntVector >====---------------------------
  1683. ;
  1684. ; OurIntVector    -- process DMA interrupts
  1685. ;
  1686.  
  1687. intsemaphore    db    -1        ; -1 free, 0+ locked
  1688.  
  1689.     public    OurIntVector
  1690. OurIntVector    proc
  1691.     push    dx
  1692.     push    ax
  1693.         push    ds
  1694.  
  1695. if MODELSIZE eq 0
  1696.     mov    ax,cs            ; tiny (.com) model uses cs segment
  1697. else
  1698.     mov    ax,@data        ; all others use their data segments
  1699. endif
  1700.     mov    ds,ax
  1701.  
  1702.     mov    dx,INTRCTLRST        ; clear the interrupt
  1703.         xor     dx,[_MVTranslateCode]           ; xlate the board address
  1704.     in    al,dx
  1705.  
  1706.         test    al,bISsampbuff          ; our interrupt?
  1707.     jz    skip_int        ; no, continue on...
  1708.  
  1709.     out    dx,al            ; yes, flush it...
  1710.  
  1711.     mov    al,EOI            ; clear the interrupt
  1712.     cmp    TheIRQChannel,8     ; 2nd IRQ controller?
  1713.     jb    @F
  1714.     out    IRQ2ACKREG,al
  1715.     ;
  1716.     @@:
  1717.     out    IRQ1ACKREG,al
  1718.  
  1719.         inc     [NumberOfInterrupts]
  1720.  
  1721.     inc    cs:[intsemaphore]
  1722.         jnz     oiv_done
  1723.  
  1724.     sti                ; let interrupts go while we work
  1725.  
  1726.     cmp    wptr [UserRoutine+2],0    ; call the user function?
  1727.     jz    oiv_done        ; no, just exit
  1728.  
  1729.     call    dword ptr [UserRoutine]
  1730. ;
  1731. oiv_done:
  1732.     dec    cs:[intsemaphore]
  1733. ;
  1734. exit_int:
  1735.     pop    ds
  1736.     pop    ax
  1737.     pop    dx
  1738.     iret
  1739. ;
  1740. skip_int:
  1741.     pushf
  1742.     call    dword ptr ds:[OldIRQRoutine] ; perform the old interrupt
  1743.     jmp    short exit_int
  1744.  
  1745. OurIntVector    endp
  1746. ;
  1747. endif    ; MISC2OBJ
  1748. if PCMOBJ
  1749. ;
  1750. ;---------------------------====< SetupPCMDMAIO >====--------------------------
  1751. ;
  1752. ; SetupPCMDMAIO  --  Setup to output to the DAC
  1753. ;
  1754.     public    SetupPCMDMAIO
  1755. SetupPCMDMAIO   proc
  1756.     push    es
  1757.     push    di
  1758.     les    di,[mvhwShadowPointer]
  1759. ;
  1760. ; setup the sample rate timer
  1761. ;
  1762.         call    _ASloadtimer0
  1763. ;
  1764. ; Setup the Sample Buffer Counter Timer (T1 & rate generator)
  1765. ;
  1766.         mov     ax,[DMABuffLength]      ; get the count
  1767.     sub    dx,dx
  1768.     add    ax,1            ; make it 1 based (1 - 64k)
  1769.     adc    dx,dx
  1770.     mov    cl,[DMABUffDivides]    ; get the buffer size
  1771.     sub    ch,ch
  1772.     div    cx            ; now, we must be flexible
  1773.  
  1774.     mov    bl,[TheDMAChannel]    ; is this a 16 bit channel?
  1775.     mov    bh,[SampleSize]     ; CX = sample size, channel
  1776.  
  1777.     sub    cx,cx            ; ch = multiplier, cl=divider
  1778.     cmp    bx,0003h        ; 8 bits on 8 bit channel?
  1779.     jbe    @F            ; yes, continue on...
  1780.  
  1781.     inc    cx            ; divide by 2
  1782.     cmp    bx,0007h        ; 8 bits on 16 bit channel?
  1783.     jbe    @F            ; yes, continue on...
  1784.  
  1785.     xchg    ch,cl            ; multiply by 2
  1786.     cmp    bx,0203h        ; 16 bits on 8 bit channel?
  1787.     jbe    @F            ; yes, continue on...
  1788.     sub    cx,cx            ; no multiply or divide
  1789.     ;
  1790.     @@:
  1791.         shr     ax,cl                   ; if 8 on 16 divide by 2
  1792.     xchg    ch,cl
  1793.     shl    ax,cl            ; if 16 on 8 multiply by 2
  1794.  
  1795.     sub    cx,cx            ; The buffer size is # of bytes, so
  1796.     neg    bh            ; we must convert it to the data size
  1797.     adc    cx,cx
  1798.     shr    ax,cl
  1799.  
  1800.         call    FFAR ptr _ASloadtimer1
  1801. ;
  1802. ; Setup the system interrupt mask (IRQ mask)
  1803. ;
  1804.     mov    dx,IRQ1MASKREG
  1805.     cmp    TheIRQChannel,8     ; 2nd IRQ controller?
  1806.     jl    @F
  1807.     mov    dl,IRQ2MASKREG
  1808.     ;
  1809.     @@:
  1810.     in    al,dx            ; get the mask
  1811.     mov    ah,TheIRQMask
  1812.     not    ah
  1813.     and    al,ah            ; unmask the correct IRQ
  1814.     out    dx,al            ; then let the system know
  1815. ;
  1816. ; Setup the Interrupt Control Register
  1817. ;
  1818.     mov    dx,INTRCTLRST        ; flush any pending interrupts
  1819.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1820.     out    dx,al            ; of the PCM circuitry
  1821.  
  1822.         mov     dx,INTRCTLR
  1823.         xor     dx,[_MVTranslateCode]           ; xlate the board address
  1824.     in    al,dx            ; get the real mask
  1825.     or    al,bICsampbuff        ; interrupt on sample buffer count
  1826.     out    dx,al            ; send it..
  1827.     mov    es:[di._intrctlr],al    ; save it..
  1828. ;
  1829. ; enable the 12/16 bit stuff
  1830. ;
  1831.     test    [_MVHWVersionBits],bMV101 ; 101 chip?
  1832.     jz    sdhpas1_05          ; no, don't touch this...
  1833.  
  1834.     mov    cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit+bSC212bit
  1835.     cmp    [SampleSize],1        ; 12 bit?
  1836.     jz    @F
  1837.     mov    cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit
  1838.     cmp    [SampleSize],2        ; 16 bit?
  1839.     jz    @F
  1840.     mov    cx,((NOT(bSC216bit+bSC212bit))*256) + 0
  1841.     ;
  1842.     @@:
  1843.     mov    dx,SYSCONFIG2
  1844.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1845.     in    al,dx
  1846.     and    al,ch            ; clear the bits
  1847.     or    al,cl            ; set the appropriate bits
  1848.     out    dx,al
  1849.     ;
  1850.     sdhpas1_05:
  1851. ;
  1852. ; setup the direction, stereo/mono and DMA enable bits
  1853. ;
  1854.     mov    al,bCCmono        ; get the stereo/mono mask bit
  1855.     and    al,[StereoMono]     ; al = bCCmono if in mono mode
  1856.     or    al,[PCMDirection]    ; get the direction bit mask
  1857.     or    al,bCCenapcm        ; enable the PCM state machine
  1858.         mov     dx,CROSSCHANNEL
  1859.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1860.     mov    ah,0fh + bCCdrq     ; get a mask to load non PCM bits
  1861.     and    ah,es:[di._crosschannel]; grab all but PCM/DRQ/MONO/DIRECTION
  1862.     or    al,ah            ; merge the two states
  1863.     xor    al,bCCenapcm        ; disable the PCM bit
  1864.     out    dx,al            ; send to the hardware
  1865.     xor    al,bCCenapcm        ; enable the PCM bit
  1866.     out    dx,al            ; send to the hardware
  1867.     mov    es:[di._crosschannel],al; and save the new state
  1868. ;
  1869. ; Setup the audio filter sample bits
  1870. ;
  1871.     mov    al,es:[di._audiofilt]
  1872.     or    al,(bFIsrate+bFIsbuff)    ; enable the sample count/buff counters
  1873.     mov    dx,AUDIOFILT
  1874.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1875.     out    dx,al
  1876.     mov    es:[di._audiofilt],al
  1877.  
  1878.         mov     NumberOfInterrupts,0
  1879.  
  1880.         enable                          ; Fly, baby Fly!!!
  1881.  
  1882.     pop    di
  1883.     pop    es
  1884.     ret
  1885.  
  1886. SetupPCMDMAIO    endp
  1887. ;
  1888. ;
  1889. ;---------------------------====< SetupPCMPolledIO >====-----------------------
  1890. ;
  1891. ; SetupPCMPolledIO  --    Setup to read/write to the ADC/DAC in a polled fashion
  1892. ;
  1893.     public    SetupPCMPolledIO
  1894. SetupPCMPolledIO        proc
  1895.     push    es
  1896.     push    di
  1897.     les    di,[mvhwShadowPointer]
  1898. ;
  1899. ; Setup the Sample Timer (T0 & square wave output)
  1900. ;
  1901.     call    _ASloadTimer0
  1902. ;
  1903. ; Setup the Sample Buffer Counter Timer (T1 & rate generator)
  1904. ;
  1905.     mov    ax,1            ; get the count
  1906.     call    FFAR ptr _ASloadtimer1
  1907. ;
  1908. ; Setup the Interrupt Control Register
  1909. ;
  1910.         mov     dx,INTRCTLR
  1911.     xor    dx,[_MVTranslateCode]       ; xlate the board address
  1912.     in    al,dx               ; get the real mask
  1913.     or    al,bICsampbuff+bICsamprate ; enable both sample timer ints
  1914.     out    dx,al               ; send it...
  1915.     mov    es:[di._intrctlr],al       ; save it...
  1916. ;
  1917. ; enable the 16 bit stuff
  1918. ;
  1919.     test    [_MVHWVersionBits],bMV101 ; 101 chip?
  1920.     jz    sphpas1_05          ; no, don't touch this...
  1921.  
  1922.     mov    cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit+bSC212bit
  1923.     cmp    [SampleSize],1        ; 12 bit?
  1924.     jz    @F
  1925.     mov    cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit
  1926.     cmp    [SampleSize],2        ; 16 bit?
  1927.     jz    @F
  1928.     mov    cx,((NOT(bSC216bit+bSC212bit))*256) + 0
  1929.     ;
  1930.     @@:
  1931.     mov    dx,SYSCONFIG2
  1932.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1933.     in    al,dx
  1934.     and    al,ch            ; clear the bits
  1935.     or    al,cl            ; set the appropriate bits
  1936.     out    dx,al
  1937.     ;
  1938.     sphpas1_05:
  1939. ;
  1940. ; setup the direction, stereo/mono and DMA enable bits
  1941. ;
  1942.     mov    al,bCCmono        ; get the stereo/mono mask bit
  1943.     and    al,[StereoMono]     ; al = bCCmono if in mono mode
  1944.     or    al,[PCMDirection]    ; get the direction bit mask
  1945.     or    al,bCCenapcm + bCCdrq    ; enable the PCM & set DRQ for NOT mask
  1946.         mov     dx,CROSSCHANNEL
  1947.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1948.     mov    ah,0fh            ; get a mask to load the non-PCM bits
  1949.     and    ah,es:[di._crosschannel]; grab all but PCM/DRQ/MONO/DIRECTION
  1950.     or    al,ah            ; merge the two states
  1951.     xor    al,bCCenapcm + bCCdrq    ; disable the PCM & DRQ
  1952.     out    dx,al            ; send to the hardware
  1953.     xor    al,bCCenapcm        ; enable the PCM
  1954.     out    dx,al
  1955.     mov    es:[di._crosschannel],al; and save the new state
  1956. ;
  1957. ; Setup the audio filter sample bits to enable sample timer/count
  1958. ;
  1959.     mov    al,es:[di._audiofilt]
  1960.     or    al,(bFIsrate+bFIsbuff)    ; enable the sample timer/counter
  1961.     mov    dx,AUDIOFILT
  1962.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1963.     out    dx,al
  1964.     mov    es:[di._audiofilt],al
  1965.  
  1966.         sub     ax,ax
  1967.     mov    NumberOfInterrupts,ax
  1968.  
  1969.         enable
  1970.  
  1971.     pop    di
  1972.     pop    es
  1973.     ret
  1974.  
  1975. SetupPCMPolledIO   endp
  1976. ;
  1977. ;
  1978. ;----------------------------====< StartPlaying >====--------------------------
  1979. ;
  1980.     public    StartPlaying
  1981. StartPlaying    proc
  1982. ;
  1983. ; Save the type of setup. It contains the interrupt masks needed
  1984. ;
  1985.     mov    [TypeOfSetup],DMAOUTPUT
  1986.     mov    [PCMDirection],bCCdac    ; bit d6 of interrupt control register
  1987. ;
  1988. ; Select the DMA mode for playing
  1989. ;
  1990.     mov    al,10h            ; auto init bit on 8237 chip
  1991.     and    al,[DMAAutoInit]    ; al may have the auto-init bit
  1992.     or    al,48h            ; merge in the rest of the DMA bits
  1993.     mov    TheDMAMode,al        ; save the mode
  1994. ;
  1995. ; Program the DMA, then our board circuitry to start the interrupts
  1996. ;
  1997.         call    LoadDMA                 ; setup the DMA controller
  1998.     call    SetupPCMDMAIO        ; Setup the MV Hardware
  1999.  
  2000.     mov    StatusWord,1        ; set the global status word
  2001.  
  2002.         ret
  2003.  
  2004. StartPlaying    endp
  2005. ;
  2006. ;
  2007. ;---------------------------====< StartRecording >====-------------------------
  2008. ;
  2009.     public    StartRecording
  2010. StartRecording    proc
  2011. ;
  2012. ; Save the type of setup. It contains the interrupt masks needed
  2013. ;
  2014.     mov    [TypeOfSetup],DMAINPUT
  2015.     mov    [PCMDirection],00h    ; bit d6 of interrupt control register
  2016. ;
  2017. ; Select the DMA mode for recording
  2018. ;
  2019.     mov    al,10h            ; auto init bit on 8237 chip
  2020.     and    al,[DMAAutoInit]    ; al may have the auto-init bit
  2021.     or    al,44h            ; merge in the rest of the DMA bits
  2022.     mov    TheDMAMode,al        ; save the mode
  2023. ;
  2024. ; Program the DMA, then our board circuitry to start the interrupts
  2025. ;
  2026.         call    LoadDMA                 ; setup the DMA controller
  2027.     call    SetupPCMDMAIO        ; Setup the MV Hardware
  2028.  
  2029.     mov    StatusWord,2        ; set the global status word
  2030.         ret
  2031.  
  2032. StartRecording    endp
  2033. ;
  2034. endif    ; PCMOBJ
  2035. if MISC2OBJ
  2036. ;
  2037. ;---------------------====< _unloadirqvector >====---------------
  2038. ;
  2039. ; Restore the original vector
  2040. ;
  2041. ; Entry Conditions:
  2042. ;     dParm1 points to the user routine
  2043. ;
  2044. ; Exit Conditions:
  2045. ;     Nothing
  2046. ;
  2047. ;
  2048.     public    _unloadirqvector
  2049. _unloadirqvector    proc
  2050.     push    es
  2051.  
  2052.         les     ax,OldIRQRoutine
  2053.     mov    bx,es
  2054.     or    bx,ax
  2055.     jz    @F
  2056.  
  2057.     mov    bl,[TheIRQChannel]
  2058.     call    _getirqoffset
  2059.  
  2060.     push    ds
  2061.     sub    cx,cx
  2062.     mov    ds,cx
  2063.  
  2064.         disable
  2065.     mov    ds:[bx+0],ax
  2066.     mov    ds:[bx+2],es
  2067.         enable
  2068.  
  2069.     pop    ds
  2070.  
  2071.         sub     ax,ax
  2072.     mov    wptr [OldIRQRoutine+0],ax
  2073.     mov    wptr [OldIRQRoutine+2],ax
  2074. ;
  2075. @@:
  2076.     pop    es
  2077.     ret
  2078.  
  2079. _unloadirqvector    endp
  2080.  
  2081. endif    ; MISC2OBJ
  2082.  
  2083.     end
  2084.  
  2085.