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

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

More optimizations. Merged RamVars_IsFunction/DriveHandledByThisBIOS in with FindDPT_ForDriveNumber, since they are often used together, making a returned NULL DI pointer indicate a foreign drive in many places. Revamped the iteration done in the handlers for int13/0dh and int13h/0h. Added serial specific print string during drive detection.

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