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

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

Moved .bSerialPortAndBaud out of the main DPT into a an attached struc DPT_SERIAL, used by the serial port code only

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