source: xtideuniversalbios/trunk/XTIDE_Universal_BIOS/Src/Device/Serial/SerialCommand.asm@ 196

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

Added printing of COM port and baud rate, when set explicitly by idecfg. Although it eats some bytes, I think it is worth it, since the BIOS will be looking for a server on a particular com port and baud rate, and it could be hard to troubleshoot a mismatch without this information. However, if we become space crunched, this change can be backed out.

File size: 15.6 KB
Line 
1; Project name : XTIDE Universal BIOS
2; Description : Serial Device Command functions.
3
4; Section containing code
5SECTION .text
6
7;--------------- UART Equates -----------------------------
8;
9; Serial Programming References:
10; http://en.wikibooks.org/wiki/Serial_Programming
11;
12
13SerialCommand_UART_base EQU 0
14SerialCommand_UART_transmitByte EQU 0
15SerialCommand_UART_receiveByte EQU 0
16SerialCommand_UART_divisorLow EQU 0
17; Values for UART_divisorLow:
18; 60h = 1200, 30h = 2400, 18h = 4800, 0ch = 9600, 6 = 19200, 3 = 38400, 2 = 57600, 1 = 115200
19
20SerialCommand_UART_divisorLow_startingBaud EQU 030h
21; We support 4 baud rates, starting here going higher and skipping every other baud rate
22; Starting with 30h, that means 30h (1200 baud), 0ch (9600 baud), 3 (38400 baud), and 1 (115200 baud)
23; Note: hardware baud multipliers (2x, 4x) will impact the final baud rate and are not known at this level
24
25SerialCommand_UART_interruptEnable EQU 1
26SerialCommand_UART_divisorHigh EQU 1
27; UART_divisorHigh is zero for all speeds including and above 1200 baud
28
29SerialCommand_UART_interruptIdent EQU 2
30SerialCommand_UART_FIFOControl EQU 2
31
32SerialCommand_UART_lineControl EQU 3
33
34SerialCommand_UART_modemControl EQU 4
35
36SerialCommand_UART_lineStatus EQU 5
37
38SerialCommand_UART_modemStatus EQU 6
39
40SerialCommand_UART_scratch EQU 7
41
42; note that the actual StaringPoint port address is not achievable (results in 0 which triggers auto detect)
43SerialCommand_PackedPortAndBaud_StartingPort EQU 240h
44
45SerialCommand_PackedPortAndBaud_PortMask EQU 0fch ; upper 6 bits - 240h through 438h
46SerialCommand_PackedPortAndBaud_BaudMask EQU 3 ; lower 2 bits - 4 baud rates
47
48SerialCommand_Protocol_Write EQU 3
49SerialCommand_Protocol_Read EQU 2
50SerialCommand_Protocol_Inquire EQU 0
51SerialCommand_Protocol_Header EQU 0a0h
52
53;--------------------------------------------------------------------
54; SerialCommand_OutputWithParameters
55; Parameters:
56; BH: Non-zero if 48-bit addressing used
57; (ignored at present as 48-bit addressing is not supported)
58; BL: IDE Status Register bit to poll after command
59; (ignored at present, since there is no IDE status register to poll)
60; ES:SI: Ptr to buffer (for data transfer commands)
61; DS:DI: Ptr to DPT (in RAMVARS segment)
62; SS:BP: Ptr to IDEREGS_AND_INTPACK
63; Returns:
64; AH: INT 13h Error Code
65; CF: Cleared if success, Set if error
66; Corrupts registers:
67; AL, BX, CX, DX, (ES:SI for data transfer commands)
68;--------------------------------------------------------------------
69ALIGN JUMP_ALIGN
70SerialCommand_OutputWithParameters:
71
72 mov ah,(SerialCommand_Protocol_Header | SerialCommand_Protocol_Read)
73
74 mov al,[bp+IDEPACK.bCommand]
75
76 cmp al,20h ; Read Sectors IDE command
77 jz .readOrWrite
78 inc ah ; now SerialCommand_Protocol_Write
79 cmp al,30h ; Write Sectors IDE command
80 jz .readOrWrite
81
82; all other commands return success
83; including function 0ech which should return drive information, this is handled with the identify functions
84 xor ah,ah ; also clears carry
85 ret
86
87.readOrWrite:
88 mov [bp+IDEPACK.bFeatures],ah ; store protocol command
89
90 mov dl, byte [di+DPT.bSerialPortAndBaud]
91
92; fall-through
93
94;--------------------------------------------------------------------
95; SerialCommand_OutputWithParameters_DeviceInDL
96; Parameters:
97; AH: Protocol Command
98; DL: Packed I/O port and baud rate
99; ES:SI: Ptr to buffer (for data transfer commands)
100; SS:BP: Ptr to IDEREGS_AND_INTPACK
101; Returns:
102; AH: INT 13h Error Code
103; CF: Cleared if success, Set if error
104; Corrupts registers:
105; AL, BX, CX, DX, (ES:SI for data transfer commands)
106;--------------------------------------------------------------------
107SerialCommand_OutputWithParameters_DeviceInDL:
108
109 push si
110 push di
111 push bp
112 push es
113
114;
115; Unpack I/O port and baud from DPT
116; Port to DX more or less for the remainder of the routine
117; Baud in CH until UART initialization is complete
118;
119 mov cl, dl
120
121 and cl, SerialCommand_PackedPortAndBaud_BaudMask
122 shl cl, 1
123 mov ch, SerialCommand_UART_divisorLow_startingBaud
124 shr ch, cl
125 adc ch, 0
126
127 and dl, SerialCommand_PackedPortAndBaud_PortMask
128 mov dh, 0
129 shl dx, 1 ; port offset already x4, needs one more shift to be x8
130 add dx, SerialCommand_PackedPortAndBaud_StartingPort
131
132;
133; Buffer is referenced through ES:DI throughout, since we need to store faster than we read
134;
135 mov di,si
136
137 mov al,[bp+IDEPACK.bSectorCount]
138
139;
140; Command byte and sector count live at the top of the stack, pop/push are used to access
141;
142 push ax
143
144; cld ; Shouldn't be needed. DF has already been cleared (line 24, Int13h.asm)
145
146;----------------------------------------------------------------------
147;
148; Initialize UART
149;
150; We do this each time since DOS (at boot) or another program may have
151; decided to reprogram the UART
152;
153 push dx
154
155 mov al,83h
156 add dl,SerialCommand_UART_lineControl
157 out dx,al
158
159 mov al,ch
160 pop dx ; divisor low
161 out dx,al
162
163 xor ax,ax
164 inc dx ; divisor high
165 push dx
166 out dx,al
167
168 mov al,047h
169 inc dx ; fifo
170 out dx,al
171
172 mov al,03h
173 inc dx ; linecontrol
174 out dx,al
175
176 mov al,0bh
177 inc dx ; modemcontrol
178 out dx,al
179
180 pop dx ; base, interrupts disabled
181 xor ax,ax
182 out dx,al
183 dec dx
184
185;----------------------------------------------------------------------
186;
187; Send Command
188;
189; Sends first six bytes of IDEREGS_AND_INTPACK as the command
190;
191 call Registers_NormalizeESDI
192
193 push es ; save off real buffer location
194 push di
195
196 mov di,bp ; point to IDEREGS for command dispatch;
197 push ss
198 pop es
199
200 xor si,si ; initialize checksum for write
201 dec si
202 mov bp,si
203
204 mov bl,03h ; writing 3 words
205
206 call SerialCommand_WriteProtocol
207
208 pop di ; restore real buffer location
209 pop es
210
211 pop ax ; load command byte (done before call to .nextSector on subsequent iterations)
212 push ax
213
214;
215; Top of the read/write loop, one iteration per sector
216;
217.nextSector:
218 xor si,si ; initialize checksum for read or write
219 dec si
220 mov bp,si
221
222 mov bx,0100h
223
224 shr ah,1 ; command byte, are we doing a write?
225 jnc .readSector
226 call SerialCommand_WriteProtocol
227
228 xor bx,bx
229
230.readSector:
231 mov cx,bx
232 inc cx
233
234 mov bl,dl ; setup bl with proper values for read loop (bh comes later)
235
236;----------------------------------------------------------------------
237;
238; Timeout
239;
240; During read, we first poll in a tight loop, interrupts off, for the next character to come in
241; If that loop completes, then we assume there is a long delay involved, turn interrupts back on
242; and wait for a given number of timer ticks to pass.
243;
244; To save code space, we use the contents of DL to decide which byte in the word to return for reading.
245;
246.readTimeout:
247 push cx
248 xor cx,cx
249.readTimeoutLoop:
250 push dx
251 or dl,SerialCommand_UART_lineStatus
252 in al,dx
253 pop dx
254 shr al,1
255 jc .readTimeoutComplete
256 loop .readTimeoutLoop
257 sti
258 mov bh,1
259 call SerialCommand_WaitAndPoll_Init
260 cli
261.readTimeoutComplete:
262 mov bh,bl
263 or bh,SerialCommand_UART_lineStatus
264
265 pop cx
266 test dl,1
267 jz .readByte1Ready
268 jmp .readByte2Ready
269
270;----------------------------------------------------------------------------
271;
272; Read Block (without interrupts, used when there is a FIFO, high speed)
273;
274; NOTE: This loop is very time sensitive. Literally, another instruction
275; cannot be inserted into this loop without us falling behind at high
276; speed (460.8K baud) on a 4.77Mhz 8088, making it hard to receive
277; a full 512 byte block.
278;
279.readLoop:
280 stosw ; store word in caller's data buffer
281
282 add bp, ax ; update Fletcher's checksum
283 adc bp, 0
284 add si, bp
285 adc si, 0
286
287 mov dl,bh
288 in al,dx
289 shr al,1 ; data ready (byte 1)?
290 mov dl,bl ; get ready to read data
291 jnc .readTimeout ; nope not ready, update timeouts
292
293;
294; Entry point after initial timeout. We enter here so that the checksum word
295; is not stored (and is left in AX after the loop is complete).
296;
297.readByte1Ready:
298 in al, dx ; read data byte 1
299
300 mov ah, al ; store byte in ah for now
301
302;
303; note the placement of this reset of dl to bh, and that it is
304; before the return, which is assymetric with where this is done
305; above for byte 1. The value of dl is used by the timeout routine
306; to know which byte to return to (.read_byte1_ready or
307; .read_byte2_ready)
308;
309 mov dl,bh
310
311 in al,dx
312 shr al,1 ; data ready (byte 2)?
313 jnc .readTimeout
314.readByte2Ready:
315 mov dl,bl
316 in al, dx ; read data byte 2
317
318 xchg al, ah ; ah was holding byte 1, reverse byte order
319
320 loop .readLoop
321
322 sti ; interrupts back on ASAP, if we turned them off
323
324;
325; Compare checksums
326;
327 xor bp,si
328 cmp ax,bp
329 jnz SerialCommand_OutputWithParameters_Error
330
331
332;----------------------------------------------------------------------
333;
334; Clear read buffer
335;
336; In case there are extra characters or an error in the FIFO, clear it out.
337; In theory the initialization of the UART registers above should have
338; taken care of this, but I have seen cases where this is not true.
339;
340.clearBuffer:
341 mov dl,bh
342 in al,dx
343 mov dl,bl
344 test al,08fh
345 jz .clearBufferComplete
346 shr al,1
347 in al,dx
348 jc .clearBuffer ; note CF from shr above
349 jmp SerialCommand_OutputWithParameters_Error
350
351.clearBufferComplete:
352 pop ax ; sector count and command byte
353 dec al ; decrememnt sector count
354 push ax ; save
355 jz SerialCommand_OutputWithParameters_ReturnCodeInALCF ; CF clear from .clearBuffer test above
356
357 cli ; interrupts back off for ACK byte to host
358 ; (host could start sending data immediately)
359 out dx,al ; ACK with next sector number
360
361 jmp .nextSector ; all is well, time for next sector
362
363;---------------------------------------------------------------------------
364;
365; Cleanup, error reporting, and exit
366;
367
368;
369; Used in situations where a call is underway, such as with SerialCommand_WaitAndPoll
370;
371SerialCommand_OutputWithParameters_ErrorAndPop2Words:
372 pop ax
373 pop ax
374
375SerialCommand_OutputWithParameters_Error:
376 stc
377 mov al,1
378
379SerialCommand_OutputWithParameters_ReturnCodeInALCF:
380 sti
381 mov ah,al
382
383 pop bp ; recover ax from stack, throw away
384
385 pop es
386 pop bp
387 pop di
388 pop si
389
390 ret
391
392;--------------------------------------------------------------------
393; SerialCommand_WaitAndPoll
394;
395; Parameters:
396; BH: UART_LineStatus bit to test (20h for write, or 1h for read)
397; DX: Port address (OK if already incremented to UART_lineStatus)
398; Stack: 2 words on the stack below the command/count word
399; Returns:
400; Returns when desired UART_LineStatus bit is cleared
401; Jumps directly to error exit if timeout elapses (and cleans up stack)
402; Corrupts registers:
403; CX, flags
404;--------------------------------------------------------------------
405
406SerialCommand_WaitAndPoll_SoftDelayTicks EQU 20
407
408ALIGN JUMP_ALIGN
409SerialCommand_WaitAndPoll_Init:
410 mov cl,SerialCommand_WaitAndPoll_SoftDelayTicks
411 call Timer_InitializeTimeoutWithTicksInCL
412; fall-through
413
414SerialCommand_WaitAndPoll:
415 call Timer_SetCFifTimeout
416 jc SerialCommand_OutputWithParameters_ErrorAndPop2Words
417 push dx
418 push ax
419 or dl,SerialCommand_UART_lineStatus
420 in al,dx
421 test al,bh
422 pop ax
423 pop dx
424 jz SerialCommand_WaitAndPoll
425; fall-through
426
427SerialCommand_WaitAndPoll_Done:
428 ret
429
430;--------------------------------------------------------------------
431; SerialCommand_WriteProtocol
432;
433; Parameters:
434; ES:DI: Ptr to buffer
435; BL: Words to write (1-255, or 0=256)
436; BP/SI: Initialized for Checksum (-1 in each)
437; DX: I/O Port
438; Returns:
439; BP/SI: Checksum for written bytes, compared against ACK from server in .readLoop
440; Corrupts registers:
441; AX, BX, CX, DI
442;--------------------------------------------------------------------
443ALIGN JUMP_ALIGN
444SerialCommand_WriteProtocol:
445 mov bh,20h
446
447.writeLoop:
448 test bh,1
449 jnz SerialCommand_WaitAndPoll_Done
450
451 mov ax,[es:di] ; fetch next word
452 inc di
453 inc di
454
455 add bp,ax ; update checksum
456 adc bp,0
457 add si,bp
458 adc si,0
459
460.writeLoopChecksum:
461 call SerialCommand_WaitAndPoll_Init
462
463 out dx,al ; output first byte
464
465 call SerialCommand_WaitAndPoll
466
467 mov al,ah ; output second byte
468 out dx,al
469
470 dec bl
471 jnz .writeLoop
472
473 inc bh
474
475 mov ax,bp ; merge checksum for possible write (last loop)
476 xor ax,si
477
478 jmp .writeLoopChecksum
479
480
481; To return the port number and baud rate to the FinalizeDPT routine, we
482; stuff the value in a "vendor" specific area of the 512-byte IdentifyDevice
483; sector.
484;
485SerialCommand_IdentifyDevice_PackedPortAndBaud equ (157*2)
486
487;--------------------------------------------------------------------
488; SerialCommand_IdentifyDeviceToBufferInESSIwithDriveSelectByteInBH
489; Parameters:
490; BH: Drive Select byte for Drive and Head Select Register
491; DS: Segment to RAMVARS
492; ES:SI: Ptr to buffer to receive 512-byte IDE Information
493; CS:BP: Ptr to IDEVARS
494; Returns:
495; AH: INT 13h Error Code
496; CF: Cleared if success, Set if error
497; Corrupts registers:
498; AL, BL, CX, DX, SI, DI, ES
499;--------------------------------------------------------------------
500ALIGN JUMP_ALIGN
501SerialCommand_IdentifyDeviceToBufferInESSIwithDriveSelectByteInBH:
502
503 mov dl,[cs:bp+IDEVARS.bSerialPackedPortAndBaud]
504 test dl,dl
505 jz SerialCommand_AutoSerial
506
507; fall-through
508SerialCommand_IdentifyDeviceInDL_DriveInBH:
509
510 push bp ; setup fake IDEREGS_AND_INTPACK
511
512 push dx
513
514 mov cl,1 ; 1 sector to move
515 push cx
516
517 mov bl,0a0h ; protocol command to ah and onto stack with bh
518 mov ah,bl
519
520 push bx
521
522 mov bp,sp
523
524 call SerialCommand_OutputWithParameters_DeviceInDL
525
526 pop bx
527
528 pop cx
529 pop dx
530
531 pop bp
532
533; place packed port/baud in vendor area of packet, read by FinalizeDPT
534 mov byte [es:si+SerialCommand_IdentifyDevice_PackedPortAndBaud], dl
535
536 ret
537
538;----------------------------------------------------------------------
539;
540; SerialCommand_AutoSerial
541;
542; When the SerialAuto IDEVARS entry is used, scans the COM ports on the machine for a possible serial connection.
543;
544
545SerialCommand_ScanPortAddresses: db 0b8h, 0f8h, 0bch, 0bah, 0fah, 0beh, 0feh, 0
546; Corresponds to I/O port: 3f8, 2f8, 3e8, 2e8, 2f0, 3e0, 2e0, 260, 368, 268, 360, 270
547; COM Assignments: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
548; Corresponds to Packed I/O port (hex): 37, 17, 35, 15, 16, 34, 14, 4, 25, 5, 24, 6
549
550ALIGN JUMP_ALIGN
551SerialCommand_AutoSerial:
552 mov di,SerialCommand_ScanPortAddresses-1
553
554.nextPort:
555 inc di ; load next port address
556 mov dl,[cs:di]
557
558 mov dh,0 ; shift from one byte to two
559 eSHL_IM dx, 2
560 jz .exitNotFound
561
562;
563; Test for COM port presence, write to and read from registers
564;
565 push dx
566 add dl,SerialCommand_UART_lineControl
567 mov al, 09ah
568 out dx, al
569 in al, dx
570 pop dx
571 cmp al, 09ah
572 jnz .nextPort
573
574 mov al, 0ch
575 out dx, al
576 in al, dx
577 cmp al, 0ch
578 jnz .nextPort
579
580;
581; Pack into dl, baud rate starts at 0
582;
583 add dx,-(SerialCommand_PackedPortAndBaud_StartingPort)
584 shr dx,1
585
586 jmp .testFirstBaud
587
588;
589; Walk through 4 possible baud rates
590;
591.nextBaud:
592 inc dx
593 test dl,3
594 jz .nextPort
595
596.testFirstBaud:
597 call SerialCommand_IdentifyDeviceInDL_DriveInBH
598 jc .nextBaud
599
600 ret
601
602.exitNotFound:
603 stc
604 mov ah,1
605
606 ret
Note: See TracBrowser for help on using the repository browser.