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
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;       CX:     Number of successfully transferred sectors (for transfer commands)
59;       CF:     Cleared if success, Set if error
60;   Corrupts registers:
61;       AL, BX, CX, DX, (ES:SI for data transfer commands)
62;--------------------------------------------------------------------
63ALIGN JUMP_ALIGN
64SerialCommand_OutputWithParameters:
65
66        mov     ah,(SerialCommand_Protocol_Header | SerialCommand_Protocol_Read)
67
68        mov     al,[bp+IDEPACK.bCommand]
69
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
75
76;  all other commands return success
77;  including function 0ech which should return drive information, this is handled with the identify functions
78;
79        xor     ah,ah           ;  also clears carry
80        ret
81
82.readOrWrite:
83        mov     [bp+IDEPACK.bFeatures],ah       ; store protocol command
84
85        mov     dx, [di+DPT_SERIAL.wSerialPortAndBaud]
86
87; fall-through
88
89;--------------------------------------------------------------------
90; SerialCommand_OutputWithParameters_DeviceInDX
91;   Parameters:
92;       AH:     Protocol Command
93;       DX:     Packed I/O port and baud rate
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)
101;--------------------------------------------------------------------
102SerialCommand_OutputWithParameters_DeviceInDX:
103
104        push    si
105        push    di
106        push    bp
107
108;
109; Unpack I/O port and baud from DPT
110;       Port to DX for the remainder of the routine (+/- different register offsets)
111;       Baud in CH until UART initialization is complete
112;
113        mov     ch,dh
114        xor     dh,dh
115        eSHL_IM dx, 2           ; shift from one byte to two
116
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
121;
122        push    ax
123
124%if 0
125        cld     ; Shouldn't be needed. DF has already been cleared (line 24, Int13h.asm)
126%endif
127
128;----------------------------------------------------------------------
129;
130; Initialize UART
131;
132; We do this each time since DOS (at boot) or another program may have
133; decided to reprogram the UART
134;
135        mov     bl,dl           ; setup BL with proper values for read/write loops (BH comes later)
136
137        mov     al,83h
138        add     dl,SerialCommand_UART_lineControl
139        out     dx,al
140
141        mov     al,ch
142        mov     dl,bl           ; divisor low
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
152        out     dx,al
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
162        inc     dx              ;  linestatus (no output now, just setting up BH for later use)
163        mov     bh,dl
164
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
176        push    si
177
178        mov     si,bp           ; point to IDEREGS for command dispatch;
179        push    ss
180        pop     es
181
182        mov     di,0ffffh       ; initialize checksum for write
183        mov     bp,di
184
185        mov     cx,4            ; writing 3 words (plus 1)
186
187        cli                     ; interrupts off...
188
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)
194        pop     es
195
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...
200.nextSectorNormalize:
201        call    Registers_NormalizeESDI
202%endif
203
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
209;
210.nextSector:
211        mov     si,0ffffh       ; initialize checksum for read or write
212        mov     bp,si
213
214        mov     cx,0101h        ; writing 256 words (plus 1)
215
216        shr     ah,1            ; command byte, are we doing a write?
217        jnc     .readEntry
218
219        xchg    si,di
220        call    SerialCommand_WriteProtocol.entry
221        xchg    si,di
222
223        inc     cx              ; CX = 1 now (0 out of WriteProtocol)
224        jmp     .readEntry
225
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:
233        push    ax              ; not only does this push preserve AX (which we need), but it also
234                                ; means the stack has the same number of bytes on it as when we are
235                                ; sending a packet, important for error cleanup and exit
236        mov     ah,1
237        call    SerialCommand_WaitAndPoll_Read
238        pop     ax
239        test    dl,1
240        jz      .readByte1Ready
241        jmp     .readByte2Ready
242
243;----------------------------------------------------------------------------
244;
245; Read Block (without interrupts, used when there is a FIFO, high speed)
246;
247; NOTE: This loop is very time sensitive.  Literally, another instruction
248; cannot be inserted into this loop without us falling behind at high
249; speed (460.8K baud) on a 4.77Mhz 8088, making it hard to receive
250; a full 512 byte block.
251;
252.readLoop:
253        stosw                   ; store word in caller's data buffer
254
255        add     bp, ax          ; update Fletcher's checksum
256        adc     bp, 0
257        add     si, bp
258        adc     si, 0
259
260.readEntry:
261        mov     dl,bh
262        in      al,dx
263        shr     al,1            ; data ready (byte 1)?
264        mov     dl,bl           ; get ready to read data
265        jnc     .readTimeout    ; nope not ready, update timeouts
266
267;
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).
270;
271.readByte1Ready:
272        in      al, dx          ; read data byte 1
273
274        mov     ah, al          ; store byte in ah for now
275
276;
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
281; .read_byte2_ready)
282;
283        mov     dl,bh
284
285        in      al,dx
286        shr     al,1            ; data ready (byte 2)?
287        jnc     .readTimeout
288.readByte2Ready:
289        mov     dl,bl
290        in      al, dx          ; read data byte 2
291
292        xchg    al, ah          ; ah was holding byte 1, reverse byte order
293
294        loop    .readLoop
295
296        sti                     ; interrupts back on ASAP, between packets
297
298;
299; Compare checksums
300;
301        xchg    ax,bp
302        xor     ah,al
303        mov     cx,si
304        xor     cl,ch
305        mov     al,cl
306        cmp     ax,bp
307        jnz     SerialCommand_OutputWithParameters_Error
308
309        pop     ax              ; sector count and command byte
310        dec     al              ; decrement sector count
311        push    ax              ; save
312        jz      SerialCommand_OutputWithParameters_ReturnCodeInAL
313
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
317
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...
321
322;
323; Normalize buffer pointer for next go round, if needed.
324;
325; We need to re-normalize the pointer in ES:DI after processing every 7f sectors.  That number could
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
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
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
339; function also appear to be capped at 127 sectors.  So although this can support the full 256 sectors
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)
354
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
358                                        ; fe moves to 0 and OF=0, SF=0, so OF=SF
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
364;       jpo     short .nextSector       ; if we really wanted to avoid normalizing for ff, this
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
371%else
372
373        jmp     short .nextSector
374
375%endif
376
377;---------------------------------------------------------------------------
378;
379; Cleanup, error reporting, and exit
380;
381
382;
383; Used in situations where a call is underway, such as with SerialCommand_WaitAndPoll
384;
385ALIGN JUMP_ALIGN
386SerialCommand_OutputWithParameters_ErrorAndPop4Words:
387        add     sp,8
388;;; fall-through
389
390ALIGN JUMP_ALIGN
391SerialCommand_OutputWithParameters_Error:
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;
400        xor     cx,cx                   ; timeout this clearing routine, in case the UART isn't there
401.clearBuffer:
402        mov     dl,bh
403        in      al,dx
404        mov     dl,bl
405        test    al,08fh
406        jz      .clearBufferComplete
407        test    al,1
408        in      al,dx
409        loopnz  .clearBuffer            ; note ZF from test above
410
411.clearBufferComplete:
412        mov     al, 3           ;  error return code and CF (low order bit)
413
414ALIGN JUMP_ALIGN
415SerialCommand_OutputWithParameters_ReturnCodeInAL:
416%if 0
417        sti                     ;  all paths here will already have interrupts turned back on
418%endif
419        mov     ah, al          ;  for success, AL will already be zero
420
421        pop     bx              ;  recover "ax" (command and count) from stack
422
423        pop     bp
424        pop     di
425        pop     si
426
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
433        ret
434
435;--------------------------------------------------------------------
436; SerialCommand_WriteProtocol
437;
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.
441;
442;   Parameters:
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)
448;   Returns:
449;       BP/DI:  Checksum for written bytes, compared against ACK from server in .readLoop
450;       CX:     Zero
451;       DL:     Receive/Transmit Register address
452;   Corrupts registers:
453;       AX
454;--------------------------------------------------------------------
455ALIGN JUMP_ALIGN
456SerialCommand_WriteProtocol:
457.writeLoop:
458        es lodsw                ; fetch next word
459
460        out     dx,al           ; output first byte
461
462        add     bp,ax           ; update checksum
463        adc     bp,0
464        add     di,bp
465        adc     di,0
466
467        mov     dl,bh           ; transmit buffer empty?
468        in      al,dx
469        test    al,20h
470        jz      .writeTimeout2  ; nope, use our polling routine
471
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
497        ret
498
499.writeTimeout2:
500        mov     dl,ah           ; need to preserve AH, but don't need DL (will be reset upon return)
501        call    SerialCommand_WaitAndPoll_Write
502        mov     ah,dl
503        jmp     .writeByte2Ready
504
505.writeTimeout1:
506%ifndef USE_186
507        mov     ax,.writeByte1Ready
508        push    ax              ; return address for ret at end of SC_writeTimeout2
509%else
510        push    .writeByte1Ready
511%endif
512;;; fall-through
513
514;--------------------------------------------------------------------
515; SerialCommand_WaitAndPoll
516;
517;   Parameters:
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)
521;       BX:
522;       Stack:  2 words on the stack below the command/count word
523;   Returns:
524;       Returns when desired UART_LineStatus bit is cleared
525;       Jumps directly to error exit if timeout elapses (and cleans up stack)
526;   Corrupts registers:
527;       AX
528;--------------------------------------------------------------------
529
530SerialCommand_WaitAndPoll_SoftDelayTicks   EQU   20
531
532ALIGN JUMP_ALIGN
533SerialCommand_WaitAndPoll_Write:
534        mov     ah,20h
535;;; fall-through
536
537ALIGN JUMP_ALIGN
538SerialCommand_WaitAndPoll_Read:
539        push    cx
540        push    dx
541
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:
547        mov     dl,bh
548        in      al,dx
549        test    al,ah
550        jnz     .readTimeoutComplete
551        loop    .readTimeoutLoop
552
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
567
568.readTimeoutComplete:
569        pop     dx
570        pop     cx
571        ret
572
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
582;               NOTE: Not set (or checked) during drive detection
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:
589;
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.
593;
594; But drive detection isn't the only case - we also need to get the right drive when called on int13h/25h.
595;
596; The decision tree:
597;
598;    Master:
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)
603;
604;    Slave:
605;          wSerialPortAndBaud Non-Zero:
606;              previous serial drive not found:   -> Error - Not Found (4)
607;              previous serial drive found:       -> Continue with wSerialPackedAndBaud (5)
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)
611;
612; (1) This was a port/baud that was explicitly set with the configurator.  In the drive detection case, as this
613;     is the Master, we are checking out a new controller, and so don't care if we already have a serial drive.
614;     And as with the int13h/25h case, we just go off and get the needed information using the user's setting.
615; (2) We are using the special .ideVarsSerialAuto structure.  During drive detection, we would only be here
616;     if we hadn't already seen a serial drive (since we only scan if no explicit drives are set),
617;     so we go off to scan.
618; (3) We are using the special .ideVarsSerialAuto structure.  We won't get here during drive detection, but
619;     we might get here on an int13h/25h call.  If we have scanned COM drives, they are the ONLY serial drives
620;     in use, and so we use the values from the previously seen serial drive DPT.
621; (4) No master has been found yet, therefore no slave should be found.  Avoiding the slave reduces boot time,
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,
624;     we will do the slave scan, which isn't harmful, it just wastes time.  But the most common case (by a wide
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
627;     controller scenario being called with int13h/25h, we need to use the value in bSerialPackedPortAndBaud
628;     to make sure we get the proper drive.
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
632;     master scan.
633;
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
640%ifdef MODULE_SERIAL_FLOPPY
641        jnc     .founddpt
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
649        jnc     .notfounddpt
650%endif
651        mov     ax, [di+DPT_SERIAL.wSerialPortAndBaud]
652.notfounddpt:
653
654        test    bh, FLG_DRVNHEAD_DRV
655        jz      .master
656
657        test    ax,ax           ; Take care of the case that is different between master and slave.
658        jz      .error          ; Because we do this here, the jz after the "or" below will not be taken
659
660; fall-through
661.master:
662        test    dx,dx
663        jnz     .identifyDeviceInDX
664
665        or      dx,ax           ; Since DX is zero, this effectively moves the previously found serial drive
666                                ; information to dx, as well as test for zero
667        jz      .scanSerial
668
669; fall-through
670.identifyDeviceInDX:
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
680
681        push    bx
682
683        mov     bp,sp
684        call    SerialCommand_OutputWithParameters_DeviceInDX
685
686        pop     bx
687
688        pop     cx
689        pop     dx
690
691        pop     bp
692;
693; place port and baud word in to the return sector, in a vendor specific area,
694; which is read by FinalizeDPT and DetectDrives
695;
696        mov     [es:si+ATA6.wSerialPortAndBaud],dx
697
698.notFound:
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.
706;
707
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
716
717ALIGN JUMP_ALIGN
718.scanSerial:
719        mov     di,.scanPortAddresses-1
720        mov     ch,1            ;  tell server that we are scanning
721
722.nextPort:
723        inc     di              ; load next port address
724        xor     dh, dh
725        mov     dl,[cs:di]
726        eSHL_IM dx, 2           ; shift from one byte to two
727        jz      .error
728
729;
730; Test for COM port presence, write to and read from registers
731;
732        push    dx
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
739        jnz     .nextPort
740
741        mov     al, 0ch
742        out     dx, al
743        in      al, dx
744        cmp     al, 0ch
745        jnz     .nextPort
746
747;
748; Begin baud rate scan on this port...
749;
750; On a scan, we support 6 baud rates, starting here and going higher by a factor of two each step, with a
751; small jump between 9600 and 38800.  These 6 were selected since we wanted to support 9600 baud and 115200,
752; *on the server side* if the client side had a 4x clock multiplier, a 2x clock multiplier, or no clock multiplier.
753;
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)
756;
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
762.nextBaud:
763        shr     dh,1
764        jz      .nextPort
765        cmp     dh,6            ; skip from 6 to 4, to move from the top of the 9600 baud range
766        jnz     .testBaud       ; to the bottom of the 115200 baud range
767        mov     dh,4
768
769.testBaud:
770        call    .identifyDeviceInDX
771        jc      .nextBaud
772
773        ret
774
775.error:
776        stc
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
781        ret
782
783
Note: See TracBrowser for help on using the repository browser.