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

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

Serial Port: split single byte port and baud into two bytes, taking advantage of the two bytes in DPT_SERIAL, which supports more serial baud rates and in particular fixed a bug where a 4x client machine couldn't talk to a 115.2K server machine. This is a wide change, touching lots of files, but most are shallow changes. DetectPrint.asm took the most significant changes, now it calculates the baud rate to display instead of using characters provided by the Configurator. The Configurator now has a new menu flag, FLG_MENUITEM_CHOICESTRINGS, for specifying that values are not linear and they should be lookedup rather than indexed. Finally, another important bug fixed here is that in some error cases, the serial port code could get into an infinite loop waiting ont the hardware; now it has a timeout.

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