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

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

Moved .bSerialPortAndBaud out of the main DPT into a an attached struc DPT_SERIAL, used by the serial port code only

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