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
Line 
1; Project name  :   XTIDE Universal BIOS
2; Description   :   Serial Device Command functions.
3
4; Section containing code
5SECTION .text
6
7;--------------- UART Equates -----------------------------
8;
9; Serial Programming References:
10;    http://en.wikibooks.org/wiki/Serial_Programming
11;
12
13SerialCommand_UART_base                         EQU     0
14SerialCommand_UART_transmitByte                 EQU     0
15SerialCommand_UART_receiveByte                  EQU     0
16
17;
18; Values for UART_divisorLow:
19; 60h = 1200, 30h = 2400, 18h = 4800, 0ch = 9600, 6 = 19200, 4 = 28800, 3 = 38400, 2 = 57600, 1 = 115200
20;
21SerialCommand_UART_divisorLow                   EQU     0
22
23;
24; UART_divisorHigh is zero for all speeds including and above 1200 baud (which is all we do)
25;
26SerialCommand_UART_divisorHigh                  EQU     1
27
28SerialCommand_UART_interruptIdent               EQU     2
29SerialCommand_UART_FIFOControl                  EQU     2
30
31SerialCommand_UART_lineControl                  EQU     3
32
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
45
46;--------------------------------------------------------------------
47; SerialCommand_OutputWithParameters
48;   Parameters:
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
56;   Returns:
57;       AH:     INT 13h Error Code
58;       CF:     Cleared if success, Set if error
59;   Corrupts registers:
60;       AL, BX, CX, DX, (ES:SI for data transfer commands)
61;--------------------------------------------------------------------
62ALIGN JUMP_ALIGN
63SerialCommand_OutputWithParameters:
64
65        mov     ah,(SerialCommand_Protocol_Header | SerialCommand_Protocol_Read)
66
67        mov     al,[bp+IDEPACK.bCommand]
68
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
74
75;  all other commands return success
76;  including function 0ech which should return drive information, this is handled with the identify functions
77;
78        xor     ah,ah           ;  also clears carry
79        ret
80
81.readOrWrite:
82        mov     [bp+IDEPACK.bFeatures],ah       ; store protocol command
83
84        mov     dx, [di+DPT_SERIAL.wSerialPortAndBaud]
85
86; fall-through
87
88;--------------------------------------------------------------------
89; SerialCommand_OutputWithParameters_DeviceInDX
90;   Parameters:
91;       AH:     Protocol Command
92;       DX:     Packed I/O port and baud rate
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)
100;--------------------------------------------------------------------
101SerialCommand_OutputWithParameters_DeviceInDX:
102
103        push    si
104        push    di
105        push    bp
106
107;
108; Unpack I/O port and baud from DPT
109;       Port to DX for the remainder of the routine (+/- different register offsets)
110;       Baud in CH until UART initialization is complete
111;
112        mov     ch,dh
113        xor     dh,dh
114        eSHL_IM dx, 2           ; shift from one byte to two       
115       
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
120;
121        push    ax
122
123%if 0
124        cld     ; Shouldn't be needed. DF has already been cleared (line 24, Int13h.asm)
125%endif
126
127;----------------------------------------------------------------------
128;
129; Initialize UART
130;
131; We do this each time since DOS (at boot) or another program may have
132; decided to reprogram the UART
133;
134        mov     bl,dl           ; setup BL with proper values for read/write loops (BH comes later)
135
136        mov     al,83h
137        add     dl,SerialCommand_UART_lineControl
138        out     dx,al
139
140        mov     al,ch
141        mov     dl,bl           ; divisor low
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
151        out     dx,al
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
161        inc     dx              ;  linestatus (no output now, just setting up BH for later use)
162        mov     bh,dl
163
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
175        push    si
176
177        mov     si,bp           ; point to IDEREGS for command dispatch;
178        push    ss
179        pop     es
180
181        mov     di,0ffffh       ; initialize checksum for write
182        mov     bp,di
183
184        mov     cx,4            ; writing 3 words (plus 1)
185
186        cli                     ; interrupts off...
187
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)
193        pop     es
194
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...
199.nextSectorNormalize:
200        call    Registers_NormalizeESDI
201%endif
202
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
208;
209.nextSector:
210        mov     si,0ffffh       ; initialize checksum for read or write
211        mov     bp,si
212
213        mov     cx,0101h        ; writing 256 words (plus 1)
214
215        shr     ah,1            ; command byte, are we doing a write?
216        jnc     .readEntry
217
218        xchg    si,di
219        call    SerialCommand_WriteProtocol.entry
220        xchg    si,di
221
222        inc     cx              ; CX = 1 now (0 out of WriteProtocol)
223        jmp     .readEntry
224
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:
232        push    ax              ; not only does this push preserve AX (which we need), but it also
233                                ; means the stack has the same number of bytes on it as when we are
234                                ; sending a packet, important for error cleanup and exit
235        mov     ah,1
236        call    SerialCommand_WaitAndPoll_Read
237        pop     ax
238        test    dl,1
239        jz      .readByte1Ready
240        jmp     .readByte2Ready
241
242;----------------------------------------------------------------------------
243;
244; Read Block (without interrupts, used when there is a FIFO, high speed)
245;
246; NOTE: This loop is very time sensitive.  Literally, another instruction
247; cannot be inserted into this loop without us falling behind at high
248; speed (460.8K baud) on a 4.77Mhz 8088, making it hard to receive
249; a full 512 byte block.
250;
251.readLoop:
252        stosw                   ; store word in caller's data buffer
253
254        add     bp, ax          ; update Fletcher's checksum
255        adc     bp, 0
256        add     si, bp
257        adc     si, 0
258
259.readEntry:
260        mov     dl,bh
261        in      al,dx
262        shr     al,1            ; data ready (byte 1)?
263        mov     dl,bl           ; get ready to read data
264        jnc     .readTimeout    ; nope not ready, update timeouts
265
266;
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).
269;
270.readByte1Ready:
271        in      al, dx          ; read data byte 1
272
273        mov     ah, al          ; store byte in ah for now
274
275;
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
280; .read_byte2_ready)
281;
282        mov     dl,bh
283
284        in      al,dx
285        shr     al,1            ; data ready (byte 2)?
286        jnc     .readTimeout
287.readByte2Ready:
288        mov     dl,bl
289        in      al, dx          ; read data byte 2
290
291        xchg    al, ah          ; ah was holding byte 1, reverse byte order
292
293        loop    .readLoop
294
295        sti                     ; interrupts back on ASAP, between packets
296
297;
298; Compare checksums
299;
300        xchg    ax,bp
301        xor     ah,al
302        mov     cx,si
303        xor     cl,ch
304        mov     al,cl
305        cmp     ax,bp
306        jnz     SerialCommand_OutputWithParameters_Error
307
308        pop     ax              ; sector count and command byte
309        dec     al              ; decrement sector count
310        push    ax              ; save
311        jz      SerialCommand_OutputWithParameters_ReturnCodeInALCF    ; CF=0 from "cmp ax,bp" returning Zero above
312
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
316
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...
320
321;
322; Normalize buffer pointer for next go round, if needed.
323;
324; We need to re-normalize the pointer in ES:DI after processing every 7f sectors.  That number could
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
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
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
338; function also appear to be capped at 127 sectors.  So although this can support the full 256 sectors
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)
353
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
357                                        ; fe moves to 0 and OF=0, SF=0, so OF=SF
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
363;       jpo     short .nextSector       ; if we really wanted to avoid normalizing for ff, this
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
370%else
371
372        jmp     short .nextSector
373
374%endif
375
376;---------------------------------------------------------------------------
377;
378; Cleanup, error reporting, and exit
379;
380
381;
382; Used in situations where a call is underway, such as with SerialCommand_WaitAndPoll
383;
384ALIGN JUMP_ALIGN
385SerialCommand_OutputWithParameters_ErrorAndPop4Words:
386        add     sp,8
387;;; fall-through
388
389ALIGN JUMP_ALIGN
390SerialCommand_OutputWithParameters_Error:
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;
399        xor     cx,cx                   ; timeout this clearing routine, in case the UART isn't there
400.clearBuffer:
401        mov     dl,bh
402        in      al,dx
403        mov     dl,bl
404        test    al,08fh
405        jz      .clearBufferComplete
406        test    al,1
407        in      al,dx
408        loopnz  .clearBuffer            ; note ZF from test above
409
410.clearBufferComplete:
411        stc
412        mov     al,1
413
414ALIGN JUMP_ALIGN
415SerialCommand_OutputWithParameters_ReturnCodeInALCF:
416%if 0
417        sti                     ;  all paths here will already have interrupts turned back on
418%endif
419        mov     ah,al
420
421        pop     bp              ;  recover ax (command and count) from stack, throw away
422
423        pop     bp
424        pop     di
425        pop     si
426
427        ret
428
429;--------------------------------------------------------------------
430; SerialCommand_WriteProtocol
431;
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.
435;
436;   Parameters:
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)
442;   Returns:
443;       BP/DI:  Checksum for written bytes, compared against ACK from server in .readLoop
444;       CX:     Zero
445;       DL:     Receive/Transmit Register address
446;   Corrupts registers:
447;       AX
448;--------------------------------------------------------------------
449ALIGN JUMP_ALIGN
450SerialCommand_WriteProtocol:
451.writeLoop:
452        es lodsw                ; fetch next word
453
454        out     dx,al           ; output first byte
455
456        add     bp,ax           ; update checksum
457        adc     bp,0
458        add     di,bp
459        adc     di,0
460
461        mov     dl,bh           ; transmit buffer empty?
462        in      al,dx
463        test    al,20h
464        jz      .writeTimeout2  ; nope, use our polling routine
465
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
491        ret
492
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
498
499.writeTimeout1:
500%ifndef USE_186
501        mov     ax,.writeByte1Ready
502        push    ax              ; return address for ret at end of SC_writeTimeout2
503%else
504        push    .writeByte1Ready
505%endif
506;;; fall-through
507
508;--------------------------------------------------------------------
509; SerialCommand_WaitAndPoll
510;
511;   Parameters:
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)
515;       BX:
516;       Stack:  2 words on the stack below the command/count word
517;   Returns:
518;       Returns when desired UART_LineStatus bit is cleared
519;       Jumps directly to error exit if timeout elapses (and cleans up stack)
520;   Corrupts registers:
521;       AX
522;--------------------------------------------------------------------
523
524SerialCommand_WaitAndPoll_SoftDelayTicks   EQU   20
525
526ALIGN JUMP_ALIGN
527SerialCommand_WaitAndPoll_Write:
528        mov     ah,20h
529;;; fall-through
530
531ALIGN JUMP_ALIGN
532SerialCommand_WaitAndPoll_Read:
533        push    cx
534        push    dx
535
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:
541        mov     dl,bh
542        in      al,dx
543        test    al,ah
544        jnz     .readTimeoutComplete
545        loop    .readTimeoutLoop
546
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
561
562.readTimeoutComplete:
563        pop     dx
564        pop     cx
565        ret
566
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
576;               NOTE: Not set (or checked) during drive detection
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:
583;
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.
587;
588; But drive detection isn't the only case - we also need to get the right drive when called on int13h/25h.
589;
590; The decision tree:
591;
592;    Master:
593;          bSerialPackedPortAndBaud Non-Zero:   -> Continue with bSerialPackedAndBaud (1)
594;          bSerialPackedPortAndBaud Zero:
595;                         bLastSerial Zero:     -> Scan (2)
596;                         bLastSerial Non-Zero: -> Continue with bLastSerial (3)
597;
598;    Slave:
599;          bSerialPackedPortAndBaud Non-Zero:
600;                         bLastSerial Zero:     -> Error - Not Found (4)
601;                         bLastSerial Non-Zero: -> Continue with bSerialPackedAndBaud (5)
602;          bSerialPackedPortAndBaud Zero:
603;                         bLastSerial Zero:     -> Error - Not Found (4)
604;                         bLastSerial Non-Zero: -> Continue with bLastSerial (6)
605;
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.
608;     And as with the int13h/25h case, we just go off and get the needed information using the user's setting.
609; (2) We are using the special .ideVarsSerialAuto structure.  During drive detection, we would only be here
610;     if bLastSerial is zero (since we only scan if no explicit drives are set), so we go off to scan.
611; (3) We are using the special .ideVarsSerialAuto structure.  We won't get here during drive detection, but
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.
614; (4) No master has been found yet, therefore no slave should be found.  Avoiding the slave reduces boot time,
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,
617;     we will do the slave scan, which isn't harmful, it just wastes time.  But the most common case (by a wide
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
620;     controller scenario being called with int13h/25h, we need to use the value in bSerialPackedPortAndBaud
621;     to make sure we get the proper drive.
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
625;     master scan.
626;
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:   
636
637        test    bh, FLG_DRVNHEAD_DRV
638        jz      .master
639
640        test    ax,ax           ; Take care of the case that is different between master and slave.
641        jz      .error          ; Because we do this here, the jz after the "or" below will not be taken
642
643; fall-through
644.master:
645        test    dx,dx
646        jnz     .identifyDeviceInDX
647
648        or      dx,ax           ; Move bLast into position in dl, as well as test for zero
649        jz      .scanSerial
650
651; fall-through
652.identifyDeviceInDX:
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
662
663        push    bx
664
665        mov     bp,sp
666        call    SerialCommand_OutputWithParameters_DeviceInDX
667
668        pop     bx
669
670        pop     cx
671        pop     dx
672       
673        pop     bp
674;
675; place packed port/baud in RAMVARS, read by FinalizeDPT and DetectDrives
676;
677        mov     [es:si+ATA6.wVendor],dx
678
679.notFound:
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.
687;
688
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
697
698ALIGN JUMP_ALIGN
699.scanSerial:
700        mov     di,.scanPortAddresses-1
701        mov     ch,1            ;  tell server that we are scanning
702
703.nextPort:
704        inc     di              ; load next port address
705        xor     dh, dh
706        mov     dl,[cs:di]
707        eSHL_IM dx, 2           ; shift from one byte to two
708        jz      .error
709
710;
711; Test for COM port presence, write to and read from registers
712;
713        push    dx
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
720        jnz     .nextPort
721
722        mov     al, 0ch
723        out     dx, al
724        in      al, dx
725        cmp     al, 0ch
726        jnz     .nextPort
727
728;
729; Begin baud rate scan on this port...
730;
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. 
734;
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)
737;
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
743.nextBaud:
744        shr     dh,1
745        jz      .nextPort
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
749
750.testBaud:
751        call    .identifyDeviceInDX
752        jc      .nextBaud
753
754        ret
755
756.error:
757        stc
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
762        ret
763
764
Note: See TracBrowser for help on using the repository browser.