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

Last change on this file since 280 was 277, checked in by gregli@…, 13 years ago

Moved the bulk of the serial code to the assembly library, for inclusion in other utilities. Fixed a bug in int13h.asm when floppy support was not enabled that was preventing foreign drives from working properly.

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