source: xtideuniversalbios/trunk/Assembly_Library/Src/Serial/SerialServer.asm @ 526

Last change on this file since 526 was 526, checked in by krille_n_@…, 11 years ago

Changes:

  • Update of the copyright notices to include the year 2013.
File size: 12.4 KB
Line 
1; Project name  :   Assembly Library
2; Description   :   Serial Server Support
3
4;
5; XTIDE Universal BIOS and Associated Tools
6; Copyright (C) 2009-2010 by Tomi Tilli, 2011-2013 by XTIDE Universal BIOS Team.
7;
8; This program is free software; you can redistribute it and/or modify
9; it under the terms of the GNU General Public License as published by
10; the Free Software Foundation; either version 2 of the License, or
11; (at your option) any later version.
12;
13; This program is distributed in the hope that it will be useful,
14; but WITHOUT ANY WARRANTY; without even the implied warranty of
15; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16; GNU General Public License for more details.
17; Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
18;
19
20
21%include "SerialServer.inc"
22
23; Section containing code
24SECTION .text
25
26;--------------------------------------------------------------------
27; SerialServer_SendReceive:
28;   Parameters:
29;       DX:     Packed I/O port and baud rate
30;       ES:SI:  Ptr to buffer (for data transfer commands)
31;       SS:BP:  Ptr to SerialServer_Command structure
32;   Returns:
33;       AH:     INT 13h Error Code
34;       CX:     Number of 512-byte blocks transferred
35;       CF:     Cleared if success, Set if error
36;   Corrupts registers:
37;       AL, BX, CX, DX
38;--------------------------------------------------------------------
39SerialServer_SendReceive:
40
41        push    si
42        push    di
43        push    bp
44
45;
46; Unpack I/O port and baud from DPT
47;       Port to DX for the remainder of the routine (+/- different register offsets)
48;       Baud in CH until UART initialization is complete
49;
50        mov     ch,dh
51        xor     dh,dh
52        eSHL_IM dx, 2           ; shift from one byte to two
53
54        mov     al,[bp+SerialServer_Command.bSectorCount]
55        mov     ah,[bp+SerialServer_Command.bCommand]
56
57;
58; Command byte and sector count live at the top of the stack, pop/push are used to access
59;
60        push    ax              ; save sector count for return value
61        push    ax              ; working copy on the top of the stack
62
63%ifndef EXCLUDE_FROM_XTIDE_UNIVERSAL_BIOS   ; DF already cleared in Int13h.asm
64        cld
65%endif
66
67;----------------------------------------------------------------------
68;
69; Initialize UART
70;
71; We do this each time since DOS (at boot) or another program may have
72; decided to reprogram the UART
73;
74        mov     bl,dl           ; setup BL with proper values for read/write loops (BH comes later)
75
76        mov     al,83h
77        add     dl, Serial_UART_lineControl ; Clears CF
78        out     dx,al
79
80        mov     al,ch
81        mov     dl,bl           ; divisor low
82        out     dx,al
83
84%ifdef USE_UNDOC_INTEL
85        eSALC   ; Clear AL using CF
86%else
87        xor     ax,ax
88%endif
89        inc     dx              ; divisor high
90        push    dx
91        out     dx,al
92
93        mov     al,047h
94        inc     dx              ;  fifo
95        out     dx,al
96
97        mov     al,03h
98        inc     dx              ;  linecontrol
99        out     dx,al
100
101        mov     al,0bh
102        inc     dx              ;  modemcontrol
103        out     dx,al
104
105        inc     dx              ;  linestatus (no output now, just setting up BH for later use)
106        mov     bh,dl
107
108        pop     dx              ; base, interrupts disabled
109%ifdef USE_UNDOC_INTEL
110        eSALC   ; Clear AL using CF
111%else
112        xor     ax,ax
113%endif
114        out     dx,al
115
116;----------------------------------------------------------------------
117;
118; Send Command
119;
120; Sends first six bytes of IDEREGS_AND_INTPACK as the command
121;
122        push    es              ; save off real buffer location
123        push    si
124
125        mov     si,bp           ; point to IDEREGS for command dispatch;
126        push    ss
127        pop     es
128
129        mov     di,0ffffh       ; initialize checksum for write
130        mov     bp,di
131
132        mov     cx,4            ; writing 3 words (plus 1)
133
134        cli                     ; interrupts off...
135
136        call    SerialServer_WriteProtocol.entry
137
138        pop     di              ; restore real buffer location (note change from SI to DI)
139                                ; Buffer is primarily referenced through ES:DI throughout, since
140                                ; we need to store (read sector) faster than we read (write sector)
141        pop     es
142
143        pop     ax              ; load command byte (done before call to .nextSector on subsequent iterations)
144        push    ax
145
146%ifndef SERIALSERVER_NO_ZERO_SECTOR_COUNTS
147        test    al,al           ; if no sectors to be transferred, wait for the ACK checksum on the command
148        jz      .zeroSectors
149%endif
150
151;
152; Top of the read/write loop, one iteration per sector
153;
154.nextSector:
155        mov     si,0ffffh       ; initialize checksum for read or write
156        mov     bp,si
157
158        mov     cx,0101h        ; writing 256 words (plus 1)
159
160        shr     ah,1            ; command byte, are we doing a write?
161        jnc     .readEntry
162
163        xchg    si,di           ; swap pointer and checksum, will be re-swap'ed in WriteProtocol
164        call    SerialServer_WriteProtocol.entry
165
166.zeroSectors:
167        inc     cx              ; CX = 1 now (0 out of WriteProtocol)
168        jmp     .readEntry
169
170;----------------------------------------------------------------------
171;
172; Timeout
173;
174; To save code space, we use the contents of DL to decide which byte in the word to return for reading.
175;
176.readTimeout:
177        push    ax              ; not only does this push preserve AX (which we need), but it also
178                                ; means the stack has the same number of bytes on it as when we are
179                                ; sending a packet, important for error cleanup and exit
180        mov     ah,1
181        call    SerialServer_WaitAndPoll_Read
182        pop     ax
183        test    dl,1
184        jz      .readByte1Ready
185        jmp     .readByte2Ready
186
187;----------------------------------------------------------------------------
188;
189; Read Block (without interrupts, used when there is a FIFO, high speed)
190;
191; NOTE: This loop is very time sensitive.  Literally, another instruction
192; cannot be inserted into this loop without us falling behind at high
193; speed (460.8K baud) on a 4.77Mhz 8088, making it hard to receive
194; a full 512 byte block.
195;
196.readLoop:
197        stosw                   ; store word in caller's data buffer
198
199        add     bp, ax          ; update Fletcher's checksum
200        adc     bp, 0
201        add     si, bp
202        adc     si, 0
203
204.readEntry:
205        mov     dl,bh
206        in      al,dx
207        shr     al,1            ; data ready (byte 1)?
208        mov     dl,bl           ; get ready to read data
209        jnc     .readTimeout    ; nope not ready, update timeouts
210
211;
212; Entry point after initial timeout.  We enter here so that the checksum word
213; is not stored (and is left in AX after the loop is complete).
214;
215.readByte1Ready:
216        in      al, dx          ; read data byte 1
217
218        mov     ah, al          ; store byte in ah for now
219
220;
221; note the placement of this reset of dl to bh, and that it is
222; before the return, which is assymetric with where this is done
223; above for byte 1.  The value of dl is used by the timeout routine
224; to know which byte to return to (.read_byte1_ready or
225; .read_byte2_ready)
226;
227        mov     dl,bh
228
229        in      al,dx
230        shr     al,1            ; data ready (byte 2)?
231        jnc     .readTimeout
232.readByte2Ready:
233        mov     dl,bl
234        in      al, dx          ; read data byte 2
235
236        xchg    al, ah          ; ah was holding byte 1, reverse byte order
237
238        loop    .readLoop
239
240        sti                     ; interrupts back on ASAP, between packets
241
242;
243; Compare checksums
244;
245        xchg    ax,bp
246        xor     ah,al
247        mov     cx,si
248        xor     cl,ch
249        mov     al,cl
250        cmp     ax,bp
251        jnz     SerialServer_OutputWithParameters_Error
252
253        pop     ax              ; sector count and command byte
254        dec     al              ; decrement sector count
255        push    ax              ; save
256        jz      SerialServer_OutputWithParameters_ReturnCodeInAL
257
258        cli                     ; interrupts back off for ACK byte to host
259                                ; (host could start sending data immediately)
260        out     dx,al           ; ACK with next sector number
261
262        jmp     short .nextSector
263
264;---------------------------------------------------------------------------
265;
266; Cleanup, error reporting, and exit
267;
268
269;
270; Used in situations where a call is underway, such as with SerialServer_WaitAndPoll
271;
272ALIGN JUMP_ALIGN
273SerialServer_OutputWithParameters_ErrorAndPop4Words:
274        add     sp,8
275;;; fall-through
276
277ALIGN JUMP_ALIGN
278SerialServer_OutputWithParameters_Error:
279;----------------------------------------------------------------------
280;
281; Clear read buffer
282;
283; In case there are extra characters or an error in the FIFO, clear it out.
284; In theory the initialization of the UART registers above should have
285; taken care of this, but I have seen cases where this is not true.
286;
287        xor     cx,cx                   ; timeout this clearing routine, in case the UART isn't there
288.clearBuffer:
289        mov     dl,bh
290        in      al,dx
291        mov     dl,bl
292        test    al,08fh
293        jz      .clearBufferComplete
294        test    al,1
295        in      al,dx
296        loopnz  .clearBuffer            ; note ZF from test above
297
298.clearBufferComplete:
299        mov     al, 3           ;  error return code and CF (low order bit)
300
301ALIGN JUMP_ALIGN
302SerialServer_OutputWithParameters_ReturnCodeInAL:
303%if 0
304        sti                     ;  all paths here will already have interrupts turned back on
305%endif
306        mov     ah, al          ;  for success, AL will already be zero
307
308        pop     bx              ;  recover "ax" (command and count) from stack
309        pop     cx              ;  recover saved sector count
310        xor     ch, ch
311        sub     cl, bl          ; subtract off the number of sectors that remained
312
313        pop     bp
314        pop     di
315        pop     si
316
317        shr     ah, 1           ; shift down return code and CF
318
319        ret
320
321;--------------------------------------------------------------------
322; SerialServer_WriteProtocol
323;
324; NOTE: As with its read counterpart, this loop is very time sensitive.
325; Although it will still function, adding additional instructions will
326; impact the write throughput, especially on slower machines.
327;
328;   Parameters:
329;       ES:SI:  Ptr to buffer
330;       CX:     Words to write, plus 1
331;       BP/DI:  Initialized for Checksum (-1 in each)
332;       DH:     I/O Port high byte
333;       BX:     LineStatus Register address (BH) and Receive/Transmit Register address (BL)
334;   Returns:
335;       BP/SI:  Checksum for written bytes, compared against ACK from server in .readLoop
336;       CX:     Zero
337;       DL:     Receive/Transmit Register address
338;       ES:DI:  Ptr to buffer
339;   Corrupts registers:
340;       AX
341;--------------------------------------------------------------------
342ALIGN JUMP_ALIGN
343SerialServer_WriteProtocol:
344.writeLoop:
345        es lodsw                ; fetch next word
346
347        out     dx,al           ; output first byte
348
349        add     bp,ax           ; update checksum
350        adc     bp,0
351        add     di,bp
352        adc     di,0
353
354        mov     dl,bh           ; transmit buffer empty?
355        in      al,dx
356        test    al,20h
357        jz      .writeTimeout2  ; nope, use our polling routine
358
359.writeByte2Ready:
360        mov     dl,bl
361        mov     al,ah           ; output second byte
362        out     dx,al
363
364.entry:
365        mov     dl,bh           ; transmit buffer empty?
366        in      al,dx
367        test    al,20h
368        mov     dl,bl
369        jz      .writeTimeout1  ; nope, use our polling routine
370
371.writeByte1Ready:
372        loop    .writeLoop
373
374        mov     ax,di           ; fold Fletcher's checksum and output
375        xor     al,ah
376        out     dx,al           ; byte 1
377
378        call    SerialServer_WaitAndPoll_Write
379
380        mov     ax,bp
381        xor     al,ah
382        out     dx,al           ; byte 2
383
384        xchg    si,di           ; preserve checksum word in si, move pointer back to di
385
386        ret
387
388.writeTimeout2:
389        mov     dl,ah           ; need to preserve AH, but don't need DL (will be reset upon return)
390        call    SerialServer_WaitAndPoll_Write
391        mov     ah,dl
392        jmp     .writeByte2Ready
393
394.writeTimeout1:
395        ePUSH_T ax, .writeByte1Ready    ; return address for ret at end of SC_writeTimeout2
396;;; fall-through
397
398;--------------------------------------------------------------------
399; SerialServer_WaitAndPoll
400;
401;   Parameters:
402;       AH:     UART_LineStatus bit to test (20h for write, or 1h for read)
403;               One entry point fills in AH with 20h for write
404;       DX:     Port address (OK if already incremented to UART_lineStatus)
405;       BX:
406;       Stack:  2 words on the stack below the command/count word
407;   Returns:
408;       Returns when desired UART_LineStatus bit is cleared
409;       Jumps directly to error exit if timeout elapses (and cleans up stack)
410;   Corrupts registers:
411;       AX
412;--------------------------------------------------------------------
413
414SerialServer_WaitAndPoll_SoftDelayTicks   EQU   20
415
416ALIGN JUMP_ALIGN
417SerialServer_WaitAndPoll_Write:
418        mov     ah,20h
419;;; fall-through
420
421ALIGN JUMP_ALIGN
422SerialServer_WaitAndPoll_Read:
423        push    cx
424        push    dx
425
426;
427; We first poll in a tight loop, interrupts off, for the next character to come in/be sent
428;
429        xor     cx,cx
430.readTimeoutLoop:
431        mov     dl,bh
432        in      al,dx
433        test    al,ah
434        jnz     .readTimeoutComplete
435        loop    .readTimeoutLoop
436
437;
438; If that loop completes, then we assume there is a long delay involved, turn interrupts back on
439; and wait for a given number of timer ticks to pass.
440;
441        sti
442        mov     cl,SerialServer_WaitAndPoll_SoftDelayTicks
443%ifndef SERIALSERVER_TIMER_LOCATION
444        call    Timer_InitializeTimeoutWithTicksInCL
445%else
446        push    ax
447        push    bx
448        mov     ax,SerialServer_WaitAndPoll_SoftDelayTicks
449        mov     bx,SERIALSERVER_TIMER_LOCATION
450        call    TimerTicks_InitializeTimeoutFromAX
451        pop     bx
452        pop     ax
453%endif
454
455.WaitAndPoll:
456%ifndef SERIALSERVER_TIMER_LOCATION
457        call    Timer_SetCFifTimeout
458%else
459        push    ax
460        push    bx
461        mov     bx,SERIALSERVER_TIMER_LOCATION
462        call    TimerTicks_GetTimeoutTicksLeftToAXfromDSBX
463        pop     bx
464        pop     ax
465%endif
466        jc      SerialServer_OutputWithParameters_ErrorAndPop4Words
467        in      al,dx
468        test    al,ah
469        jz      .WaitAndPoll
470        cli
471
472.readTimeoutComplete:
473        pop     dx
474        pop     cx
475        ret
476
477
Note: See TracBrowser for help on using the repository browser.