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

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

Serial Port: split single byte port and baud into two bytes, taking advantage of the two bytes in DPT_SERIAL, which supports more serial baud rates and in particular fixed a bug where a 4x client machine couldn't talk to a 115.2K server machine. This is a wide change, touching lots of files, but most are shallow changes. DetectPrint.asm took the most significant changes, now it calculates the baud rate to display instead of using characters provided by the Configurator. The Configurator now has a new menu flag, FLG_MENUITEM_CHOICESTRINGS, for specifying that values are not linear and they should be lookedup rather than indexed. Finally, another important bug fixed here is that in some error cases, the serial port code could get into an infinite loop waiting ont the hardware; now it has a timeout.

File size: 23.4 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
16
17;
18; Values for UART_divisorLow:
19; 60h = 1200, 30h = 2400, 18h = 4800, 0ch = 9600, 6 = 19200, 4 = 28800, 3 = 38400, 2 = 57600, 1 = 115200
20;
21SerialCommand_UART_divisorLow EQU 0
22
23;
24; UART_divisorHigh is zero for all speeds including and above 1200 baud (which is all we do)
25;
26SerialCommand_UART_divisorHigh EQU 1
27
28SerialCommand_UART_interruptIdent EQU 2
29SerialCommand_UART_FIFOControl EQU 2
30
31SerialCommand_UART_lineControl EQU 3
32
33SerialCommand_UART_modemControl EQU 4
34
35SerialCommand_UART_lineStatus EQU 5
36
37SerialCommand_UART_modemStatus EQU 6
38
39SerialCommand_UART_scratch EQU 7
40
41SerialCommand_Protocol_Write EQU 3
42SerialCommand_Protocol_Read EQU 2
43SerialCommand_Protocol_Inquire EQU 0
44SerialCommand_Protocol_Header EQU 0a0h
45
46;--------------------------------------------------------------------
47; SerialCommand_OutputWithParameters
48; Parameters:
49; BH: Non-zero if 48-bit addressing used
50; (ignored at present as 48-bit addressing is not supported)
51; BL: IDE Status Register bit to poll after command
52; (ignored at present, since there is no IDE status register to poll)
53; ES:SI: Ptr to buffer (for data transfer commands)
54; DS:DI: Ptr to DPT (in RAMVARS segment)
55; SS:BP: Ptr to IDEREGS_AND_INTPACK
56; Returns:
57; AH: INT 13h Error Code
58; CF: Cleared if success, Set if error
59; Corrupts registers:
60; AL, BX, CX, DX, (ES:SI for data transfer commands)
61;--------------------------------------------------------------------
62ALIGN JUMP_ALIGN
63SerialCommand_OutputWithParameters:
64
65 mov ah,(SerialCommand_Protocol_Header | SerialCommand_Protocol_Read)
66
67 mov al,[bp+IDEPACK.bCommand]
68
69 cmp al,20h ; Read Sectors IDE command
70 jz .readOrWrite
71 inc ah ; now SerialCommand_Protocol_Write
72 cmp al,30h ; Write Sectors IDE command
73 jz .readOrWrite
74
75; all other commands return success
76; including function 0ech which should return drive information, this is handled with the identify functions
77;
78 xor ah,ah ; also clears carry
79 ret
80
81.readOrWrite:
82 mov [bp+IDEPACK.bFeatures],ah ; store protocol command
83
84 mov dx, [di+DPT_SERIAL.wSerialPortAndBaud]
85
86; fall-through
87
88;--------------------------------------------------------------------
89; SerialCommand_OutputWithParameters_DeviceInDX
90; Parameters:
91; AH: Protocol Command
92; DX: Packed I/O port and baud rate
93; ES:SI: Ptr to buffer (for data transfer commands)
94; SS:BP: Ptr to IDEREGS_AND_INTPACK
95; Returns:
96; AH: INT 13h Error Code
97; CF: Cleared if success, Set if error
98; Corrupts registers:
99; AL, BX, CX, DX, (ES:SI for data transfer commands)
100;--------------------------------------------------------------------
101SerialCommand_OutputWithParameters_DeviceInDX:
102
103 push si
104 push di
105 push bp
106
107;
108; Unpack I/O port and baud from DPT
109; Port to DX for the remainder of the routine (+/- different register offsets)
110; Baud in CH until UART initialization is complete
111;
112 mov ch,dh
113 xor dh,dh
114 eSHL_IM dx, 2 ; shift from one byte to two
115
116 mov al,[bp+IDEPACK.bSectorCount]
117
118;
119; Command byte and sector count live at the top of the stack, pop/push are used to access
120;
121 push ax
122
123%if 0
124 cld ; Shouldn't be needed. DF has already been cleared (line 24, Int13h.asm)
125%endif
126
127;----------------------------------------------------------------------
128;
129; Initialize UART
130;
131; We do this each time since DOS (at boot) or another program may have
132; decided to reprogram the UART
133;
134 mov bl,dl ; setup BL with proper values for read/write loops (BH comes later)
135
136 mov al,83h
137 add dl,SerialCommand_UART_lineControl
138 out dx,al
139
140 mov al,ch
141 mov dl,bl ; divisor low
142 out dx,al
143
144 xor ax,ax
145 inc dx ; divisor high
146 push dx
147 out dx,al
148
149 mov al,047h
150 inc dx ; fifo
151 out dx,al
152
153 mov al,03h
154 inc dx ; linecontrol
155 out dx,al
156
157 mov al,0bh
158 inc dx ; modemcontrol
159 out dx,al
160
161 inc dx ; linestatus (no output now, just setting up BH for later use)
162 mov bh,dl
163
164 pop dx ; base, interrupts disabled
165 xor ax,ax
166 out dx,al
167
168;----------------------------------------------------------------------
169;
170; Send Command
171;
172; Sends first six bytes of IDEREGS_AND_INTPACK as the command
173;
174 push es ; save off real buffer location
175 push si
176
177 mov si,bp ; point to IDEREGS for command dispatch;
178 push ss
179 pop es
180
181 mov di,0ffffh ; initialize checksum for write
182 mov bp,di
183
184 mov cx,4 ; writing 3 words (plus 1)
185
186 cli ; interrupts off...
187
188 call SerialCommand_WriteProtocol.entry
189
190 pop di ; restore real buffer location (note change from SI to DI)
191 ; Buffer is primarily referenced through ES:DI throughout, since
192 ; we need to store (read sector) faster than we read (write sector)
193 pop es
194
195%if 0
196;;; no longer needed, since the pointer is normalized before we are called and we do not support
197;;; more than 128 sectors (and for 128 specifically, the pointer must be segment aligned).
198;;; See comments below at the point this entry point was called for more details...
199.nextSectorNormalize:
200 call Registers_NormalizeESDI
201%endif
202
203 pop ax ; load command byte (done before call to .nextSector on subsequent iterations)
204 push ax
205
206;
207; Top of the read/write loop, one iteration per sector
208;
209.nextSector:
210 mov si,0ffffh ; initialize checksum for read or write
211 mov bp,si
212
213 mov cx,0101h ; writing 256 words (plus 1)
214
215 shr ah,1 ; command byte, are we doing a write?
216 jnc .readEntry
217
218 xchg si,di
219 call SerialCommand_WriteProtocol.entry
220 xchg si,di
221
222 inc cx ; CX = 1 now (0 out of WriteProtocol)
223 jmp .readEntry
224
225;----------------------------------------------------------------------
226;
227; Timeout
228;
229; To save code space, we use the contents of DL to decide which byte in the word to return for reading.
230;
231.readTimeout:
232 push ax ; not only does this push preserve AX (which we need), but it also
233 ; means the stack has the same number of bytes on it as when we are
234 ; sending a packet, important for error cleanup and exit
235 mov ah,1
236 call SerialCommand_WaitAndPoll_Read
237 pop ax
238 test dl,1
239 jz .readByte1Ready
240 jmp .readByte2Ready
241
242;----------------------------------------------------------------------------
243;
244; Read Block (without interrupts, used when there is a FIFO, high speed)
245;
246; NOTE: This loop is very time sensitive. Literally, another instruction
247; cannot be inserted into this loop without us falling behind at high
248; speed (460.8K baud) on a 4.77Mhz 8088, making it hard to receive
249; a full 512 byte block.
250;
251.readLoop:
252 stosw ; store word in caller's data buffer
253
254 add bp, ax ; update Fletcher's checksum
255 adc bp, 0
256 add si, bp
257 adc si, 0
258
259.readEntry:
260 mov dl,bh
261 in al,dx
262 shr al,1 ; data ready (byte 1)?
263 mov dl,bl ; get ready to read data
264 jnc .readTimeout ; nope not ready, update timeouts
265
266;
267; Entry point after initial timeout. We enter here so that the checksum word
268; is not stored (and is left in AX after the loop is complete).
269;
270.readByte1Ready:
271 in al, dx ; read data byte 1
272
273 mov ah, al ; store byte in ah for now
274
275;
276; note the placement of this reset of dl to bh, and that it is
277; before the return, which is assymetric with where this is done
278; above for byte 1. The value of dl is used by the timeout routine
279; to know which byte to return to (.read_byte1_ready or
280; .read_byte2_ready)
281;
282 mov dl,bh
283
284 in al,dx
285 shr al,1 ; data ready (byte 2)?
286 jnc .readTimeout
287.readByte2Ready:
288 mov dl,bl
289 in al, dx ; read data byte 2
290
291 xchg al, ah ; ah was holding byte 1, reverse byte order
292
293 loop .readLoop
294
295 sti ; interrupts back on ASAP, between packets
296
297;
298; Compare checksums
299;
300 xchg ax,bp
301 xor ah,al
302 mov cx,si
303 xor cl,ch
304 mov al,cl
305 cmp ax,bp
306 jnz SerialCommand_OutputWithParameters_Error
307
308 pop ax ; sector count and command byte
309 dec al ; decrement sector count
310 push ax ; save
311 jz SerialCommand_OutputWithParameters_ReturnCodeInALCF ; CF=0 from "cmp ax,bp" returning Zero above
312
313 cli ; interrupts back off for ACK byte to host
314 ; (host could start sending data immediately)
315 out dx,al ; ACK with next sector number
316
317%if 0
318;;; This code is no longer needed as we do not support more than 128 sectors, and for 128 the pointer
319;;; must be segment aligned. If we ever do want to support more sectors, the code can help...
320
321;
322; Normalize buffer pointer for next go round, if needed.
323;
324; We need to re-normalize the pointer in ES:DI after processing every 7f sectors. That number could
325; have been 80 if we knew the offset was on a segment boundary, but this may not be the case.
326;
327; We re-normalize based on the sector count (flags from "dec al" above)...
328; a) we normalize before the first sector goes out, immediately after sending the command packet (above)
329; b) on transitions from FF to FE, very rare case for writing 255 or 256 sectors
330; c) on transitions from 80 to 7F, a large read/write
331; d) on transitions from 00 to FF, very, very rare case of writing 256 sectors
332; We don't need to renormalize in this case, but it isn't worth the memory/effort to not do
333; the extra work, and it does no harm.
334;
335; I really don't care much about (d) because I have not seen cases where any OS makes a request
336; for more than 127 sectors. Back in the day, it appears that some BIOS could not support more than 127
337; sectors, so that may be the practical limit for OS and application developers. The Extended BIOS
338; function also appear to be capped at 127 sectors. So although this can support the full 256 sectors
339; if needed, we are optimized for that 1-127 range.
340;
341; Assume we start with 0000:000f, with 256 sectors to write...
342; After first packet, 0000:020f
343; First decrement of AL, transition from 00 to FF: renormalize to 0020:000f (unnecessary)
344; After second packet, 0020:020f
345; Second derement of AL, transition from FF to FE: renormalize to 0040:000f
346; After 7f more packets, 0040:fe0f
347; Decrement of AL, transition from 80 to 7F: renormalize to 1020:000f
348; After 7f more packets, 1020:fe0f or 2000:000f if normalized
349; Decrement of AL, from 1 to 0: exit
350;
351 jge short .nextSector ; OF=SF, branch for 1-7e, most common case
352 ; (0 kicked out above for return success)
353
354 add al,2 ; 7f-ff moves to 81-01
355 ; (0-7e kicked out before we get here)
356 ; 7f moves to 81 and OF=1, so OF=SF
357 ; fe moves to 0 and OF=0, SF=0, so OF=SF
358 ; ff moves to 1 and OF=0, SF=0, so OF=SF
359 ; 80-fd moves to 82-ff and OF=0, so OF<>SF
360
361 jl short .nextSector ; OF<>SF, branch for all cases but 7f, fe, and ff
362
363; jpo short .nextSector ; if we really wanted to avoid normalizing for ff, this
364 ; is one way to do it, but it adds more memory and more
365 ; cycles for the 7f and fe cases. IMHO, given that I've
366 ; never seen a request for more than 7f, this seems unnecessary.
367
368 jmp short .nextSectorNormalize ; our two renormalization cases (plus one for ff)
369
370%else
371
372 jmp short .nextSector
373
374%endif
375
376;---------------------------------------------------------------------------
377;
378; Cleanup, error reporting, and exit
379;
380
381;
382; Used in situations where a call is underway, such as with SerialCommand_WaitAndPoll
383;
384ALIGN JUMP_ALIGN
385SerialCommand_OutputWithParameters_ErrorAndPop4Words:
386 add sp,8
387;;; fall-through
388
389ALIGN JUMP_ALIGN
390SerialCommand_OutputWithParameters_Error:
391;----------------------------------------------------------------------
392;
393; Clear read buffer
394;
395; In case there are extra characters or an error in the FIFO, clear it out.
396; In theory the initialization of the UART registers above should have
397; taken care of this, but I have seen cases where this is not true.
398;
399 xor cx,cx ; timeout this clearing routine, in case the UART isn't there
400.clearBuffer:
401 mov dl,bh
402 in al,dx
403 mov dl,bl
404 test al,08fh
405 jz .clearBufferComplete
406 test al,1
407 in al,dx
408 loopnz .clearBuffer ; note ZF from test above
409
410.clearBufferComplete:
411 stc
412 mov al,1
413
414ALIGN JUMP_ALIGN
415SerialCommand_OutputWithParameters_ReturnCodeInALCF:
416%if 0
417 sti ; all paths here will already have interrupts turned back on
418%endif
419 mov ah,al
420
421 pop bp ; recover ax (command and count) from stack, throw away
422
423 pop bp
424 pop di
425 pop si
426
427 ret
428
429;--------------------------------------------------------------------
430; SerialCommand_WriteProtocol
431;
432; NOTE: As with its read counterpart, this loop is very time sensitive.
433; Although it will still function, adding additional instructions will
434; impact the write throughput, especially on slower machines.
435;
436; Parameters:
437; ES:SI: Ptr to buffer
438; CX: Words to write, plus 1
439; BP/DI: Initialized for Checksum (-1 in each)
440; DH: I/O Port high byte
441; BX: LineStatus Register address (BH) and Receive/Transmit Register address (BL)
442; Returns:
443; BP/DI: Checksum for written bytes, compared against ACK from server in .readLoop
444; CX: Zero
445; DL: Receive/Transmit Register address
446; Corrupts registers:
447; AX
448;--------------------------------------------------------------------
449ALIGN JUMP_ALIGN
450SerialCommand_WriteProtocol:
451.writeLoop:
452 es lodsw ; fetch next word
453
454 out dx,al ; output first byte
455
456 add bp,ax ; update checksum
457 adc bp,0
458 add di,bp
459 adc di,0
460
461 mov dl,bh ; transmit buffer empty?
462 in al,dx
463 test al,20h
464 jz .writeTimeout2 ; nope, use our polling routine
465
466.writeByte2Ready:
467 mov dl,bl
468 mov al,ah ; output second byte
469 out dx,al
470
471.entry:
472 mov dl,bh ; transmit buffer empty?
473 in al,dx
474 test al,20h
475 mov dl,bl
476 jz .writeTimeout1 ; nope, use our polling routine
477
478.writeByte1Ready:
479 loop .writeLoop
480
481 mov ax,di ; fold Fletcher's checksum and output
482 xor al,ah
483 out dx,al ; byte 1
484
485 call SerialCommand_WaitAndPoll_Write
486
487 mov ax,bp
488 xor al,ah
489 out dx,al ; byte 2
490
491 ret
492
493.writeTimeout2:
494 mov dl,ah ; need to preserve AH, but don't need DL (will be reset upon return)
495 call SerialCommand_WaitAndPoll_Write
496 mov ah,dl
497 jmp .writeByte2Ready
498
499.writeTimeout1:
500%ifndef USE_186
501 mov ax,.writeByte1Ready
502 push ax ; return address for ret at end of SC_writeTimeout2
503%else
504 push .writeByte1Ready
505%endif
506;;; fall-through
507
508;--------------------------------------------------------------------
509; SerialCommand_WaitAndPoll
510;
511; Parameters:
512; AH: UART_LineStatus bit to test (20h for write, or 1h for read)
513; One entry point fills in AH with 20h for write
514; DX: Port address (OK if already incremented to UART_lineStatus)
515; BX:
516; Stack: 2 words on the stack below the command/count word
517; Returns:
518; Returns when desired UART_LineStatus bit is cleared
519; Jumps directly to error exit if timeout elapses (and cleans up stack)
520; Corrupts registers:
521; AX
522;--------------------------------------------------------------------
523
524SerialCommand_WaitAndPoll_SoftDelayTicks EQU 20
525
526ALIGN JUMP_ALIGN
527SerialCommand_WaitAndPoll_Write:
528 mov ah,20h
529;;; fall-through
530
531ALIGN JUMP_ALIGN
532SerialCommand_WaitAndPoll_Read:
533 push cx
534 push dx
535
536;
537; We first poll in a tight loop, interrupts off, for the next character to come in/be sent
538;
539 xor cx,cx
540.readTimeoutLoop:
541 mov dl,bh
542 in al,dx
543 test al,ah
544 jnz .readTimeoutComplete
545 loop .readTimeoutLoop
546
547;
548; If that loop completes, then we assume there is a long delay involved, turn interrupts back on
549; and wait for a given number of timer ticks to pass.
550;
551 sti
552 mov cl,SerialCommand_WaitAndPoll_SoftDelayTicks
553 call Timer_InitializeTimeoutWithTicksInCL
554.WaitAndPoll:
555 call Timer_SetCFifTimeout
556 jc SerialCommand_OutputWithParameters_ErrorAndPop4Words
557 in al,dx
558 test al,ah
559 jz .WaitAndPoll
560 cli
561
562.readTimeoutComplete:
563 pop dx
564 pop cx
565 ret
566
567;--------------------------------------------------------------------
568; SerialCommand_IdentifyDeviceToBufferInESSIwithDriveSelectByteInBH
569; Parameters:
570; BH: Drive Select byte for Drive and Head Select Register
571; DS: Segment to RAMVARS
572; ES:SI: Ptr to buffer to receive 512-byte IDE Information
573; CS:BP: Ptr to IDEVARS
574; Returns:
575; AH: INT 13h Error Code
576; NOTE: Not set (or checked) during drive detection
577; CF: Cleared if success, Set if error
578; Corrupts registers:
579; AL, BL, CX, DX, SI, DI, ES
580;--------------------------------------------------------------------
581ALIGN JUMP_ALIGN
582SerialCommand_IdentifyDeviceToBufferInESSIwithDriveSelectByteInBH:
583;
584; To improve boot time, we do our best to avoid looking for slave serial drives when we already know the results
585; from the looking for a master. This is particularly true when doing a COM port scan, as we will end up running
586; through all the COM ports and baud rates a second time.
587;
588; But drive detection isn't the only case - we also need to get the right drive when called on int13h/25h.
589;
590; The decision tree:
591;
592; Master:
593; bSerialPackedPortAndBaud Non-Zero: -> Continue with bSerialPackedAndBaud (1)
594; bSerialPackedPortAndBaud Zero:
595; bLastSerial Zero: -> Scan (2)
596; bLastSerial Non-Zero: -> Continue with bLastSerial (3)
597;
598; Slave:
599; bSerialPackedPortAndBaud Non-Zero:
600; bLastSerial Zero: -> Error - Not Found (4)
601; bLastSerial Non-Zero: -> Continue with bSerialPackedAndBaud (5)
602; bSerialPackedPortAndBaud Zero:
603; bLastSerial Zero: -> Error - Not Found (4)
604; bLastSerial Non-Zero: -> Continue with bLastSerial (6)
605;
606; (1) This was a port/baud that was explicitly set with the configurator. In the drive detection case, as this
607; is the Master, we are checking out a new controller, and so don't care about the value of bLastSerial.
608; And as with the int13h/25h case, we just go off and get the needed information using the user's setting.
609; (2) We are using the special .ideVarsSerialAuto structure. During drive detection, we would only be here
610; if bLastSerial is zero (since we only scan if no explicit drives are set), so we go off to scan.
611; (3) We are using the special .ideVarsSerialAuto structure. We won't get here during drive detection, but
612; we might get here on an int13h/25h call. If we have scanned COM drives, they are the ONLY serial drives
613; in use, and so bLastSerial will reflect the port/baud setting for the scanned COM drives.
614; (4) No master has been found yet, therefore no slave should be found. Avoiding the slave reduces boot time,
615; especially in the full COM port scan case. Note that this is different from the hardware IDE, where we
616; will scan for a slave even if a master is not present. Note that if ANY master had been previously found,
617; we will do the slave scan, which isn't harmful, it just wastes time. But the most common case (by a wide
618; margin) will be just one serial controller.
619; (5) A COM port scan for a master had been previously completed, and a drive was found. In a multiple serial
620; controller scenario being called with int13h/25h, we need to use the value in bSerialPackedPortAndBaud
621; to make sure we get the proper drive.
622; (6) A COM port scan for a master had been previously completed, and a drive was found. We would only get here
623; if no serial drive was explicitly set by the user in the configurator or that drive had not been found.
624; Instead of performing the full COM port scan for the slave, use the port/baud value stored during the
625; master scan.
626;
627 mov cx,1 ; 1 sector to move, 0 for non-scan
628 mov dx,[cs:bp+IDEVARS.wSerialPortAndBaud]
629 xor ax,ax
630 push si
631 call FindDPT_ToDSDIforSerialDevice
632 pop si
633 jnc .notfounddpt
634 mov ax,[ds:di+DPT_SERIAL.wSerialPortAndBaud]
635.notfounddpt:
636
637 test bh, FLG_DRVNHEAD_DRV
638 jz .master
639
640 test ax,ax ; Take care of the case that is different between master and slave.
641 jz .error ; Because we do this here, the jz after the "or" below will not be taken
642
643; fall-through
644.master:
645 test dx,dx
646 jnz .identifyDeviceInDX
647
648 or dx,ax ; Move bLast into position in dl, as well as test for zero
649 jz .scanSerial
650
651; fall-through
652.identifyDeviceInDX:
653
654 push bp ; setup fake IDEREGS_AND_INTPACK
655
656 push dx
657
658 push cx
659
660 mov bl,0a0h ; protocol command to ah and onto stack with bh
661 mov ah,bl
662
663 push bx
664
665 mov bp,sp
666 call SerialCommand_OutputWithParameters_DeviceInDX
667
668 pop bx
669
670 pop cx
671 pop dx
672
673 pop bp
674;
675; place packed port/baud in RAMVARS, read by FinalizeDPT and DetectDrives
676;
677 mov [es:si+ATA6.wVendor],dx
678
679.notFound:
680 ret
681
682;----------------------------------------------------------------------
683;
684; SerialCommand_AutoSerial
685;
686; When the SerialAuto IDEVARS entry is used, scans the COM ports on the machine for a possible serial connection.
687;
688
689.scanPortAddresses: db DEVICE_SERIAL_COM7 >> 2
690 db DEVICE_SERIAL_COM6 >> 2
691 db DEVICE_SERIAL_COM5 >> 2
692 db DEVICE_SERIAL_COM4 >> 2
693 db DEVICE_SERIAL_COM3 >> 2
694 db DEVICE_SERIAL_COM2 >> 2
695 db DEVICE_SERIAL_COM1 >> 2
696 db 0
697
698ALIGN JUMP_ALIGN
699.scanSerial:
700 mov di,.scanPortAddresses-1
701 mov ch,1 ; tell server that we are scanning
702
703.nextPort:
704 inc di ; load next port address
705 xor dh, dh
706 mov dl,[cs:di]
707 eSHL_IM dx, 2 ; shift from one byte to two
708 jz .error
709
710;
711; Test for COM port presence, write to and read from registers
712;
713 push dx
714 add dl,SerialCommand_UART_lineControl
715 mov al, 09ah
716 out dx, al
717 in al, dx
718 pop dx
719 cmp al, 09ah
720 jnz .nextPort
721
722 mov al, 0ch
723 out dx, al
724 in al, dx
725 cmp al, 0ch
726 jnz .nextPort
727
728;
729; Begin baud rate scan on this port...
730;
731; On a scan, we support 6 baud rates, starting here and going higher by a factor of two each step, with a
732; small jump between 9600 and 38800. These 6 were selected since we wanted to support 9600 baud and 115200,
733; *on the server side* if the client side had a 4x clock multiplier, a 2x clock multiplier, or no clock multiplier.
734;
735; Starting with 30h, that means 30h (2400 baud), 18h (4800 baud), 0ch (9600 baud), and
736; 04h (28800 baud), 02h (57600 baud), 01h (115200 baud)
737;
738; Note: hardware baud multipliers (2x, 4x) will impact the final baud rate and are not known at this level
739;
740 mov dh,030h * 2 ; multiply by 2 since we are about to divide by 2
741 mov dl,[cs:di] ; restore single byte port address for scan
742
743.nextBaud:
744 shr dh,1
745 jz .nextPort
746 cmp dh,6 ; skip from 6 to 4, to move from the top of the 9600 baud range
747 jnz .testBaud ; to the bottom of the 115200 baud range
748 mov dh,4
749
750.testBaud:
751 call .identifyDeviceInDX
752 jc .nextBaud
753
754 ret
755
756.error:
757 stc
758%if 0
759 mov ah,1 ; setting the error code is unnecessary as this path can only be taken during
760 ; drive detection, and drive detection works off CF and does not check AH
761%endif
762 ret
763
764
Note: See TracBrowser for help on using the repository browser.