Changeset 277 in xtideuniversalbios for trunk/XTIDE_Universal_BIOS/Src/Device/Serial
- Timestamp:
- Feb 28, 2012, 2:45:48 PM (13 years ago)
- google:author:
- gregli@hotmail.com
- Location:
- trunk/XTIDE_Universal_BIOS/Src/Device/Serial
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/XTIDE_Universal_BIOS/Src/Device/Serial/SerialCommand.asm
r262 r277 4 4 ; Section containing code 5 5 SECTION .text 6 7 ;--------------- UART Equates -----------------------------8 ;9 ; Serial Programming References:10 ; http://en.wikibooks.org/wiki/Serial_Programming11 ;12 13 SerialCommand_UART_base EQU 014 SerialCommand_UART_transmitByte EQU 015 SerialCommand_UART_receiveByte EQU 016 17 ;18 ; Values for UART_divisorLow:19 ; 60h = 1200, 30h = 2400, 18h = 4800, 0ch = 9600, 6 = 19200, 4 = 28800, 3 = 38400, 2 = 57600, 1 = 11520020 ;21 SerialCommand_UART_divisorLow EQU 022 23 ;24 ; UART_divisorHigh is zero for all speeds including and above 1200 baud (which is all we do)25 ;26 SerialCommand_UART_divisorHigh EQU 127 28 SerialCommand_UART_interruptIdent EQU 229 SerialCommand_UART_FIFOControl EQU 230 31 SerialCommand_UART_lineControl EQU 332 33 SerialCommand_UART_modemControl EQU 434 35 SerialCommand_UART_lineStatus EQU 536 37 SerialCommand_UART_modemStatus EQU 638 39 SerialCommand_UART_scratch EQU 740 41 SerialCommand_Protocol_Write EQU 342 SerialCommand_Protocol_Read EQU 243 SerialCommand_Protocol_Inquire EQU 044 SerialCommand_Protocol_Header EQU 0a0h45 6 46 7 ;-------------------------------------------------------------------- … … 64 25 SerialCommand_OutputWithParameters: 65 26 66 mov ah, (SerialCommand_Protocol_Header | SerialCommand_Protocol_Read)27 mov ah,SerialServer_Command_Read 67 28 68 29 mov al,[bp+IDEPACK.bCommand] … … 70 31 cmp al,20h ; Read Sectors IDE command 71 32 jz .readOrWrite 72 inc ah ; now Serial Command_Protocol_Write33 inc ah ; now SerialServer_Protocol_Write 73 34 cmp al,30h ; Write Sectors IDE command 74 35 jz .readOrWrite … … 85 46 mov dx, [di+DPT_SERIAL.wSerialPortAndBaud] 86 47 87 ; fall-through 48 jmp SerialServer_SendReceive 88 49 89 ;--------------------------------------------------------------------90 ; SerialCommand_OutputWithParameters_DeviceInDX91 ; Parameters:92 ; AH: Protocol Command93 ; DX: Packed I/O port and baud rate94 ; ES:SI: Ptr to buffer (for data transfer commands)95 ; SS:BP: Ptr to IDEREGS_AND_INTPACK96 ; Returns:97 ; AH: INT 13h Error Code98 ; CF: Cleared if success, Set if error99 ; Corrupts registers:100 ; AL, BX, CX, DX, (ES:SI for data transfer commands)101 ;--------------------------------------------------------------------102 SerialCommand_OutputWithParameters_DeviceInDX:103 104 push si105 push di106 push bp107 108 ;109 ; Unpack I/O port and baud from DPT110 ; Port to DX for the remainder of the routine (+/- different register offsets)111 ; Baud in CH until UART initialization is complete112 ;113 mov ch,dh114 xor dh,dh115 eSHL_IM dx, 2 ; shift from one byte to two116 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 access121 ;122 push ax123 124 %if 0125 cld ; Shouldn't be needed. DF has already been cleared (line 24, Int13h.asm)126 %endif127 128 ;----------------------------------------------------------------------129 ;130 ; Initialize UART131 ;132 ; We do this each time since DOS (at boot) or another program may have133 ; decided to reprogram the UART134 ;135 mov bl,dl ; setup BL with proper values for read/write loops (BH comes later)136 137 mov al,83h138 add dl,SerialCommand_UART_lineControl139 out dx,al140 141 mov al,ch142 mov dl,bl ; divisor low143 out dx,al144 145 xor ax,ax146 inc dx ; divisor high147 push dx148 out dx,al149 150 mov al,047h151 inc dx ; fifo152 out dx,al153 154 mov al,03h155 inc dx ; linecontrol156 out dx,al157 158 mov al,0bh159 inc dx ; modemcontrol160 out dx,al161 162 inc dx ; linestatus (no output now, just setting up BH for later use)163 mov bh,dl164 165 pop dx ; base, interrupts disabled166 xor ax,ax167 out dx,al168 169 ;----------------------------------------------------------------------170 ;171 ; Send Command172 ;173 ; Sends first six bytes of IDEREGS_AND_INTPACK as the command174 ;175 push es ; save off real buffer location176 push si177 178 mov si,bp ; point to IDEREGS for command dispatch;179 push ss180 pop es181 182 mov di,0ffffh ; initialize checksum for write183 mov bp,di184 185 mov cx,4 ; writing 3 words (plus 1)186 187 cli ; interrupts off...188 189 call SerialCommand_WriteProtocol.entry190 191 pop di ; restore real buffer location (note change from SI to DI)192 ; Buffer is primarily referenced through ES:DI throughout, since193 ; we need to store (read sector) faster than we read (write sector)194 pop es195 196 %if 0197 ;;; no longer needed, since the pointer is normalized before we are called and we do not support198 ;;; 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_NormalizeESDI202 %endif203 204 pop ax ; load command byte (done before call to .nextSector on subsequent iterations)205 push ax206 207 ;208 ; Top of the read/write loop, one iteration per sector209 ;210 .nextSector:211 mov si,0ffffh ; initialize checksum for read or write212 mov bp,si213 214 mov cx,0101h ; writing 256 words (plus 1)215 216 shr ah,1 ; command byte, are we doing a write?217 jnc .readEntry218 219 xchg si,di220 call SerialCommand_WriteProtocol.entry221 xchg si,di222 223 inc cx ; CX = 1 now (0 out of WriteProtocol)224 jmp .readEntry225 226 ;----------------------------------------------------------------------227 ;228 ; Timeout229 ;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 also234 ; means the stack has the same number of bytes on it as when we are235 ; sending a packet, important for error cleanup and exit236 mov ah,1237 call SerialCommand_WaitAndPoll_Read238 pop ax239 test dl,1240 jz .readByte1Ready241 jmp .readByte2Ready242 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 instruction248 ; cannot be inserted into this loop without us falling behind at high249 ; speed (460.8K baud) on a 4.77Mhz 8088, making it hard to receive250 ; a full 512 byte block.251 ;252 .readLoop:253 stosw ; store word in caller's data buffer254 255 add bp, ax ; update Fletcher's checksum256 adc bp, 0257 add si, bp258 adc si, 0259 260 .readEntry:261 mov dl,bh262 in al,dx263 shr al,1 ; data ready (byte 1)?264 mov dl,bl ; get ready to read data265 jnc .readTimeout ; nope not ready, update timeouts266 267 ;268 ; Entry point after initial timeout. We enter here so that the checksum word269 ; is not stored (and is left in AX after the loop is complete).270 ;271 .readByte1Ready:272 in al, dx ; read data byte 1273 274 mov ah, al ; store byte in ah for now275 276 ;277 ; note the placement of this reset of dl to bh, and that it is278 ; before the return, which is assymetric with where this is done279 ; above for byte 1. The value of dl is used by the timeout routine280 ; to know which byte to return to (.read_byte1_ready or281 ; .read_byte2_ready)282 ;283 mov dl,bh284 285 in al,dx286 shr al,1 ; data ready (byte 2)?287 jnc .readTimeout288 .readByte2Ready:289 mov dl,bl290 in al, dx ; read data byte 2291 292 xchg al, ah ; ah was holding byte 1, reverse byte order293 294 loop .readLoop295 296 sti ; interrupts back on ASAP, between packets297 298 ;299 ; Compare checksums300 ;301 xchg ax,bp302 xor ah,al303 mov cx,si304 xor cl,ch305 mov al,cl306 cmp ax,bp307 jnz SerialCommand_OutputWithParameters_Error308 309 pop ax ; sector count and command byte310 dec al ; decrement sector count311 push ax ; save312 jz SerialCommand_OutputWithParameters_ReturnCodeInAL313 314 cli ; interrupts back off for ACK byte to host315 ; (host could start sending data immediately)316 out dx,al ; ACK with next sector number317 318 %if 0319 ;;; This code is no longer needed as we do not support more than 128 sectors, and for 128 the pointer320 ;;; 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 could326 ; 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 sectors331 ; c) on transitions from 80 to 7F, a large read/write332 ; d) on transitions from 00 to FF, very, very rare case of writing 256 sectors333 ; We don't need to renormalize in this case, but it isn't worth the memory/effort to not do334 ; 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 request337 ; for more than 127 sectors. Back in the day, it appears that some BIOS could not support more than 127338 ; sectors, so that may be the practical limit for OS and application developers. The Extended BIOS339 ; function also appear to be capped at 127 sectors. So although this can support the full 256 sectors340 ; 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:020f344 ; First decrement of AL, transition from 00 to FF: renormalize to 0020:000f (unnecessary)345 ; After second packet, 0020:020f346 ; Second derement of AL, transition from FF to FE: renormalize to 0040:000f347 ; After 7f more packets, 0040:fe0f348 ; Decrement of AL, transition from 80 to 7F: renormalize to 1020:000f349 ; After 7f more packets, 1020:fe0f or 2000:000f if normalized350 ; Decrement of AL, from 1 to 0: exit351 ;352 jge short .nextSector ; OF=SF, branch for 1-7e, most common case353 ; (0 kicked out above for return success)354 355 add al,2 ; 7f-ff moves to 81-01356 ; (0-7e kicked out before we get here)357 ; 7f moves to 81 and OF=1, so OF=SF358 ; fe moves to 0 and OF=0, SF=0, so OF=SF359 ; ff moves to 1 and OF=0, SF=0, so OF=SF360 ; 80-fd moves to 82-ff and OF=0, so OF<>SF361 362 jl short .nextSector ; OF<>SF, branch for all cases but 7f, fe, and ff363 364 ; jpo short .nextSector ; if we really wanted to avoid normalizing for ff, this365 ; is one way to do it, but it adds more memory and more366 ; cycles for the 7f and fe cases. IMHO, given that I've367 ; 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 %else372 373 jmp short .nextSector374 375 %endif376 377 ;---------------------------------------------------------------------------378 ;379 ; Cleanup, error reporting, and exit380 ;381 382 ;383 ; Used in situations where a call is underway, such as with SerialCommand_WaitAndPoll384 ;385 ALIGN JUMP_ALIGN386 SerialCommand_OutputWithParameters_ErrorAndPop4Words:387 add sp,8388 ;;; fall-through389 390 ALIGN JUMP_ALIGN391 SerialCommand_OutputWithParameters_Error:392 ;----------------------------------------------------------------------393 ;394 ; Clear read buffer395 ;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 have398 ; 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 there401 .clearBuffer:402 mov dl,bh403 in al,dx404 mov dl,bl405 test al,08fh406 jz .clearBufferComplete407 test al,1408 in al,dx409 loopnz .clearBuffer ; note ZF from test above410 411 .clearBufferComplete:412 mov al, 3 ; error return code and CF (low order bit)413 414 ALIGN JUMP_ALIGN415 SerialCommand_OutputWithParameters_ReturnCodeInAL:416 %if 0417 sti ; all paths here will already have interrupts turned back on418 %endif419 mov ah, al ; for success, AL will already be zero420 421 pop bx ; recover "ax" (command and count) from stack422 423 pop bp424 pop di425 pop si426 427 mov ch, 0428 mov cl,[bp+IDEPACK.bSectorCount]429 sub cl, bl ; subtract off the number of sectors that remained430 431 shr ah, 1 ; shift down return code and CF432 433 ret434 435 ;--------------------------------------------------------------------436 ; SerialCommand_WriteProtocol437 ;438 ; NOTE: As with its read counterpart, this loop is very time sensitive.439 ; Although it will still function, adding additional instructions will440 ; impact the write throughput, especially on slower machines.441 ;442 ; Parameters:443 ; ES:SI: Ptr to buffer444 ; CX: Words to write, plus 1445 ; BP/DI: Initialized for Checksum (-1 in each)446 ; DH: I/O Port high byte447 ; 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 .readLoop450 ; CX: Zero451 ; DL: Receive/Transmit Register address452 ; Corrupts registers:453 ; AX454 ;--------------------------------------------------------------------455 ALIGN JUMP_ALIGN456 SerialCommand_WriteProtocol:457 .writeLoop:458 es lodsw ; fetch next word459 460 out dx,al ; output first byte461 462 add bp,ax ; update checksum463 adc bp,0464 add di,bp465 adc di,0466 467 mov dl,bh ; transmit buffer empty?468 in al,dx469 test al,20h470 jz .writeTimeout2 ; nope, use our polling routine471 472 .writeByte2Ready:473 mov dl,bl474 mov al,ah ; output second byte475 out dx,al476 477 .entry:478 mov dl,bh ; transmit buffer empty?479 in al,dx480 test al,20h481 mov dl,bl482 jz .writeTimeout1 ; nope, use our polling routine483 484 .writeByte1Ready:485 loop .writeLoop486 487 mov ax,di ; fold Fletcher's checksum and output488 xor al,ah489 out dx,al ; byte 1490 491 call SerialCommand_WaitAndPoll_Write492 493 mov ax,bp494 xor al,ah495 out dx,al ; byte 2496 497 ret498 499 .writeTimeout2:500 mov dl,ah ; need to preserve AH, but don't need DL (will be reset upon return)501 call SerialCommand_WaitAndPoll_Write502 mov ah,dl503 jmp .writeByte2Ready504 505 .writeTimeout1:506 %ifndef USE_186507 mov ax,.writeByte1Ready508 push ax ; return address for ret at end of SC_writeTimeout2509 %else510 push .writeByte1Ready511 %endif512 ;;; fall-through513 514 ;--------------------------------------------------------------------515 ; SerialCommand_WaitAndPoll516 ;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 write520 ; DX: Port address (OK if already incremented to UART_lineStatus)521 ; BX:522 ; Stack: 2 words on the stack below the command/count word523 ; Returns:524 ; Returns when desired UART_LineStatus bit is cleared525 ; Jumps directly to error exit if timeout elapses (and cleans up stack)526 ; Corrupts registers:527 ; AX528 ;--------------------------------------------------------------------529 530 SerialCommand_WaitAndPoll_SoftDelayTicks EQU 20531 532 ALIGN JUMP_ALIGN533 SerialCommand_WaitAndPoll_Write:534 mov ah,20h535 ;;; fall-through536 537 ALIGN JUMP_ALIGN538 SerialCommand_WaitAndPoll_Read:539 push cx540 push dx541 542 ;543 ; We first poll in a tight loop, interrupts off, for the next character to come in/be sent544 ;545 xor cx,cx546 .readTimeoutLoop:547 mov dl,bh548 in al,dx549 test al,ah550 jnz .readTimeoutComplete551 loop .readTimeoutLoop552 553 ;554 ; If that loop completes, then we assume there is a long delay involved, turn interrupts back on555 ; and wait for a given number of timer ticks to pass.556 ;557 sti558 mov cl,SerialCommand_WaitAndPoll_SoftDelayTicks559 call Timer_InitializeTimeoutWithTicksInCL560 .WaitAndPoll:561 call Timer_SetCFifTimeout562 jc SerialCommand_OutputWithParameters_ErrorAndPop4Words563 in al,dx564 test al,ah565 jz .WaitAndPoll566 cli567 568 .readTimeoutComplete:569 pop dx570 pop cx571 ret572 50 573 51 ;-------------------------------------------------------------------- … … 579 57 ; CS:BP: Ptr to IDEVARS 580 58 ; Returns: 581 ; AH: INT 13h Error Code582 ; NOTE: Not set (or checked) during drive detection583 59 ; CF: Cleared if success, Set if error 584 60 ; Corrupts registers: … … 632 108 ; master scan. 633 109 ; 634 mov cx,1 ; 1 sector to move, 0 for non-scan635 110 mov dx,[cs:bp+IDEVARS.wSerialPortAndBaud] 636 111 xor ax,ax 112 637 113 push si 638 114 call FindDPT_ToDSDIforSerialDevice … … 642 118 ; 643 119 ; If not found above with FindDPT_ToDSDIforSerialDevice, DI will point to the DPT after the last hard disk DPT 120 ; So, if there was a previously found floppy disk, DI will point to that DPT and we use that value for the slave. 644 121 ; 645 122 cmp byte [RAMVARS.xlateVars+XLATEVARS.bFlopCntAndFirst], 0 … … 647 124 .founddpt: 648 125 %else 649 j nc .notfounddpt126 jc .notfounddpt 650 127 %endif 651 128 mov ax, [di+DPT_SERIAL.wSerialPortAndBaud] … … 656 133 657 134 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 taken135 jz .error 659 136 660 137 ; fall-through … … 663 140 jnz .identifyDeviceInDX 664 141 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 142 xchg dx, ax ; move ax to dx (move previously found serial drive to dx, could be zero) 668 143 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 717 ALIGN 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 144 .identifyDeviceInDX: 145 jmp SerialServerScan_ScanForServer 774 146 775 147 .error: 776 148 stc 777 %if 0778 mov ah,1 ; setting the error code is unnecessary as this path can only be taken during779 ; drive detection, and drive detection works off CF and does not check AH780 %endif781 149 ret 782 783 -
trunk/XTIDE_Universal_BIOS/Src/Device/Serial/SerialDPT.asm
r258 r277 17 17 ;-------------------------------------------------------------------- 18 18 SerialDPT_Finalize: 19 mov ax, [es:si+ ATA6.wSerialPortAndBaud]19 mov ax, [es:si+SerialServer_ATA_wPortAndBaud] 20 20 mov [di+DPT_SERIAL.wSerialPortAndBaud], ax 21 21 22 22 ; 23 23 ; Note that this section is not under %ifdef MODULE_SERIAL_FLOPPY. It is important to 24 ; d etect floppy disks presented by the server and not treat them likehard disks, even24 ; distinguish floppy disks presented by the server and not treat them as hard disks, even 25 25 ; if the floppy support is disabled. 26 26 ; 27 mov al, [es:si+ ATA6.wSerialFloppyFlagAndType]27 mov al, [es:si+SerialServer_ATA_wFloppyFlagAndType] 28 28 or al, FLGH_DPT_SERIAL_DEVICE 29 29 or byte [di+DPT.bFlagsHigh], al
Note:
See TracChangeset
for help on using the changeset viewer.