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

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

Added floppy drive emulation over the serial connection (MODULE_SERIAL_FLOPPY). Along the way, various optimizations were made to stay within the 8K ROM size target. Also, serial code now returns the number of sectors transferred.

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