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

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

Serial port code - improved pointer re-normalization.

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