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

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

Serial Port: Missed updating some comments in the code from the last checkin.

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:
[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:
[234]593;          wSerialPortAndBaud Non-Zero:           -> Continue with wSerialPortAndBaud (1)
594;          wSerialPortAndBaud Zero:
595;              previous serial drive not found:   -> Scan (2)
596;              previous serial drive found:       -> Continue with previous serial drive info (3)
[223]597;
[203]598;    Slave:
[234]599;          wSerialPortAndBaud Non-Zero:
600;              previous serial drive not found:   -> Error - Not Found (4)
601;              previosu serial drive found:       -> Continue with wSerialPackedAndBaud (5)
602;          wSerialPortAndBaud Zero:
603;              previous serial drive not found:   -> Error - Not Found (4)
604;              previous serial drive found:       -> Continue with previous serial drive info (6)
[203]605;
[223]606; (1) This was a port/baud that was explicitly set with the configurator.  In the drive detection case, as this
[234]607;     is the Master, we are checking out a new controller, and so don't care if we already have a serial drive.
[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
[234]610;     if we hand't already seen a serial drive (since we only scan if no explicit drives are set),
611;     so we go off to scan.
[223]612; (3) We are using the special .ideVarsSerialAuto structure.  We won't get here during drive detection, but
[203]613;     we might get here on an int13h/25h call.  If we have scanned COM drives, they are the ONLY serial drives
[234]614;     in use, and so we use the values from the previously seen serial drive DPT.
[223]615; (4) No master has been found yet, therefore no slave should be found.  Avoiding the slave reduces boot time,
[203]616;     especially in the full COM port scan case.  Note that this is different from the hardware IDE, where we
617;     will scan for a slave even if a master is not present.  Note that if ANY master had been previously found,
[223]618;     we will do the slave scan, which isn't harmful, it just wastes time.  But the most common case (by a wide
[203]619;     margin) will be just one serial controller.
620; (5) A COM port scan for a master had been previously completed, and a drive was found.  In a multiple serial
[223]621;     controller scenario being called with int13h/25h, we need to use the value in bSerialPackedPortAndBaud
[203]622;     to make sure we get the proper drive.
[223]623; (6) A COM port scan for a master had been previously completed, and a drive was found.  We would only get here
624;     if no serial drive was explicitly set by the user in the configurator or that drive had not been found.
625;     Instead of performing the full COM port scan for the slave, use the port/baud value stored during the
[203]626;     master scan.
[223]627;
[233]628        mov     cx,1            ; 1 sector to move, 0 for non-scan
629        mov     dx,[cs:bp+IDEVARS.wSerialPortAndBaud]
630        xor     ax,ax
631        push    si
632        call    FindDPT_ToDSDIforSerialDevice
633        pop     si
634        jnc     .notfounddpt
635        mov     ax,[ds:di+DPT_SERIAL.wSerialPortAndBaud]
636.notfounddpt:   
[223]637
[203]638        test    bh, FLG_DRVNHEAD_DRV
639        jz      .master
[179]640
[233]641        test    ax,ax           ; Take care of the case that is different between master and slave.
[203]642        jz      .error          ; Because we do this here, the jz after the "or" below will not be taken
643
644; fall-through
[223]645.master:
[233]646        test    dx,dx
647        jnz     .identifyDeviceInDX
[179]648
[234]649        or      dx,ax           ; Since DX is zero, this effectively moves the previously found serial drive 
650                                ; information to dx, as well as test for zero
[203]651        jz      .scanSerial
[223]652
[179]653; fall-through
[233]654.identifyDeviceInDX:
[179]655
656        push    bp              ; setup fake IDEREGS_AND_INTPACK
657
658        push    dx
659
660        push    cx
661
662        mov     bl,0a0h         ; protocol command to ah and onto stack with bh
663        mov     ah,bl
[181]664
[179]665        push    bx
666
667        mov     bp,sp
[233]668        call    SerialCommand_OutputWithParameters_DeviceInDX
[179]669
670        pop     bx
[181]671
672        pop     cx
[179]673        pop     dx
[233]674       
[179]675        pop     bp
[223]676;
[234]677; place port and baud word in to the return sector, in a vendor specific area, 
678; which is read by FinalizeDPT and DetectDrives
[203]679;
[233]680        mov     [es:si+ATA6.wVendor],dx
[179]681
[223]682.notFound:
[179]683        ret
684
685;----------------------------------------------------------------------
686;
687; SerialCommand_AutoSerial
688;
689; When the SerialAuto IDEVARS entry is used, scans the COM ports on the machine for a possible serial connection.
[181]690;
691
[203]692.scanPortAddresses: db  DEVICE_SERIAL_COM7 >> 2
693                    db  DEVICE_SERIAL_COM6 >> 2
694                    db  DEVICE_SERIAL_COM5 >> 2
695                    db  DEVICE_SERIAL_COM4 >> 2
696                    db  DEVICE_SERIAL_COM3 >> 2
697                    db  DEVICE_SERIAL_COM2 >> 2
698                    db  DEVICE_SERIAL_COM1 >> 2
699                    db  0
[179]700
[181]701ALIGN JUMP_ALIGN
[203]702.scanSerial:
703        mov     di,.scanPortAddresses-1
[233]704        mov     ch,1            ;  tell server that we are scanning
[181]705
[179]706.nextPort:
707        inc     di              ; load next port address
[223]708        xor     dh, dh
[179]709        mov     dl,[cs:di]
[223]710        eSHL_IM dx, 2           ; shift from one byte to two
[203]711        jz      .error
[179]712
713;
714; Test for COM port presence, write to and read from registers
[181]715;
716        push    dx
[179]717        add     dl,SerialCommand_UART_lineControl
718        mov     al, 09ah
719        out     dx, al
720        in      al, dx
721        pop     dx
722        cmp     al, 09ah
[181]723        jnz     .nextPort
[179]724
725        mov     al, 0ch
726        out     dx, al
727        in      al, dx
728        cmp     al, 0ch
729        jnz     .nextPort
730
731;
[233]732; Begin baud rate scan on this port...
[181]733;
[233]734; On a scan, we support 6 baud rates, starting here and going higher by a factor of two each step, with a 
735; small jump between 9600 and 38800.  These 6 were selected since we wanted to support 9600 baud and 115200,
736; *on the server side* if the client side had a 4x clock multiplier, a 2x clock multiplier, or no clock multiplier. 
[179]737;
[233]738; Starting with 30h, that means 30h (2400 baud), 18h (4800 baud), 0ch (9600 baud), and
739;                               04h (28800 baud), 02h (57600 baud), 01h (115200 baud)
[181]740;
[233]741; Note: hardware baud multipliers (2x, 4x) will impact the final baud rate and are not known at this level
742;
743        mov     dh,030h * 2     ; multiply by 2 since we are about to divide by 2
744        mov     dl,[cs:di]      ; restore single byte port address for scan
745
[181]746.nextBaud:
[233]747        shr     dh,1
[179]748        jz      .nextPort
[233]749        cmp     dh,6            ; skip from 6 to 4, to move from the top of the 9600 baud range 
750        jnz     .testBaud       ; to the bottom of the 115200 baud range
751        mov     dh,4
[181]752
[233]753.testBaud:
754        call    .identifyDeviceInDX
[179]755        jc      .nextBaud
756
757        ret
[181]758
[223]759.error:
[181]760        stc
[216]761%if 0
762        mov     ah,1        ; setting the error code is unnecessary as this path can only be taken during
763                            ; drive detection, and drive detection works off CF and does not check AH
764%endif
[203]765        ret
[179]766
[203]767
Note: See TracBrowser for help on using the repository browser.