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

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

Serial port code - improved pointer re-normalization.

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