home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / assemblr / library / asm_kit / host.asm < prev    next >
Assembly Source File  |  1985-11-06  |  17KB  |  386 lines

  1.                 PAGE    66,132
  2.                 TITLE   HOST - Link communication device to console using interrupts
  3. ;       
  4. ;       Program to install resident communications interrupt driver,
  5. ;       and link it into the keyboard/video interrupt routines.
  6. ;
  7. ;       We must define a general interrupt handler for the COM1 port,
  8. ;       which will input characters directly into BIOS's keyboard input
  9. ;       (typeahead) buffer.  This buffer is defined by pointers at offset
  10. ;       001A (start of buffer pointer), and 001C (end of buffer pointer).
  11. ;       The data segment for all of this is 0040.  There is a BIOS routine
  12. ;       at F000:E875 which handles a 15-char circular buffer wrap-around.
  13. ;       We should copy it.  We must compare [001A] with [001C] after calling
  14. ;       the buffer wrap routine to see if the buffer full.  If so, it'd
  15. ;       be nice to send a bell to the caller, but im not sure this is the
  16. ;       place to do it (inside an interrupt routine).
  17. ;
  18. ;       Note that we assume the COM1 port is already initialized (RS232 stuff)
  19. ;
  20. ;       Note that this routine must also detect change of line status and
  21. ;       have appropriate logic for indicating and handling loss of carrier,
  22. ;       and other delta indications in the line status register.
  23. ;
  24. ;       This takes care of the keyboard input end of the communication 
  25. ;       interface.
  26. ;
  27. ;       For linking screen output, I guess we just intercept the old
  28. ;       screen output 'interrupt' vector, located at 0000:0040-:0043.
  29. ;       There is no reason to buffer the output, so the intercept routine
  30. ;       will first output the byte to the UART (if UART accepting), then
  31. ;       pass control on to the former screen handler.
  32. ;
  33. ; The record-type HOSTFLAGS contains duplex, CR/LF, bell enable, and
  34. ; timeout specification.  Timeout determines iff forced disconnect for
  35. ; lack of user input enablad. 
  36. hostflags       record  duplex:1,crlf:1,bell:1,cls:1,timeout:1
  37. discflags       record  rlsd:1,ri:1,dsr:1,cts:1
  38. ;       
  39. comment % 
  40. ; Structure HOSTCB contains terminal setting values:
  41. hostcb          struc
  42. clsequence      db      0,12    ; default cls sequence
  43. timeout_at      db      128     ; halfway through the timeout scale default
  44. baudrate_lsb    db      80h
  45. baudrate_msb    db      1       ; default UART baud rate = 300 baud
  46. userid          dt      ?       ; ten bytes?  for user identification
  47. screen_size     db      24      ; # of lines on screen
  48. screen_width    db      80      ; # of chars per line on screen
  49. hostcb          ends
  50. ;
  51. %
  52. ;
  53. inport          macro   port
  54.                 lea     dx,port ; get port offset into dx
  55.                 in      al,dx
  56.                 endm
  57. ;
  58. outport         macro   port
  59.                 lea     dx,port ; get port offset into dx
  60.                 out     dx,al
  61.                 endm
  62. ;
  63. ; Set up references to the system interrupt vector table: 
  64. ;
  65. ;
  66. int_table       segment at 0h
  67.                 org     10H*4           ; address of video driver vector
  68. int10           label   word
  69.                 org     0CH*4           ; address of comm interrupt vector
  70. int0c           label   word
  71. int_table       ends
  72. ; Set up references to BIOS keyboard and COM system table.
  73. ;
  74. ;
  75. sys_table       segment at 40h
  76. rs232_base      dw      4 dup(?)
  77.                 org     1Ah
  78. buffer_head     dw      ?
  79. buffer_tail     dw      ?
  80. kb_buffer       dw      16 dup(?)
  81. kb_buffer_end   label   word
  82.                 org     71h
  83. bios_break      db      ?
  84. sys_table       ends
  85. ;
  86. ;
  87. comgrp          group   host,com_init
  88. ;
  89. host            segment 
  90.                 assume  cs:comgrp
  91. ;
  92. ; Proc to bump BIOS's keyboard buffer pointer, in DI.
  93. advance_kb      proc    far
  94.                 add     di,2
  95.                 cmp     di,offset kb_buffer_end
  96.                 jnz     noneed
  97.                 mov     di,offset kb_buffer     ; wrap if at end of buffer
  98. noneed:         ret
  99. advance_kb      endp
  100. ;
  101. eoi             equ     20h     ; end of interrupt value for 8259 controller
  102. ;
  103. baud_data       equ     0[BX]   ; baud rate selector and data register in UART
  104. baud_msb_int    equ     1[BX]   ; baud rate selector MSB and interrupt enable
  105. interrupt_id    equ     2[BX]   ; interrupt identification register
  106. line_control    equ     3[BX]   ; line control register 
  107. modem_control   equ     4[BX]   ; modem control register
  108. line_status     equ     5[BX]   ; line status register
  109. modem_status    equ     6[BX]   ; modem status register 
  110. ;
  111. comint          proc    far
  112.                 assume  cs:comgrp,ds:sys_table
  113.                 sti
  114.                 push    ax
  115.                 push    bx
  116.                 push    cx
  117.                 push    dx
  118.                 push    si
  119.                 push    di
  120.                 push    ds
  121.                 push    es
  122.                 mov     ax,sys_table            ; point to system table segment
  123.                 mov     ds,ax
  124.                 mov     bx,rs232_base           ; get base port for COM1 device
  125. ;
  126. ; Begin code to interrogate interrupt situation: "Why were we called ?"
  127. ;
  128. ; Note that we have set interrupts for change in modem status, and 
  129. ; receiver data-ready.  This means either he hung up (or ?) or he 
  130. ; just sent us a character.  The interrupt-id register will tell us which.
  131. ;
  132.                 inport  interrupt_id    ; read the interrupt id register
  133.                 shr     al,1            ; of course an interrupt occurred!
  134.                 and     al,00000011b    ; lower 2 bits active.
  135.                 jz      delta_stat      ; go interpret change in modm stat
  136.                 dec     al              ; test for transmitter hold empty.   
  137.                 jz      no_action       ; we're not processing these here.
  138.                 dec     al              ; test for received char?
  139.                 jz      get_com_char    ; read char from com device.
  140.                 dec     al              ; Break or error received.      
  141.                 jz      brk_rcd
  142. no_action:      mov     al,eoi          ; end-of-inerrupt code to al
  143.                 out     20h,al          ; tell controller to cancel interrupt
  144.                 pop     es
  145.                 pop     ds
  146.                 pop     di
  147.                 pop     si
  148.                 pop     dx
  149.                 pop     cx
  150.                 pop     bx
  151.                 pop     ax
  152.                 iret                    ; return to previous task.
  153. ;
  154. ; Break was received (or there was a line error)
  155. ; IF break received, simulate console CONTROL-BREAK function.
  156. ;
  157. brk_rcd:        inport  line_status
  158.                 and     al,00010000b    ; break detected ?
  159.                 jz      no_action       ; we're ignoring other errors now.
  160.                 mov     di,offset kb_buffer     ; load kb_buffer start
  161.                 mov     buffer_head,di  ; reset buffer to empty
  162.                 mov     buffer_tail,di
  163.                 mov     bios_break,80h  ; set break byte.
  164.                 int     1bh             ; do break service
  165.                 jmp     no_action       ; return ourselves
  166. ;
  167. get_com_char:   inport  baud_data       ; read byte from port
  168.                 mov     di,buffer_tail  ; end of kb buff
  169.                 mov     si,di           ; store it
  170.                 call    advance_kb      ; try to make space for it
  171.                 cmp     di,buffer_head  ; has buffer wrapped ?
  172.                 jz      kb_full         ; buffer full!
  173.                 xor     ah,ah           ; convert al -> ax
  174.                 mov     [si],ax         ; store it in BIOS keyboard buffer
  175.                 mov     buffer_tail,di  ; update buffer
  176.                 jmp     no_action       ; return to caller
  177. ;
  178. kb_full:        jmp     no_action       ; we'll eventually BEEP the user here.
  179. ;
  180. delta_stat:     inport  modem_status
  181.                 mov     cs:c_modem_status,al    ; remember new modem status     
  182.  
  183.                 jmp     no_action
  184. ;
  185. comint          endp
  186. ;
  187. ;
  188. console_out     proc    far
  189.                 assume  cs:host,ds:sys_table
  190.                 jmp     begin_console   ; jump around ID field
  191. console_id:     db      'HOST'          ; our identification field
  192. begin_console:  cmp     ah,14           ; is it 'print tty' function ?
  193.                 jz      take_over       ; yes, intercept it
  194.                 cmp     ah,10           ; it is 'print over char' function ?
  195.                 jz      take_over       ; yes, lets intercept it too
  196. normal_tty:     jmp     cs:old_int10    ; go to normal int 10 handler
  197. take_over:      push    ax
  198.                 push    di
  199.                 push    si
  200.                 push    dx
  201.                 push    bx
  202.                 push    cx
  203.                 push    ds
  204.                 test    cs:c_modem_status,10000000b     ; is there a connection?
  205.  
  206.                 jz      bypass_user             ; no, we wont try to send 
  207.                 mov     cl,al           ; save value for output
  208.                 mov     ax,sys_table
  209.                 mov     ds,ax           ; prepare to examine UART
  210.                 mov     bx,rs232_base   ; get base address of com port
  211. send_char:      inport  line_status     ; see if ready to send byte.
  212.                 and     al,00100000b    ; test xmit hold reg empty ?
  213.                 jz      send_char       ; no, wait for it
  214.                 mov     al,cl           ; get back char to send
  215.                 outport baud_data       ; output byte to com1 iff ready
  216. bypass_user:    pop     ds
  217.                 pop     cx
  218.                 pop     bx
  219.                 pop     dx
  220.                 pop     si
  221.                 pop     di
  222.                 pop     ax
  223.                 jmp     normal_tty
  224. ;
  225. console_out     endp
  226. ;
  227. old_int10       dd      ?               ; doubleword pointer to old int10
  228. ;
  229. ; Set up our internal status flags:
  230. c_modem_status  discflags       <?,?,?,?>
  231. ; Set up user parm area
  232. user_flags      hostflags <1,1,1,1,1>   ; user logon and termninal flags
  233. user_disc       discflags <1,0,1,0>     ; lines for continual test/disconnect
  234. ;user_parms     hostcb <,,,,,,>         ; user logon and terminal characteristics
  235. user_parms      equ     $
  236. ;
  237. ; Structure HOSTCB contains terminal setting values:
  238. clsequence      db      0,12    ; default cls sequence
  239. timeout_at      db      128     ; halfway through the timeout scale default
  240. baudrate_lsb    db      80h
  241. baudrate_msb    db      1       ; default UART baud rate = 300 baud
  242. userid          dt      ?       ; ten bytes?  for user identification
  243. screen_size     db      24      ; # of lines on screen
  244. screen_width    db      80      ; # of chars per line on screen
  245. ;
  246. end_com         equ     this    byte    ; return to dos, stay res.
  247. ;
  248. host            ends
  249. ;
  250. com_init        segment
  251.                 assume  cs:com_init,ds:sys_table,es:comgrp      
  252. host_init       proc    far
  253. ;
  254. ; We'll assume that the UART has been initialized for now
  255. ; we will install the interrupt driven keyboard link and 
  256. ; the INT 10H intercept driver. 
  257. ;
  258.                 cli                             ; off ints so dont get caught
  259.                 push    ds                      ; save pointer to dos psp
  260.                 mov     ax,50h                  ; offset to int21 in psp
  261.                 push    ax
  262.                 mov     ax,host                 ; point to driver segment
  263.                 mov     es,ax
  264.                 mov     ax,sys_table            ; point to system table
  265.                 mov     ds,ax
  266.                 mov     bx,rs232_base           ; get base of port addresses
  267.                 inport  modem_status
  268.                 mov     es:c_modem_status,al    ; initialize out record of it
  269.                 mov     al,00001011b            ; set MCR for interrupts
  270.                 outport modem_control
  271.                 mov     al,00001101b            ; desired interrupt fields
  272.                 outport baud_msb_int            ; enable those interrupts
  273.                 mov     ax,int_table            ; get interrupt table segment
  274.                 mov     ds,ax
  275.                 assume  ds:int_table
  276.                 mov     dx,int10                ; get offset for old int10
  277.                 push    dx
  278.                 push    bx
  279.                 push    ds
  280.                 xchg    bx,dx                   ; put offset into bx
  281.                 mov     ax,host                 ; address ID field
  282.                 mov     ds,ax
  283.                 mov     dx,[bx+3]               ; look at our ID field1
  284.                 cmp     dx,'HO'                 ; Could it be us ?
  285.                 jnz     notus                   ; nop.
  286.                 mov     dx,[bx+5]               ; Look at field 2 to be sure
  287.                 cmp     dx,'ST'
  288. notus:          pop     ds
  289.                 pop     bx
  290.                 pop     dx
  291.                 jnz     itsok
  292.                 jmp     reject_init             ; We were already installed
  293. itsok:          mov     es:old_int10,dx         ; fill in
  294.                 mov     dx,int10+2              ; get segment for old int10
  295.                 mov     es:old_int10+2,dx       ; fill in       
  296.                 mov     dx,host                 ; get new seg for int10
  297.                 mov     int10+2,dx              ; store it
  298.                 mov     dx,offset console_out   ; get new offset for int10
  299.                 mov     int10,dx                ; store it
  300.                 mov     dx,host                 ; get new seg for int0c
  301.                 mov     int0c+2,dx              ; store it
  302.                 mov     dx,offset comint        ; and offset
  303.                 mov     int0c,dx                ; and offset
  304.                 in      al,21h                  ; read from IMR
  305.                 and     al,0efh ; turn off b4=enable comm interrupts
  306.                 out     21h,al                  ; in 8259 controller
  307.                 mov     al,0                    ; retcode = 0
  308.                 mov     dx,offset comgrp:end_com; point to end of program
  309.                 mov     cl,4                    ; for devide by 16
  310.                 shr     dx,cl                   ; turn into # segments
  311.                 add     dx,100                  ; leave 1K for dos environ ????
  312.                 mov     ah,31h                  ; tell DOS to save this pgm.
  313.                 jmp     ok_init                 ; successful initialization
  314.  
  315. ;
  316. exit_init:      ret                             ; far ret to dos function call
  317. ;
  318. ok_init:        sti                             ; re-enable the interrupts
  319. ;               call    print_inline
  320. ;               db      'pcHOST 1.0 - 09/29/83 - M.R.',13,10
  321. ;               db      'Communication console link loaded and initialized.'
  322. ;               db      13,10,10,0
  323.                 jmp     exit_init
  324. ;
  325. reject_init:    sti                             ; re-enable the interrupts
  326. ;               call    print_inline
  327. ;               db      'HOST driver is already installed.',13,10
  328. ;               db      'Nothing done.',13,10,0
  329. ;               pop     ax              ; pop off 'stay resident' return
  330. ;               xor     ax,ax           ; make 'terminate overlay' return
  331. ;               push    ax
  332.                 jmp     exit_init
  333. ;
  334. ; Print_Inline proc:  Prints ASCIIZ text at offset on NEAR STACK.  
  335. ; Returns to address following delimiting zero of ASCIIZ string.
  336. ; Resgisters destroyed: SI.
  337. print_inline    proc
  338.                 pop     si
  339.                 push    ax
  340. check_char:     mov     al,[si]
  341.                 inc     si
  342.                 or      al,al
  343.                 jz      msg_done
  344.                 call    print_chr
  345.                 jmp     check_char
  346. msg_done:       pop     ax      ; get back ax
  347.                 push    si      ; is this the ONLY way to jump
  348.                 ret             ; to an address pointed to by SI ?
  349. print_inline    endp
  350. ;
  351. ; Print_Chr proc: prints char in AL via INT 10H.
  352. ; Registers destroyed:  AX.
  353. print_chr       proc
  354.                 mov     ah,14           ; and AH for PRINT TTY function
  355.                 call    int_10h         ; print char to tty
  356.                 ret
  357. print_chr       endp
  358. ;
  359. ; INT_10H proc:  Intercept to the BIOS INT 10H 
  360. ;                but saving all registers.  Also, set BX=0 to select current
  361. ;                screen page.  All registers except BX must be set prior call.
  362. ;  Registers destroyed: None.   
  363. int_10h         proc
  364.                 push    bx      
  365.                 push    ax
  366.                 mov     bx,0            ; select screen zero
  367.                 push    bp
  368.                 push    di
  369.                 push    si
  370.                 int     10h
  371.                 pop     si
  372.                 pop     di
  373.                 pop     bp
  374.                 pop     ax
  375.                 pop     bx
  376.                 ret
  377. int_10h         endp
  378. ;
  379. host_init       endp
  380. com_init        ends
  381. ;
  382. ;
  383.                 end     host_init
  384.  
  385.