home *** CD-ROM | disk | FTP | other *** search
/ Sound Sensations! / sound_sensations.iso / miditool / midiex18 / midiint.asm < prev    next >
Encoding:
Assembly Source File  |  1989-12-07  |  16.0 KB  |  547 lines

  1.         DOSSEG
  2.         .MODEL  SMALL,C
  3.  
  4.  
  5. COMMENT |
  6.  
  7.   MIDIINT.ASM -- Assembler subroutines for MIDIEX patch exchange utility
  8.  
  9.  
  10.   COPYRIGHT (C) 1986 John Bailin, Cantus Corporation
  11.  
  12.   Date:        01/02/86
  13.  
  14.   Changed 08/24/86 Jim Bergsten to function using the Microsoft "C"
  15.   compiler. Summary of changes:
  16.       1. PAGE statement added for better output listing.
  17.       2. Entry point names prefixed with "_".
  18.       3. GROUP, PROG, SEGMENT statements changed to match Microsoft
  19.          small model standards.
  20.       4. Unnecessary stack subtracts and adds removed.
  21.       5. Other corrections, simplifications...
  22.  
  23.   Changed 11/14/86 by Michael Geary - fixed several bugs
  24.  
  25.   Modified 1/22/88 by Dave Hayes - Added support for GMR bulk dumps by
  26.                                    increasing size of receive buffer
  27.  
  28.   Note: Linkage conventions assume the Microsoft C compiler small model.
  29.  
  30.  
  31.   Modified 12/5/89 by Mike W. Smith:
  32.         1. Complete rewrite of code.
  33.         2. Fixed interrupt handler to work properly on AT's and 386's.
  34.         3. Allows interrupt level and MPU base port to be changed.
  35.         4. Allows buffer size to be changed.
  36.         5. Changed code to MASM 5.1 simplified directives
  37.         6. Other minor corrections
  38.  
  39. |
  40.  
  41.  
  42. ;------------------------------------------------------------------------------
  43. ; Equates
  44. ;------------------------------------------------------------------------------
  45.  
  46. reset                   EQU 0FFh
  47. ready_to_receive?       EQU 01000000b   ;Mpu data set ready, active low.
  48. data_available?         EQU 10000000b   ;Mpu data read ready, active low.
  49.  
  50. loop_delay              EQU 0FFFFh      ;Delay for timeouts.
  51.  
  52.  
  53.  
  54.  
  55. ;------------------------------------------------------------------------------
  56.  
  57.         .DATA
  58.  
  59.         extrn   buffer_size:word
  60.  
  61.         public  mpu_data_port,mpu_command_port,mpu_status_port,mpu_irq
  62.         public  irq_mask,eoi,data_in_handler
  63.         public  buffer_ptr,buffer_end,sysex_started,sysex_ended
  64.  
  65. mpu_data_port   dw 0330h                ;Mpu data port address.
  66. mpu_command_port LABEL  WORD            ;Mpu command port address.
  67. mpu_status_port dw 0331h                ;Mpu status port address.
  68. mpu_irq         db 0Ah                  ;Mpu interrupt level
  69. irq_mask        db 00000100b            ;8259 mask for IRQ 2
  70. eoi             dw 0000000001100010b    ;End Of Interrupt mask
  71.  
  72. data_in_handler dw no_op                ;A NULL routine
  73.  
  74. buffer_ptr      dw 0
  75. buffer_end      dw 0
  76.  
  77. sysex_started   db 0                    ;Sysex receive flags
  78. sysex_ended     db 0                    ; "
  79.  
  80. old_brk_add     dw 0,0
  81.  
  82.  
  83.  
  84.  
  85.         .CODE
  86.  
  87. old_int_vect    dw 0,0                  ;Data must be placed here for proper
  88.                                         ; access in the ISR
  89.  
  90. ;______________________________________________________________________________
  91. ;
  92. ;       MPU interrupt handler
  93. ;______________________________________________________________________________
  94.  
  95. mpu_int proc    far
  96.  
  97.         push ds                         ;Save used registers
  98.         push dx
  99.         push ax
  100.  
  101.         mov ax,DGROUP                   
  102.         mov ds,ax                       ;Set DS to data area
  103.  
  104.         mov dx,mpu_status_port          ;Test to see if interrupt was initiated
  105.         in al,dx                        ; by the MPU.
  106.         test al,data_available?
  107.             jz valid_mpu_data           ;Yes, goto MPU routines
  108.  
  109.         pop ax                          ;No, restore registers
  110.         pop dx
  111.         pop ds
  112.  
  113.         jmp dword ptr cs:old_int_vect   ;Exit out to old interrupt handler
  114.  
  115.  
  116. ;Get the data byte from the MPU.
  117. valid_mpu_data:
  118.         sti
  119.         push cx
  120.         push bx
  121.  
  122.         mov dx,mpu_data_port
  123.         in al,dx
  124.  
  125.         call word ptr data_in_handler   ;Changeable data handler
  126.  
  127.  
  128. ;Acknowledge interrupt
  129.         mov ax,eoi
  130.         out 020h,al
  131.         or ah,ah                        ;Is an AT being used?
  132.             jz mi_exit
  133.         mov al,ah                       ;Yes,
  134.         out 0A0h,al                     ; acknowledge AT's second 8259
  135.  
  136. mi_exit:
  137.         pop bx
  138.         pop cx
  139.         pop ax
  140.         pop dx
  141.         pop ds
  142.  
  143.         iret
  144.  
  145. mpu_int endp
  146.  
  147.  
  148.  
  149.  
  150. ;______________________________________________________________________________
  151. ;
  152. ;       Control Break ISR
  153. ;______________________________________________________________________________
  154.  
  155. break_routine   proc    far
  156.  
  157.         clc                             ;Signal that dos is to continue
  158.         ret
  159.  
  160. break_routine   endp
  161.  
  162.  
  163.  
  164.  
  165. ;______________________________________________________________________________
  166. ;
  167. ;       A No Operation routine
  168. ;______________________________________________________________________________
  169.  
  170. no_op   proc
  171.  
  172.         ret
  173.  
  174. no_op   endp
  175.  
  176.  
  177.  
  178. ;______________________________________________________________________________
  179. ;
  180. ;       Queue received mpu data.
  181. ;       input - al = received data.
  182. ;______________________________________________________________________________
  183.  
  184. receive_sysex   proc    uses bx
  185.  
  186.         cmp al,0F0h                     ;Is byte SYSEX F0h beginning?
  187.             jne rs_1                    ;No, go on
  188.         cli
  189.         mov sysex_started,1             ;Yes, set flag
  190.         jmp short rs_3
  191. rs_1:
  192.         cmp sysex_started,1             ;Is a SYSEX currently being inputed?
  193.             jne rs_exit                 ;No, exit
  194.         test al,10000000b               ;Is byte end of SYSEX?
  195.             jz rs_3                     ;No, record SYSEX byte
  196.  
  197. ;EOX, set flags and exit
  198. rs_2:
  199.         cli
  200.         mov sysex_ended,1
  201.         mov sysex_started,0
  202.         mov al,0F7h                     ;Force EOX byte
  203.  
  204. ;Store data bytes into buffer
  205. rs_3:
  206.         cli
  207.         mov bx,buffer_ptr               ;Get buffer
  208.         add bx,buffer_end             
  209.         mov [bx],al                     ;Store SYSEX byte
  210.         inc buffer_end                  ;Increment buffer end
  211.         mov ax,buffer_end
  212.         cmp ax,buffer_size              ;At the end of the buffer?
  213.             jb rs_exit                  ;No, exit
  214.  
  215. ;Buffer overflowed, set last byte to F7h EOX, set flags, and exit
  216.         mov sysex_ended,1
  217.         mov sysex_started,0
  218.         mov byte ptr buffer_end[bx],0F7h ;Force EOX byte
  219.  
  220. rs_exit:
  221.         sti
  222.         ret
  223.  
  224. receive_sysex   endp
  225.  
  226.  
  227.  
  228.  
  229. ;______________________________________________________________________________
  230. ;
  231. ;       void reset_ctrl_brk(void);
  232. ;       Resets the Ctrl-Break ISR
  233. ;______________________________________________________________________________
  234.  
  235. reset_ctrl_brk  proc    uses ds
  236.  
  237.         mov dx,old_brk_add
  238.         mov ds,old_brk_add+2
  239.         mov ax,02523h
  240.         int 021h
  241.  
  242.         ret
  243.  
  244. reset_ctrl_brk  endp
  245.  
  246.  
  247.  
  248. ;______________________________________________________________________________
  249. ;
  250. ;       void reset_mpu_vector(void);
  251. ;       Resets the interrupt vector for the MPU-401
  252. ;______________________________________________________________________________
  253.  
  254. reset_mpu_vector        proc    uses ds
  255.  
  256. ;Mask off the IRQ line first
  257.         cmp mpu_irq,06Fh                ;Using an AT?
  258.             ja rmv_1                    ;Yes, reset second 8259
  259.         cli
  260.         in al,21h                       ;Get current mask
  261.         jmp short $+2                   ;Delay for fast processors
  262.         or al,irq_mask                  ;Set IRQ mask bit
  263.         out 21h,al                      ;Mask IRQ off
  264.         jmp short rmv_2
  265. rmv_1:
  266.         cli
  267.         in al,0A1h                      ;Read 8259 mask
  268.         jmp short $+2                   ;Delay for fast processors
  269.         or al,irq_mask                  ;Set IRQ mask bit
  270.         out 0A1h,al                     ;Mask IRQ off
  271. rmv_2:
  272.         sti
  273.  
  274. ;Then restore the old interrupt vector
  275.         mov ah,25h
  276.         mov al,mpu_irq
  277.         mov dx,old_int_vect             ;Put old offset into DX
  278.         mov ds,old_int_vect+2           ;Put old segment into DS
  279.         int 21h                         ;Reset the vector
  280.         ret                             ;Exit
  281.  
  282. reset_mpu_vector        endp
  283.  
  284.  
  285.  
  286. ;______________________________________________________________________________
  287. ;
  288. ;       int second_8259(void);
  289. ;       Detects a second 8259
  290. ;       Returns SUCCESS = 1, FAILURE = 0.
  291. ;______________________________________________________________________________
  292.  
  293. second_8259     proc    uses es
  294.  
  295.         mov ax,0C000h                   ;Get system configuration
  296.         int 015h                        ;Extended service for AT's
  297.         mov ax,0
  298.             jc s8_exit                  ;Carry is set, service not supported
  299.         cmp byte ptr es:[bx+3],0FBh     ;XT model?
  300.             je s8_exit                  ;Yes, exit
  301.         cmp byte ptr es:[bx+3],0FEh     ;XT model?
  302.             je s8_exit                  ;Yes, exit
  303.         test byte ptr es:[bx+6],040h    ;Is bit for 2nd 8259 set?
  304.             jz s8_exit                  ;No, no second 8259
  305.         mov ax,1                        ;Yes, set AX
  306. s8_exit:
  307.         ret
  308.  
  309. second_8259     endp
  310.  
  311.  
  312.  
  313. ;______________________________________________________________________________
  314. ;
  315. ;       int send_command(int command);
  316. ;       Sends a command to the MPU-401.
  317. ;
  318. ;       returns SUCCESS=-1, FAILURE=0, or command response byte
  319. ;______________________________________________________________________________
  320.  
  321. send_command    proc    command:byte
  322.  
  323.         pushf                           ;Save flags (interrupt flag)
  324.  
  325. ;Wait for MPU to be ready to receive
  326.         mov cx,loop_delay               ;Timeout loop limit
  327.         mov dx,mpu_status_port
  328. sc_1:
  329.         in al,dx
  330.         test al,ready_to_receive?
  331.             jz sc_2                     ;Ready, send byte
  332.         loop sc_1
  333.  
  334. ;MPU not ready, exit with error
  335.         xor ax,ax
  336.         jmp short sc_10
  337.  
  338. ;Send command
  339. sc_2:
  340.         cli                             ;Suspend interrupts
  341.         mov al,command                  ;Get command byte
  342.         out dx,al                       ;Send it
  343.  
  344. ;Wait for the command acknowledge
  345. sc_3:
  346.         mov cx,loop_delay               ;Timeout loop limit
  347.         mov dx,mpu_status_port
  348. sc_4:
  349.         in al,dx
  350.         test al,data_available?
  351.             jz sc_5                     ;Data available, go get it
  352.         loop sc_4                       ;Keep trying
  353.  
  354. ;Command ack not returned, exit with error.
  355.         xor ax,ax                       
  356.         jmp short sc_10
  357.  
  358. ;Get data in
  359. sc_5:
  360.         mov dx,mpu_data_port
  361.         in al,dx
  362.         cmp al,0FEh                     ;Is it an acknowledge?
  363.             je sc_6                     ;Yes, continue
  364.  
  365.         call word ptr data_in_handler   ;No, have the main data handler handle
  366.                                         ; the data byte
  367.         jmp short sc_3                  ;Try again
  368.  
  369. ;Test to see if command sent requires a returned data byte
  370. sc_6:
  371.         mov ax,-1                       ;Successful return code
  372.         cmp command,0A0h                ;Less than A0h?
  373.             jb sc_10                    ;Yes, no data byte returned
  374.         cmp command,0AFh                ;More than AFh?
  375.             ja sc_10                    ;Yes, no data byte returned
  376.  
  377. ;Get returning data byte
  378.         mov cx,loop_delay               ;Timeout loop limit
  379.         mov dx,mpu_status_port
  380. sc_7:
  381.         in al,dx
  382.         test al,data_available?
  383.             jz sc_8                     ;Data available, go get it
  384.         loop sc_7                       ;Try again
  385.  
  386. ;Command failed to return a data byte, exit with error
  387.         xor ax,ax
  388.         jmp short sc_10
  389.  
  390. ;Get data byte
  391. sc_8:
  392.         mov dx,mpu_data_port
  393.         in al,dx
  394.         xor ah,ah
  395.  
  396. ;Exit with return code in AX
  397. sc_10:
  398.         sti                             ;Restore interrupts
  399.         popf                            ;Restore flags
  400.         ret
  401.  
  402. send_command    endp
  403.  
  404.  
  405.  
  406.  
  407. ;______________________________________________________________________________
  408. ;
  409. ;       int send_data(int databyte);
  410. ;       Writes data to the MPU.
  411. ;
  412. ;       Returns SUCCESS=1, FAILURE=0.
  413. ;______________________________________________________________________________
  414.  
  415. send_data       proc    databyte:byte
  416.  
  417.         pushf                           ;Save flags (interrupt flag)
  418.  
  419. ;Wait for MPU to be ready to receive
  420.         mov cx,loop_delay               ;Timeout loop limit
  421.         mov dx,mpu_status_port
  422. sd_1:
  423.         in al,dx
  424.         test al,ready_to_receive?
  425.             jz send_d                   ;MPU is ready, send data
  426.         loop sd_1                       ;MPU not ready yet, try again
  427.  
  428. ;MPU not ready, exit with error
  429.         xor ax,ax
  430.         jmp short sd_exit
  431.  
  432. ;Send the data byte
  433. send_d:
  434.         cli
  435.         mov al,databyte                 ;Get data byte
  436.         mov dx,mpu_data_port
  437.         out dx,al                       ;Send it
  438.         mov ax,1                        ;Set AX for no error
  439.  
  440. sd_exit:
  441.         sti
  442.         popf                            ;Restore flags
  443.         ret
  444.  
  445. send_data       endp
  446.  
  447.  
  448.  
  449.  
  450. ;______________________________________________________________________________
  451. ;
  452. ;       void set_ctrl_brk(void);
  453. ;       Sets the Ctrl-Break ISR
  454. ;______________________________________________________________________________
  455.  
  456. set_ctrl_brk    proc    uses es ds
  457.  
  458.         mov ax,03523h                   ;Get original break address
  459.         int 021h
  460.         mov old_brk_add,bx
  461.         mov old_brk_add+2,es
  462.         mov dx,offset break_routine
  463.         mov ax,seg break_routine        ;Set for new break address
  464.         mov ds,ax
  465.         mov ax,02523h
  466.         int 021h
  467.  
  468.         ret
  469.  
  470. set_ctrl_brk    endp
  471.  
  472.  
  473.  
  474.  
  475. ;______________________________________________________________________________
  476. ;
  477. ;       void set_handler(void (*address)(void));
  478. ;       Sets the data in handler
  479. ;______________________________________________________________________________
  480.  
  481. set_handler     proc    address:word
  482.  
  483.            cli
  484.            mov ax,address
  485.            mov data_in_handler,ax
  486.            sti
  487.  
  488.            ret
  489.  
  490. set_handler     endp
  491.  
  492.  
  493.  
  494. ;______________________________________________________________________________
  495. ;
  496. ;       void set_mpu_vector(void);
  497. ;       Sets the interrupt vector for the MPU-401
  498. ;______________________________________________________________________________
  499.  
  500. set_mpu_vector  proc
  501.  
  502. ;Get current interrupt vector first and save
  503.         mov ah,035h                     
  504.         mov al,mpu_irq                  ;IRQ level to get
  505.         int 21h
  506.         mov cs:old_int_vect,bx          ;Save vector offset.
  507.         mov cs:old_int_vect+2,es        ;Save vector segment.
  508.  
  509. ;Set the IRQ vector to the new Interrupt Service Routine
  510.         push ds                         ;Save DS
  511.         mov ah,025h
  512.         mov al,mpu_irq
  513.         mov dx,offset mpu_int           ;ISR offset
  514.         mov bx,seg mpu_int
  515.         mov ds,bx                       ;ISR segment
  516.         int 21h                         ;Set new vector
  517.         pop ds                          ;Restore DS
  518.  
  519. ;Unmask the proper IRQ line in the Interrupt controller
  520.         cmp mpu_irq,06Fh                ;Using an AT?
  521.             ja smv_1                    ;Yes, unmask second 8259
  522.         cli
  523.         in al,21h                       ;Read 8259 mask
  524.         jmp short $+2                   ;Delay for fast processors
  525.         mov ah,irq_mask                 ;Get new mask
  526.         not ah                          ;Invert for ANDing
  527.         and al,ah                       ;Reset IRQ bit
  528.         out 21h,al                      ;Enable IRQ
  529.         jmp short smv_2
  530. smv_1:
  531.         cli
  532.         in al,0A1h                      ;Read second 8259 mask
  533.         jmp short $+2                   ;Delay for fast processors
  534.         mov ah,irq_mask                 ;Get new mask
  535.         not ah                          ;Invert for ANDing
  536.         and al,ah                       ;Reset IRQ bit
  537.         out 0A1h,al                     ;Enable IRQ
  538. smv_2:
  539.         sti
  540.         ret                             ;Exit
  541.  
  542. set_mpu_vector  endp
  543.  
  544.  
  545.  
  546.         END
  547.