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@…, 13 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
RevLine 
[150]1; Project name : XTIDE Universal BIOS
2; Description : Serial Device Command functions.
3
4; Section containing code
5SECTION .text
6
[179]7;--------------- UART Equates -----------------------------
8;
9; Serial Programming References:
10; http://en.wikibooks.org/wiki/Serial_Programming
11;
[181]12
[179]13SerialCommand_UART_base EQU 0
14SerialCommand_UART_transmitByte EQU 0
15SerialCommand_UART_receiveByte EQU 0
[216]16
17;
[181]18; Values for UART_divisorLow:
[233]19; 60h = 1200, 30h = 2400, 18h = 4800, 0ch = 9600, 6 = 19200, 4 = 28800, 3 = 38400, 2 = 57600, 1 = 115200
[216]20;
21SerialCommand_UART_divisorLow EQU 0
[179]22
[216]23;
24; UART_divisorHigh is zero for all speeds including and above 1200 baud (which is all we do)
25;
[179]26SerialCommand_UART_divisorHigh EQU 1
27
28SerialCommand_UART_interruptIdent EQU 2
29SerialCommand_UART_FIFOControl EQU 2
30
31SerialCommand_UART_lineControl EQU 3
[181]32
[179]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
[181]45
[150]46;--------------------------------------------------------------------
[179]47; SerialCommand_OutputWithParameters
[150]48; Parameters:
[179]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
[150]56; Returns:
57; AH: INT 13h Error Code
58; CF: Cleared if success, Set if error
59; Corrupts registers:
[179]60; AL, BX, CX, DX, (ES:SI for data transfer commands)
[150]61;--------------------------------------------------------------------
62ALIGN JUMP_ALIGN
[179]63SerialCommand_OutputWithParameters:
[181]64
[179]65 mov ah,(SerialCommand_Protocol_Header | SerialCommand_Protocol_Read)
[181]66
[179]67 mov al,[bp+IDEPACK.bCommand]
[150]68
[179]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
[181]74
[179]75; all other commands return success
76; including function 0ech which should return drive information, this is handled with the identify functions
[216]77;
[179]78 xor ah,ah ; also clears carry
79 ret
[181]80
81.readOrWrite:
[179]82 mov [bp+IDEPACK.bFeatures],ah ; store protocol command
[181]83
[233]84 mov dx, [di+DPT_SERIAL.wSerialPortAndBaud]
[181]85
[179]86; fall-through
[150]87
88;--------------------------------------------------------------------
[233]89; SerialCommand_OutputWithParameters_DeviceInDX
[150]90; Parameters:
[181]91; AH: Protocol Command
[233]92; DX: Packed I/O port and baud rate
[150]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)
[181]100;--------------------------------------------------------------------
[233]101SerialCommand_OutputWithParameters_DeviceInDX:
[181]102
[179]103 push si
104 push di
105 push bp
106
[181]107;
[179]108; Unpack I/O port and baud from DPT
[233]109; Port to DX for the remainder of the routine (+/- different register offsets)
[179]110; Baud in CH until UART initialization is complete
111;
[233]112 mov ch,dh
113 xor dh,dh
114 eSHL_IM dx, 2 ; shift from one byte to two
115
[179]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
[181]120;
[179]121 push ax
122
[216]123%if 0
124 cld ; Shouldn't be needed. DF has already been cleared (line 24, Int13h.asm)
125%endif
[181]126
[179]127;----------------------------------------------------------------------
128;
129; Initialize UART
130;
[181]131; We do this each time since DOS (at boot) or another program may have
[179]132; decided to reprogram the UART
133;
[214]134 mov bl,dl ; setup BL with proper values for read/write loops (BH comes later)
[223]135
[179]136 mov al,83h
137 add dl,SerialCommand_UART_lineControl
138 out dx,al
139
140 mov al,ch
[214]141 mov dl,bl ; divisor low
[179]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
[181]151 out dx,al
[179]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
[214]161 inc dx ; linestatus (no output now, just setting up BH for later use)
162 mov bh,dl
163
[179]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
[214]175 push si
[181]176
[214]177 mov si,bp ; point to IDEREGS for command dispatch;
[179]178 push ss
179 pop es
180
[214]181 mov di,0ffffh ; initialize checksum for write
182 mov bp,di
[179]183
[214]184 mov cx,4 ; writing 3 words (plus 1)
[181]185
[223]186 cli ; interrupts off...
[179]187
[214]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)
[179]193 pop es
194
[220]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...
[223]199.nextSectorNormalize:
[220]200 call Registers_NormalizeESDI
201%endif
[223]202
[179]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
[181]208;
[179]209.nextSector:
[214]210 mov si,0ffffh ; initialize checksum for read or write
[179]211 mov bp,si
212
[214]213 mov cx,0101h ; writing 256 words (plus 1)
[181]214
[179]215 shr ah,1 ; command byte, are we doing a write?
[214]216 jnc .readEntry
[181]217
[214]218 xchg si,di
219 call SerialCommand_WriteProtocol.entry
220 xchg si,di
[179]221
[214]222 inc cx ; CX = 1 now (0 out of WriteProtocol)
223 jmp .readEntry
[181]224
[179]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:
[214]232 push ax ; not only does this push preserve AX (which we need), but it also
[223]233 ; means the stack has the same number of bytes on it as when we are
[214]234 ; sending a packet, important for error cleanup and exit
235 mov ah,1
236 call SerialCommand_WaitAndPoll_Read
237 pop ax
[179]238 test dl,1
239 jz .readByte1Ready
[223]240 jmp .readByte2Ready
[179]241
242;----------------------------------------------------------------------------
243;
244; Read Block (without interrupts, used when there is a FIFO, high speed)
245;
[181]246; NOTE: This loop is very time sensitive. Literally, another instruction
[179]247; cannot be inserted into this loop without us falling behind at high
[181]248; speed (460.8K baud) on a 4.77Mhz 8088, making it hard to receive
[179]249; a full 512 byte block.
250;
[181]251.readLoop:
252 stosw ; store word in caller's data buffer
253
[179]254 add bp, ax ; update Fletcher's checksum
255 adc bp, 0
256 add si, bp
257 adc si, 0
258
[223]259.readEntry:
[181]260 mov dl,bh
261 in al,dx
[179]262 shr al,1 ; data ready (byte 1)?
[181]263 mov dl,bl ; get ready to read data
[179]264 jnc .readTimeout ; nope not ready, update timeouts
[181]265
266;
[179]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).
[181]269;
270.readByte1Ready:
[179]271 in al, dx ; read data byte 1
272
273 mov ah, al ; store byte in ah for now
[181]274
[179]275;
[181]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
[179]280; .read_byte2_ready)
281;
[181]282 mov dl,bh
283
[179]284 in al,dx
285 shr al,1 ; data ready (byte 2)?
286 jnc .readTimeout
[181]287.readByte2Ready:
288 mov dl,bl
[179]289 in al, dx ; read data byte 2
290
291 xchg al, ah ; ah was holding byte 1, reverse byte order
[181]292
[179]293 loop .readLoop
294
[214]295 sti ; interrupts back on ASAP, between packets
[181]296
[179]297;
298; Compare checksums
[181]299;
[208]300 xchg ax,bp
301 xor ah,al
302 mov cx,si
303 xor cl,ch
304 mov al,cl
[179]305 cmp ax,bp
306 jnz SerialCommand_OutputWithParameters_Error
307
308 pop ax ; sector count and command byte
[223]309 dec al ; decrement sector count
[179]310 push ax ; save
[216]311 jz SerialCommand_OutputWithParameters_ReturnCodeInALCF ; CF=0 from "cmp ax,bp" returning Zero above
[181]312
[179]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
[181]316
[220]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...
[223]320
[214]321;
[216]322; Normalize buffer pointer for next go round, if needed.
[214]323;
[223]324; We need to re-normalize the pointer in ES:DI after processing every 7f sectors. That number could
[216]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
[223]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
[216]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
[223]338; function also appear to be capped at 127 sectors. So although this can support the full 256 sectors
[216]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)
[179]353
[216]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
[223]357 ; fe moves to 0 and OF=0, SF=0, so OF=SF
[216]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
[220]363; jpo short .nextSector ; if we really wanted to avoid normalizing for ff, this
[216]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
[220]370%else
[223]371
372 jmp short .nextSector
373
[220]374%endif
375
[179]376;---------------------------------------------------------------------------
377;
378; Cleanup, error reporting, and exit
379;
[181]380
381;
[179]382; Used in situations where a call is underway, such as with SerialCommand_WaitAndPoll
[181]383;
[214]384ALIGN JUMP_ALIGN
385SerialCommand_OutputWithParameters_ErrorAndPop4Words:
386 add sp,8
[216]387;;; fall-through
[179]388
[214]389ALIGN JUMP_ALIGN
[181]390SerialCommand_OutputWithParameters_Error:
[216]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;
[233]399 xor cx,cx ; timeout this clearing routine, in case the UART isn't there
[216]400.clearBuffer:
401 mov dl,bh
402 in al,dx
403 mov dl,bl
404 test al,08fh
405 jz .clearBufferComplete
[233]406 test al,1
[216]407 in al,dx
[233]408 loopnz .clearBuffer ; note ZF from test above
[216]409
[223]410.clearBufferComplete:
[181]411 stc
[179]412 mov al,1
413
[214]414ALIGN JUMP_ALIGN
[181]415SerialCommand_OutputWithParameters_ReturnCodeInALCF:
[216]416%if 0
417 sti ; all paths here will already have interrupts turned back on
418%endif
[179]419 mov ah,al
420
[214]421 pop bp ; recover ax (command and count) from stack, throw away
[179]422
423 pop bp
424 pop di
425 pop si
426
427 ret
428
[150]429;--------------------------------------------------------------------
[214]430; SerialCommand_WriteProtocol
[179]431;
[223]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.
[214]435;
[179]436; Parameters:
[214]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)
[179]442; Returns:
[214]443; BP/DI: Checksum for written bytes, compared against ACK from server in .readLoop
444; CX: Zero
445; DL: Receive/Transmit Register address
[181]446; Corrupts registers:
[214]447; AX
[179]448;--------------------------------------------------------------------
[214]449ALIGN JUMP_ALIGN
450SerialCommand_WriteProtocol:
451.writeLoop:
452 es lodsw ; fetch next word
[179]453
[214]454 out dx,al ; output first byte
[179]455
[214]456 add bp,ax ; update checksum
457 adc bp,0
458 add di,bp
459 adc di,0
[181]460
[214]461 mov dl,bh ; transmit buffer empty?
[179]462 in al,dx
[214]463 test al,20h
464 jz .writeTimeout2 ; nope, use our polling routine
[181]465
[214]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
[179]491 ret
492
[214]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
[223]498
[214]499.writeTimeout1:
[223]500%ifndef USE_186
[214]501 mov ax,.writeByte1Ready
502 push ax ; return address for ret at end of SC_writeTimeout2
[223]503%else
504 push .writeByte1Ready
505%endif
[214]506;;; fall-through
507
[179]508;--------------------------------------------------------------------
[214]509; SerialCommand_WaitAndPoll
[179]510;
511; Parameters:
[214]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)
[223]515; BX:
[214]516; Stack: 2 words on the stack below the command/count word
[179]517; Returns:
[214]518; Returns when desired UART_LineStatus bit is cleared
519; Jumps directly to error exit if timeout elapses (and cleans up stack)
[179]520; Corrupts registers:
[214]521; AX
[179]522;--------------------------------------------------------------------
[181]523
[214]524SerialCommand_WaitAndPoll_SoftDelayTicks EQU 20
[181]525
[214]526ALIGN JUMP_ALIGN
527SerialCommand_WaitAndPoll_Write:
528 mov ah,20h
529;;; fall-through
[181]530
[214]531ALIGN JUMP_ALIGN
532SerialCommand_WaitAndPoll_Read:
533 push cx
534 push dx
[150]535
[214]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:
[223]541 mov dl,bh
[214]542 in al,dx
543 test al,ah
544 jnz .readTimeoutComplete
545 loop .readTimeoutLoop
[181]546
[214]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
[150]561
[214]562.readTimeoutComplete:
563 pop dx
564 pop cx
565 ret
[181]566
[179]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
[223]576; NOTE: Not set (or checked) during drive detection
[179]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:
[203]583;
[223]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.
[203]587;
[223]588; But drive detection isn't the only case - we also need to get the right drive when called on int13h/25h.
[203]589;
590; The decision tree:
591;
592; Master:
593; bSerialPackedPortAndBaud Non-Zero: -> Continue with bSerialPackedAndBaud (1)
[223]594; bSerialPackedPortAndBaud Zero:
[203]595; bLastSerial Zero: -> Scan (2)
596; bLastSerial Non-Zero: -> Continue with bLastSerial (3)
[223]597;
[203]598; Slave:
[223]599; bSerialPackedPortAndBaud Non-Zero:
[203]600; bLastSerial Zero: -> Error - Not Found (4)
601; bLastSerial Non-Zero: -> Continue with bSerialPackedAndBaud (5)
[223]602; bSerialPackedPortAndBaud Zero:
[203]603; bLastSerial Zero: -> Error - Not Found (4)
604; bLastSerial Non-Zero: -> Continue with bLastSerial (6)
605;
[223]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.
[203]608; And as with the int13h/25h case, we just go off and get the needed information using the user's setting.
[223]609; (2) We are using the special .ideVarsSerialAuto structure. During drive detection, we would only be here
[203]610; if bLastSerial is zero (since we only scan if no explicit drives are set), so we go off to scan.
[223]611; (3) We are using the special .ideVarsSerialAuto structure. We won't get here during drive detection, but
[203]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.
[223]614; (4) No master has been found yet, therefore no slave should be found. Avoiding the slave reduces boot time,
[203]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,
[223]617; we will do the slave scan, which isn't harmful, it just wastes time. But the most common case (by a wide
[203]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
[223]620; controller scenario being called with int13h/25h, we need to use the value in bSerialPackedPortAndBaud
[203]621; to make sure we get the proper drive.
[223]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
[203]625; master scan.
[223]626;
[233]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:
[223]636
[203]637 test bh, FLG_DRVNHEAD_DRV
638 jz .master
[179]639
[233]640 test ax,ax ; Take care of the case that is different between master and slave.
[203]641 jz .error ; Because we do this here, the jz after the "or" below will not be taken
642
643; fall-through
[223]644.master:
[233]645 test dx,dx
646 jnz .identifyDeviceInDX
[179]647
[233]648 or dx,ax ; Move bLast into position in dl, as well as test for zero
[203]649 jz .scanSerial
[223]650
[179]651; fall-through
[233]652.identifyDeviceInDX:
[179]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
[181]662
[179]663 push bx
664
665 mov bp,sp
[233]666 call SerialCommand_OutputWithParameters_DeviceInDX
[179]667
668 pop bx
[181]669
670 pop cx
[179]671 pop dx
[233]672
[179]673 pop bp
[223]674;
[203]675; place packed port/baud in RAMVARS, read by FinalizeDPT and DetectDrives
676;
[233]677 mov [es:si+ATA6.wVendor],dx
[179]678
[223]679.notFound:
[179]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.
[181]687;
688
[203]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
[179]697
[181]698ALIGN JUMP_ALIGN
[203]699.scanSerial:
700 mov di,.scanPortAddresses-1
[233]701 mov ch,1 ; tell server that we are scanning
[181]702
[179]703.nextPort:
704 inc di ; load next port address
[223]705 xor dh, dh
[179]706 mov dl,[cs:di]
[223]707 eSHL_IM dx, 2 ; shift from one byte to two
[203]708 jz .error
[179]709
710;
711; Test for COM port presence, write to and read from registers
[181]712;
713 push dx
[179]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
[181]720 jnz .nextPort
[179]721
722 mov al, 0ch
723 out dx, al
724 in al, dx
725 cmp al, 0ch
726 jnz .nextPort
727
728;
[233]729; Begin baud rate scan on this port...
[181]730;
[233]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.
[179]734;
[233]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)
[181]737;
[233]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
[181]743.nextBaud:
[233]744 shr dh,1
[179]745 jz .nextPort
[233]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
[181]749
[233]750.testBaud:
751 call .identifyDeviceInDX
[179]752 jc .nextBaud
753
754 ret
[181]755
[223]756.error:
[181]757 stc
[216]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
[203]762 ret
[179]763
[203]764
Note: See TracBrowser for help on using the repository browser.