home *** CD-ROM | disk | FTP | other *** search
- DOSSEG
- .MODEL SMALL,C
-
-
- COMMENT |
-
- MIDIINT.ASM -- Assembler subroutines for MIDIEX patch exchange utility
-
-
- COPYRIGHT (C) 1986 John Bailin, Cantus Corporation
-
- Date: 01/02/86
-
- Changed 08/24/86 Jim Bergsten to function using the Microsoft "C"
- compiler. Summary of changes:
- 1. PAGE statement added for better output listing.
- 2. Entry point names prefixed with "_".
- 3. GROUP, PROG, SEGMENT statements changed to match Microsoft
- small model standards.
- 4. Unnecessary stack subtracts and adds removed.
- 5. Other corrections, simplifications...
-
- Changed 11/14/86 by Michael Geary - fixed several bugs
-
- Modified 1/22/88 by Dave Hayes - Added support for GMR bulk dumps by
- increasing size of receive buffer
-
- Note: Linkage conventions assume the Microsoft C compiler small model.
-
-
- Modified 12/5/89 by Mike W. Smith:
- 1. Complete rewrite of code.
- 2. Fixed interrupt handler to work properly on AT's and 386's.
- 3. Allows interrupt level and MPU base port to be changed.
- 4. Allows buffer size to be changed.
- 5. Changed code to MASM 5.1 simplified directives
- 6. Other minor corrections
-
- |
-
-
- ;------------------------------------------------------------------------------
- ; Equates
- ;------------------------------------------------------------------------------
-
- reset EQU 0FFh
- ready_to_receive? EQU 01000000b ;Mpu data set ready, active low.
- data_available? EQU 10000000b ;Mpu data read ready, active low.
-
- loop_delay EQU 0FFFFh ;Delay for timeouts.
-
-
-
-
- ;------------------------------------------------------------------------------
-
- .DATA
-
- extrn buffer_size:word
-
- public mpu_data_port,mpu_command_port,mpu_status_port,mpu_irq
- public irq_mask,eoi,data_in_handler
- public buffer_ptr,buffer_end,sysex_started,sysex_ended
-
- mpu_data_port dw 0330h ;Mpu data port address.
- mpu_command_port LABEL WORD ;Mpu command port address.
- mpu_status_port dw 0331h ;Mpu status port address.
- mpu_irq db 0Ah ;Mpu interrupt level
- irq_mask db 00000100b ;8259 mask for IRQ 2
- eoi dw 0000000001100010b ;End Of Interrupt mask
-
- data_in_handler dw no_op ;A NULL routine
-
- buffer_ptr dw 0
- buffer_end dw 0
-
- sysex_started db 0 ;Sysex receive flags
- sysex_ended db 0 ; "
-
- old_brk_add dw 0,0
-
-
-
-
- .CODE
-
- old_int_vect dw 0,0 ;Data must be placed here for proper
- ; access in the ISR
-
- ;______________________________________________________________________________
- ;
- ; MPU interrupt handler
- ;______________________________________________________________________________
-
- mpu_int proc far
-
- push ds ;Save used registers
- push dx
- push ax
-
- mov ax,DGROUP
- mov ds,ax ;Set DS to data area
-
- mov dx,mpu_status_port ;Test to see if interrupt was initiated
- in al,dx ; by the MPU.
- test al,data_available?
- jz valid_mpu_data ;Yes, goto MPU routines
-
- pop ax ;No, restore registers
- pop dx
- pop ds
-
- jmp dword ptr cs:old_int_vect ;Exit out to old interrupt handler
-
-
- ;Get the data byte from the MPU.
- valid_mpu_data:
- sti
- push cx
- push bx
-
- mov dx,mpu_data_port
- in al,dx
-
- call word ptr data_in_handler ;Changeable data handler
-
-
- ;Acknowledge interrupt
- mov ax,eoi
- out 020h,al
- or ah,ah ;Is an AT being used?
- jz mi_exit
- mov al,ah ;Yes,
- out 0A0h,al ; acknowledge AT's second 8259
-
- mi_exit:
- pop bx
- pop cx
- pop ax
- pop dx
- pop ds
-
- iret
-
- mpu_int endp
-
-
-
-
- ;______________________________________________________________________________
- ;
- ; Control Break ISR
- ;______________________________________________________________________________
-
- break_routine proc far
-
- clc ;Signal that dos is to continue
- ret
-
- break_routine endp
-
-
-
-
- ;______________________________________________________________________________
- ;
- ; A No Operation routine
- ;______________________________________________________________________________
-
- no_op proc
-
- ret
-
- no_op endp
-
-
-
- ;______________________________________________________________________________
- ;
- ; Queue received mpu data.
- ; input - al = received data.
- ;______________________________________________________________________________
-
- receive_sysex proc uses bx
-
- cmp al,0F0h ;Is byte SYSEX F0h beginning?
- jne rs_1 ;No, go on
- cli
- mov sysex_started,1 ;Yes, set flag
- jmp short rs_3
- rs_1:
- cmp sysex_started,1 ;Is a SYSEX currently being inputed?
- jne rs_exit ;No, exit
- test al,10000000b ;Is byte end of SYSEX?
- jz rs_3 ;No, record SYSEX byte
-
- ;EOX, set flags and exit
- rs_2:
- cli
- mov sysex_ended,1
- mov sysex_started,0
- mov al,0F7h ;Force EOX byte
-
- ;Store data bytes into buffer
- rs_3:
- cli
- mov bx,buffer_ptr ;Get buffer
- add bx,buffer_end
- mov [bx],al ;Store SYSEX byte
- inc buffer_end ;Increment buffer end
- mov ax,buffer_end
- cmp ax,buffer_size ;At the end of the buffer?
- jb rs_exit ;No, exit
-
- ;Buffer overflowed, set last byte to F7h EOX, set flags, and exit
- mov sysex_ended,1
- mov sysex_started,0
- mov byte ptr buffer_end[bx],0F7h ;Force EOX byte
-
- rs_exit:
- sti
- ret
-
- receive_sysex endp
-
-
-
-
- ;______________________________________________________________________________
- ;
- ; void reset_ctrl_brk(void);
- ; Resets the Ctrl-Break ISR
- ;______________________________________________________________________________
-
- reset_ctrl_brk proc uses ds
-
- mov dx,old_brk_add
- mov ds,old_brk_add+2
- mov ax,02523h
- int 021h
-
- ret
-
- reset_ctrl_brk endp
-
-
-
- ;______________________________________________________________________________
- ;
- ; void reset_mpu_vector(void);
- ; Resets the interrupt vector for the MPU-401
- ;______________________________________________________________________________
-
- reset_mpu_vector proc uses ds
-
- ;Mask off the IRQ line first
- cmp mpu_irq,06Fh ;Using an AT?
- ja rmv_1 ;Yes, reset second 8259
- cli
- in al,21h ;Get current mask
- jmp short $+2 ;Delay for fast processors
- or al,irq_mask ;Set IRQ mask bit
- out 21h,al ;Mask IRQ off
- jmp short rmv_2
- rmv_1:
- cli
- in al,0A1h ;Read 8259 mask
- jmp short $+2 ;Delay for fast processors
- or al,irq_mask ;Set IRQ mask bit
- out 0A1h,al ;Mask IRQ off
- rmv_2:
- sti
-
- ;Then restore the old interrupt vector
- mov ah,25h
- mov al,mpu_irq
- mov dx,old_int_vect ;Put old offset into DX
- mov ds,old_int_vect+2 ;Put old segment into DS
- int 21h ;Reset the vector
- ret ;Exit
-
- reset_mpu_vector endp
-
-
-
- ;______________________________________________________________________________
- ;
- ; int second_8259(void);
- ; Detects a second 8259
- ; Returns SUCCESS = 1, FAILURE = 0.
- ;______________________________________________________________________________
-
- second_8259 proc uses es
-
- mov ax,0C000h ;Get system configuration
- int 015h ;Extended service for AT's
- mov ax,0
- jc s8_exit ;Carry is set, service not supported
- cmp byte ptr es:[bx+3],0FBh ;XT model?
- je s8_exit ;Yes, exit
- cmp byte ptr es:[bx+3],0FEh ;XT model?
- je s8_exit ;Yes, exit
- test byte ptr es:[bx+6],040h ;Is bit for 2nd 8259 set?
- jz s8_exit ;No, no second 8259
- mov ax,1 ;Yes, set AX
- s8_exit:
- ret
-
- second_8259 endp
-
-
-
- ;______________________________________________________________________________
- ;
- ; int send_command(int command);
- ; Sends a command to the MPU-401.
- ;
- ; returns SUCCESS=-1, FAILURE=0, or command response byte
- ;______________________________________________________________________________
-
- send_command proc command:byte
-
- pushf ;Save flags (interrupt flag)
-
- ;Wait for MPU to be ready to receive
- mov cx,loop_delay ;Timeout loop limit
- mov dx,mpu_status_port
- sc_1:
- in al,dx
- test al,ready_to_receive?
- jz sc_2 ;Ready, send byte
- loop sc_1
-
- ;MPU not ready, exit with error
- xor ax,ax
- jmp short sc_10
-
- ;Send command
- sc_2:
- cli ;Suspend interrupts
- mov al,command ;Get command byte
- out dx,al ;Send it
-
- ;Wait for the command acknowledge
- sc_3:
- mov cx,loop_delay ;Timeout loop limit
- mov dx,mpu_status_port
- sc_4:
- in al,dx
- test al,data_available?
- jz sc_5 ;Data available, go get it
- loop sc_4 ;Keep trying
-
- ;Command ack not returned, exit with error.
- xor ax,ax
- jmp short sc_10
-
- ;Get data in
- sc_5:
- mov dx,mpu_data_port
- in al,dx
- cmp al,0FEh ;Is it an acknowledge?
- je sc_6 ;Yes, continue
-
- call word ptr data_in_handler ;No, have the main data handler handle
- ; the data byte
- jmp short sc_3 ;Try again
-
- ;Test to see if command sent requires a returned data byte
- sc_6:
- mov ax,-1 ;Successful return code
- cmp command,0A0h ;Less than A0h?
- jb sc_10 ;Yes, no data byte returned
- cmp command,0AFh ;More than AFh?
- ja sc_10 ;Yes, no data byte returned
-
- ;Get returning data byte
- mov cx,loop_delay ;Timeout loop limit
- mov dx,mpu_status_port
- sc_7:
- in al,dx
- test al,data_available?
- jz sc_8 ;Data available, go get it
- loop sc_7 ;Try again
-
- ;Command failed to return a data byte, exit with error
- xor ax,ax
- jmp short sc_10
-
- ;Get data byte
- sc_8:
- mov dx,mpu_data_port
- in al,dx
- xor ah,ah
-
- ;Exit with return code in AX
- sc_10:
- sti ;Restore interrupts
- popf ;Restore flags
- ret
-
- send_command endp
-
-
-
-
- ;______________________________________________________________________________
- ;
- ; int send_data(int databyte);
- ; Writes data to the MPU.
- ;
- ; Returns SUCCESS=1, FAILURE=0.
- ;______________________________________________________________________________
-
- send_data proc databyte:byte
-
- pushf ;Save flags (interrupt flag)
-
- ;Wait for MPU to be ready to receive
- mov cx,loop_delay ;Timeout loop limit
- mov dx,mpu_status_port
- sd_1:
- in al,dx
- test al,ready_to_receive?
- jz send_d ;MPU is ready, send data
- loop sd_1 ;MPU not ready yet, try again
-
- ;MPU not ready, exit with error
- xor ax,ax
- jmp short sd_exit
-
- ;Send the data byte
- send_d:
- cli
- mov al,databyte ;Get data byte
- mov dx,mpu_data_port
- out dx,al ;Send it
- mov ax,1 ;Set AX for no error
-
- sd_exit:
- sti
- popf ;Restore flags
- ret
-
- send_data endp
-
-
-
-
- ;______________________________________________________________________________
- ;
- ; void set_ctrl_brk(void);
- ; Sets the Ctrl-Break ISR
- ;______________________________________________________________________________
-
- set_ctrl_brk proc uses es ds
-
- mov ax,03523h ;Get original break address
- int 021h
- mov old_brk_add,bx
- mov old_brk_add+2,es
- mov dx,offset break_routine
- mov ax,seg break_routine ;Set for new break address
- mov ds,ax
- mov ax,02523h
- int 021h
-
- ret
-
- set_ctrl_brk endp
-
-
-
-
- ;______________________________________________________________________________
- ;
- ; void set_handler(void (*address)(void));
- ; Sets the data in handler
- ;______________________________________________________________________________
-
- set_handler proc address:word
-
- cli
- mov ax,address
- mov data_in_handler,ax
- sti
-
- ret
-
- set_handler endp
-
-
-
- ;______________________________________________________________________________
- ;
- ; void set_mpu_vector(void);
- ; Sets the interrupt vector for the MPU-401
- ;______________________________________________________________________________
-
- set_mpu_vector proc
-
- ;Get current interrupt vector first and save
- mov ah,035h
- mov al,mpu_irq ;IRQ level to get
- int 21h
- mov cs:old_int_vect,bx ;Save vector offset.
- mov cs:old_int_vect+2,es ;Save vector segment.
-
- ;Set the IRQ vector to the new Interrupt Service Routine
- push ds ;Save DS
- mov ah,025h
- mov al,mpu_irq
- mov dx,offset mpu_int ;ISR offset
- mov bx,seg mpu_int
- mov ds,bx ;ISR segment
- int 21h ;Set new vector
- pop ds ;Restore DS
-
- ;Unmask the proper IRQ line in the Interrupt controller
- cmp mpu_irq,06Fh ;Using an AT?
- ja smv_1 ;Yes, unmask second 8259
- cli
- in al,21h ;Read 8259 mask
- jmp short $+2 ;Delay for fast processors
- mov ah,irq_mask ;Get new mask
- not ah ;Invert for ANDing
- and al,ah ;Reset IRQ bit
- out 21h,al ;Enable IRQ
- jmp short smv_2
- smv_1:
- cli
- in al,0A1h ;Read second 8259 mask
- jmp short $+2 ;Delay for fast processors
- mov ah,irq_mask ;Get new mask
- not ah ;Invert for ANDing
- and al,ah ;Reset IRQ bit
- out 0A1h,al ;Enable IRQ
- smv_2:
- sti
- ret ;Exit
-
- set_mpu_vector endp
-
-
-
- END
-