Changeset 179 in xtideuniversalbios for trunk/XTIDE_Universal_BIOS/Src/Device/Serial


Ignore:
Timestamp:
Oct 25, 2011, 7:11:38 AM (13 years ago)
Author:
gregli@…
google:author:
gregli@hotmail.com
Message:

Main checkin, adding virtual IDE drive over serial port connection

Location:
trunk/XTIDE_Universal_BIOS/Src/Device/Serial
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/XTIDE_Universal_BIOS/Src/Device/Serial/SerialCommand.asm

    r150 r179  
    44; Section containing code
    55SECTION .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
     16SerialCommand_UART_divisorLow                   EQU     0
     17; Values for UART_divisorLow:   
     18; 60h = 1200, 30h = 2400, 18h = 4800, 0ch = 9600, 6 = 19200, 3 = 38400, 2 = 57600, 1 = 115200
     19
     20SerialCommand_UART_divisorLow_startingBaud      EQU   030h
     21; We support 4 baud rates, starting here going higher and skipping every other baud rate
     22; Starting with 30h, that means 30h (1200 baud), 0ch (9600 baud), 3 (38400 baud), and 1 (115200 baud)
     23; Note: hardware baud multipliers (2x, 4x) will impact the final baud rate and are not known at this level
     24
     25SerialCommand_UART_interruptEnable              EQU     1               
     26SerialCommand_UART_divisorHigh                  EQU     1
     27; UART_divisorHigh is zero for all speeds including and above 1200 baud
     28
     29SerialCommand_UART_interruptIdent               EQU     2
     30SerialCommand_UART_FIFOControl                  EQU     2
     31
     32SerialCommand_UART_lineControl                  EQU     3
     33       
     34SerialCommand_UART_modemControl                 EQU     4
     35
     36SerialCommand_UART_lineStatus                   EQU     5
     37
     38SerialCommand_UART_modemStatus                  EQU     6
     39
     40SerialCommand_UART_scratch                      EQU     7
     41
     42SerialCommand_PackedPortAndBaud_StartingPort    EQU     240h   
     43SerialCommand_PackedPortAndBaud_PortMask        EQU     0fch    ; upper 6 bits - 240h through 438h
     44SerialCommand_PackedPortAndBaud_BaudMask        EQU     3       ; lower 2 bits - 4 baud rates
     45
     46SerialCommand_Protocol_Write                    EQU     3
     47SerialCommand_Protocol_Read                     EQU     2
     48SerialCommand_Protocol_Inquire                  EQU     0
     49SerialCommand_Protocol_Header                   EQU     0a0h
     50       
     51;--------------------------------------------------------------------
     52; SerialCommand_OutputWithParameters
     53;   Parameters:
     54;       BH:     Non-zero if 48-bit addressing used
     55;               (ignored at present as 48-bit addressing is not supported)
     56;       BL:     IDE Status Register bit to poll after command
     57;               (ignored at present, since there is no IDE status register to poll)
     58;       ES:SI:  Ptr to buffer (for data transfer commands)
     59;       DS:DI:  Ptr to DPT (in RAMVARS segment)
     60;       SS:BP:  Ptr to IDEREGS_AND_INTPACK
     61;   Returns:
     62;       AH:     INT 13h Error Code
     63;       CF:     Cleared if success, Set if error
     64;   Corrupts registers:
     65;       AL, BX, CX, DX, (ES:SI for data transfer commands)
     66;--------------------------------------------------------------------
     67
     68ALIGN JUMP_ALIGN
     69SerialCommand_OutputWithParameters:
     70       
     71        mov     ah,(SerialCommand_Protocol_Header | SerialCommand_Protocol_Read)
     72       
     73        mov     al,[bp+IDEPACK.bCommand]
     74
     75        cmp     al,20h          ; Read Sectors IDE command
     76        jz      .readOrWrite
     77        inc     ah              ; now SerialCommand_Protocol_Write
     78        cmp     al,30h          ; Write Sectors IDE command
     79        jz      .readOrWrite
     80       
     81;  all other commands return success
     82;  including function 0ech which should return drive information, this is handled with the identify functions
     83        xor     ah,ah           ;  also clears carry
     84        ret
     85       
     86.readOrWrite:   
     87        mov     [bp+IDEPACK.bFeatures],ah       ; store protocol command
     88       
     89        mov     dl, byte [ds:di+DPT.bSerialPortAndBaud]
     90       
     91; fall-through
     92
     93;--------------------------------------------------------------------
     94; SerialCommand_OutputWithParameters_DeviceInDL
     95;   Parameters:
     96;       AH:     Protocol Command
     97;       DL:     Packed I/O port and baud rate
     98;       ES:SI:  Ptr to buffer (for data transfer commands)
     99;       SS:BP:  Ptr to IDEREGS_AND_INTPACK
     100;   Returns:
     101;       AH:     INT 13h Error Code
     102;       CF:     Cleared if success, Set if error
     103;   Corrupts registers:
     104;       AL, BX, CX, DX, (ES:SI for data transfer commands)
     105;--------------------------------------------------------------------       
     106SerialCommand_OutputWithParameters_DeviceInDL:
     107       
     108        push    si
     109        push    di
     110        push    bp
     111        push    es
     112
     113;
     114; Unpack I/O port and baud from DPT
     115;       Port to DX more or less for the remainder of the routine
     116;       Baud in CH until UART initialization is complete
     117;
     118        mov     cl, dl
     119       
     120        and     cl, SerialCommand_PackedPortAndBaud_BaudMask
     121        shl     cl, 1
     122        mov     ch, SerialCommand_UART_divisorLow_startingBaud
     123        shr     ch, cl
     124        adc     ch, 0
     125
     126        and     dl, SerialCommand_PackedPortAndBaud_PortMask
     127        mov     dh, 0       
     128        shl     dx, 1
     129        add     dx, SerialCommand_PackedPortAndBaud_StartingPort
     130
     131;
     132; Buffer is referenced through ES:DI throughout, since we need to store faster than we read
     133;
     134        mov     di,si
     135
     136        mov     al,[bp+IDEPACK.bSectorCount]
     137
     138;
     139; Command byte and sector count live at the top of the stack, pop/push are used to access
     140;
     141        push    ax
     142       
     143        cld
     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        push    dx
     153       
     154        mov     al,83h
     155        add     dl,SerialCommand_UART_lineControl
     156        out     dx,al
     157
     158        mov     al,ch
     159        pop     dx              ; 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        pop     dx              ; base, interrupts disabled
     180        xor     ax,ax
     181        out     dx,al
     182        dec     dx
     183
     184;----------------------------------------------------------------------
     185;
     186; Send Command
     187;
     188; Sends first six bytes of IDEREGS_AND_INTPACK as the command
     189;
     190        call    Registers_NormalizeESDI
     191
     192        push    es              ; save off real buffer location
     193        push    di
     194       
     195        mov     di,bp           ; point to IDEREGS for command dispatch;       
     196        push    ss
     197        pop     es
     198
     199        xor     si,si           ; initialize checksum for write
     200        dec     si     
     201        mov     bp,si
     202
     203        mov     bl,03h      ; writing 3 words
     204       
     205        call    SerialCommand_WriteProtocol
     206
     207        pop     di              ; restore real buffer location
     208        pop     es
     209
     210        pop     ax              ; load command byte (done before call to .nextSector on subsequent iterations)
     211        push    ax
     212
     213;
     214; Top of the read/write loop, one iteration per sector
     215;
     216.nextSector:
     217        xor     si,si           ; initialize checksum for read or write
     218        dec     si
     219        mov     bp,si
     220
     221        mov     bx,0100h
     222       
     223        shr     ah,1            ; command byte, are we doing a write?
     224        jnc     .readSector
     225        call    SerialCommand_WriteProtocol
     226       
     227        xor     bx,bx
     228
     229.readSector:
     230        mov     cx,bx
     231        inc     cx
     232       
     233        mov     bl,dl           ; setup bl with proper values for read loop (bh comes later)
     234
     235;----------------------------------------------------------------------
     236;
     237; Timeout
     238;
     239; During read, we first poll in a tight loop, interrupts off, for the next character to come in
     240; If that loop completes, then we assume there is a long delay involved, turn interrupts back on
     241; and wait for a given number of timer ticks to pass.
     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    cx
     247        xor     cx,cx
     248.readTimeoutLoop:   
     249        push    dx
     250        or      dl,SerialCommand_UART_lineStatus
     251        in      al,dx
     252        pop     dx
     253        shr     al,1
     254        jc      .readTimeoutComplete
     255        loop    .readTimeoutLoop
     256        sti
     257        mov     bh,1
     258        call    SerialCommand_WaitAndPoll_Init
     259        cli     
     260.readTimeoutComplete:
     261        mov     bh,bl
     262        or      bh,SerialCommand_UART_lineStatus
     263       
     264        pop     cx
     265        test    dl,1
     266        jz      .readByte1Ready
     267        jmp     .readByte2Ready
     268
     269;----------------------------------------------------------------------------
     270;
     271; Read Block (without interrupts, used when there is a FIFO, high speed)
     272;
     273; NOTE: This loop is very time sensitive.  Literally, another instruction
     274; cannot be inserted into this loop without us falling behind at high
     275; speed (460.8K baud) on a 4.77Mhz 8088, making it hard to receive
     276; a full 512 byte block.
     277;
     278.readLoop:     
     279        add     bp, ax          ; update Fletcher's checksum
     280        adc     bp, 0
     281        add     si, bp
     282        adc     si, 0
     283
     284        stosw                   ; store word in caller's data buffer
     285
     286        mov     dl,bh           
     287        in      al,dx           
     288        shr     al,1            ; data ready (byte 1)?
     289        mov     dl,bl           ; get ready to read data           
     290        jnc     .readTimeout    ; nope not ready, update timeouts
     291       
     292;
     293; Entry point after initial timeout.  We enter here so that the checksum word
     294; is not stored (and is left in AX after the loop is complete).
     295;
     296.readByte1Ready:       
     297        in      al, dx          ; read data byte 1
     298
     299        mov     ah, al          ; store byte in ah for now
     300       
     301;
     302; note the placement of this reset of dl to bh, and that it is
     303; before the return, which is assymetric with where this is done
     304; above for byte 1.  The value of dl is used by the timeout routine
     305; to know which byte to return to (.read_byte1_ready or
     306; .read_byte2_ready)
     307;
     308        mov     dl,bh           
     309                               
     310        in      al,dx
     311        shr     al,1            ; data ready (byte 2)?
     312        jnc     .readTimeout
     313.readByte2Ready:                       
     314        mov     dl,bl       
     315        in      al, dx          ; read data byte 2
     316
     317        xchg    al, ah          ; ah was holding byte 1, reverse byte order
     318       
     319        loop    .readLoop
     320
     321;
     322; Compare checksums
     323;
     324        xor     bp,si
     325        cmp     ax,bp
     326        jnz     SerialCommand_OutputWithParameters_Error
     327
     328        sti                 ; interrupts back on ASAP, if we turned them off
     329       
     330;----------------------------------------------------------------------
     331;
     332; Clear read buffer
     333;
     334; In case there are extra characters or an error in the FIFO, clear it out.
     335; In theory the initialization of the UART registers above should have
     336; taken care of this, but I have seen cases where this is not true.
     337;
     338.clearBuffer:
     339        mov     dl,bh       
     340        in      al,dx
     341        mov     dl,bl               
     342        test    al,08fh
     343        jz      .clearBufferComplete
     344        shr     al,1
     345        in      al,dx       
     346        jc      .clearBuffer    ; note CF from shr above
     347        jmp     SerialCommand_OutputWithParameters_Error
     348       
     349.clearBufferComplete:   
     350        pop     ax              ; sector count and command byte
     351        dec     al              ; decrememnt sector count
     352        push    ax              ; save
     353        jz      SerialCommand_OutputWithParameters_ReturnCodeInALCF    ; CF clear from .clearBuffer test above
     354               
     355        cli                     ; interrupts back off for ACK byte to host
     356                                ; (host could start sending data immediately)
     357        out     dx,al           ; ACK with next sector number
     358       
     359        jmp     .nextSector     ; all is well, time for next sector
     360
     361;---------------------------------------------------------------------------
     362;
     363; Cleanup, error reporting, and exit
     364;
     365       
     366;
     367; Used in situations where a call is underway, such as with SerialCommand_WaitAndPoll
     368;
     369SerialCommand_OutputWithParameters_ErrorAndPop2Words:
     370        pop     ax
     371        pop     ax
     372
     373SerialCommand_OutputWithParameters_Error:       
     374        mov     al,1
     375        stc
     376
     377SerialCommand_OutputWithParameters_ReturnCodeInALCF:   
     378        mov     ah,al
     379        sti
     380
     381        pop     bp              ;  recover ax from stack, throw away
     382
     383        pop     es
     384        pop     bp
     385        pop     di
     386        pop     si
     387
     388        ret
     389
     390;--------------------------------------------------------------------
     391; SerialCommand_WaitAndPoll
     392;
     393;   Parameters:
     394;       BH:     UART_LineStatus bit to test (20h for write, or 1h for read)
     395;       DX:     Port address (OK if already incremented to UART_lineStatus)
     396;       Stack:  2 words on the stack below the command/count word
     397;   Returns:
     398;       Returns when desired UART_LineStatus bit is cleared
     399;       Jumps directly to error exit if timeout elapses (and cleans up stack)
     400;   Corrupts registers:
     401;       CX, flags
     402;--------------------------------------------------------------------
     403
     404SerialCommand_WaitAndPoll_SoftDelayTicks   EQU   20
     405
     406ALIGN JUMP_ALIGN               
     407SerialCommand_WaitAndPoll_Init:
     408        mov     cl,SerialCommand_WaitAndPoll_SoftDelayTicks
     409        call    Timer_InitializeTimeoutWithTicksInCL
     410; fall-through
     411       
     412SerialCommand_WaitAndPoll:
     413        call    Timer_SetCFifTimeout
     414        jc      SerialCommand_OutputWithParameters_ErrorAndPop2Words
     415        push    dx
     416        push    ax
     417        or      dl,SerialCommand_UART_lineStatus
     418        in      al,dx
     419        test    al,bh
     420        pop     ax
     421        pop     dx
     422        jz      SerialCommand_WaitAndPoll
     423; fall-through
     424       
     425SerialCommand_WaitAndPoll_Done:
     426        ret
     427
     428;--------------------------------------------------------------------
     429; SerialCommand_WriteProtocol
     430;
     431;   Parameters:
     432;       ES:DI:  Ptr to buffer
     433;       BL:     Words to write (1-255, or 0=256)
     434;       BP/SI:  Initialized for Checksum (-1 in each)
     435;       DX:     I/O Port
     436;   Returns:
     437;       BP/SI:  Checksum for written bytes, compared against ACK from server in .readLoop
     438;   Corrupts registers:
     439;       AX, BX, CX, DI
     440;--------------------------------------------------------------------
     441ALIGN JUMP_ALIGN
     442SerialCommand_WriteProtocol:
     443        mov     bh,20h
     444       
     445.writeLoop:
     446        test    bh,1
     447        jnz     SerialCommand_WaitAndPoll_Done
     448       
     449        mov     ax,[es:di]      ; fetch next word
     450        inc     di
     451        inc     di
     452       
     453        add     bp,ax           ; update checksum
     454        adc     bp,0
     455        add     si,bp
     456        adc     si,0
     457
     458.writeLoopChecksum:
     459        call    SerialCommand_WaitAndPoll_Init
     460       
     461        out     dx,al           ; output first byte
     462
     463        call    SerialCommand_WaitAndPoll
     464       
     465        mov     al,ah           ; output second byte
     466        out     dx,al
     467
     468        dec     bl
     469        jnz     .writeLoop
     470       
     471        inc     bh
     472       
     473        mov     ax,bp           ; merge checksum for possible write (last loop)
     474        xor     ax,si       
     475       
     476        jmp     .writeLoopChecksum
     477
     478
     479; To return the port number and baud rate to the FinalizeDPT routine, we
     480; stuff the value in a "vendor" specific area of the 512-byte IdentifyDevice
     481; sector.
     482;
     483SerialCommand_IdentifyDevice_PackedPortAndBaud  equ     (157*2)
    6484
    7485;--------------------------------------------------------------------
     
    21499SerialCommand_IdentifyDeviceToBufferInESSIwithDriveSelectByteInBH:
    22500
    23 
    24 ;--------------------------------------------------------------------
    25 ; SerialCommand_OutputWithParameters
    26 ;   Parameters:
    27 ;       BH:     Non-zero if 48-bit addressing used
    28 ;       BL:     IDE Status Register bit to poll after command
    29 ;       ES:SI:  Ptr to buffer (for data transfer commands)
    30 ;       DS:DI:  Ptr to DPT (in RAMVARS segment)
    31 ;       SS:BP:  Ptr to IDEREGS_AND_INTPACK
    32 ;   Returns:
    33 ;       AH:     INT 13h Error Code
    34 ;       CF:     Cleared if success, Set if error
    35 ;   Corrupts registers:
    36 ;       AL, BX, CX, DX, (ES:SI for data transfer commands)
    37 ;--------------------------------------------------------------------
    38 ALIGN JUMP_ALIGN
    39 SerialCommand_OutputWithParameters:
    40 
    41 
     501        mov     dx,[cs:bp+IDEVARS.wPortCtrl]
     502        inc     dx
     503        dec     dx     
     504        jz      SerialCommand_AutoSerial
     505
     506; fall-through
     507SerialCommand_IdentifyDeviceInDL_DriveInBH:     
     508
     509        push    bp              ; setup fake IDEREGS_AND_INTPACK
     510
     511        push    dx
     512
     513        mov     cl,1            ; 1 sector to move
     514        push    cx
     515
     516        mov     bl,0a0h         ; protocol command to ah and onto stack with bh
     517        mov     ah,bl
     518       
     519        push    bx
     520
     521        mov     bp,sp
     522
     523        call    SerialCommand_OutputWithParameters_DeviceInDL
     524
     525        pop     bx
     526       
     527        pop     cx             
     528        pop     dx
     529
     530        pop     bp
     531
     532; place packed port/baud in vendor area of packet, read by FinalizeDPT
     533        mov     byte [es:si+SerialCommand_IdentifyDevice_PackedPortAndBaud], dl
     534
     535        ret
     536
     537;----------------------------------------------------------------------
     538;
     539; SerialCommand_AutoSerial
     540;
     541; When the SerialAuto IDEVARS entry is used, scans the COM ports on the machine for a possible serial connection.
     542;
     543       
     544SerialCommand_ScanPortAddresses:  db  0b8h, 0f8h, 0bch, 0bah, 0fah, 0beh, 0feh, 0
     545; Corresponds to I/O port:             3f8,  2f8,  3e8,  2e8,  2f0,  3e0,  2e0,  260,  368,  268,  360,  270
     546; COM Assignments:                       1,    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,   12
     547
     548ALIGN JUMP_ALIGN                       
     549SerialCommand_AutoSerial:       
     550        mov     di,SerialCommand_ScanPortAddresses-1
     551       
     552.nextPort:
     553        inc     di              ; load next port address
     554        mov     dl,[cs:di]
     555       
     556        mov     dh,0            ; shift from one byte to two
     557        shl     dx,1
     558        shl     dx,1       
     559        jz      .exitNotFound
     560
     561;
     562; Test for COM port presence, write to and read from registers
     563;
     564        push    dx     
     565        add     dl,SerialCommand_UART_lineControl
     566        mov     al, 09ah
     567        out     dx, al
     568        in      al, dx
     569        pop     dx
     570        cmp     al, 09ah
     571        jnz     .nextPort       
     572
     573        mov     al, 0ch
     574        out     dx, al
     575        in      al, dx
     576        cmp     al, 0ch
     577        jnz     .nextPort
     578
     579;
     580; Pack into dl, baud rate starts at 0
     581;
     582        add     dx,-(SerialCommand_PackedPortAndBaud_StartingPort)
     583        shr     dx,1
     584       
     585        jmp     .testFirstBaud
     586
     587;
     588; Walk through 4 possible baud rates
     589;
     590.nextBaud:     
     591        inc     dx
     592        test    dl,3
     593        jz      .nextPort
     594       
     595.testFirstBaud:     
     596        call    SerialCommand_IdentifyDeviceInDL_DriveInBH
     597        jc      .nextBaud
     598
     599        ret
     600               
     601.exitNotFound:
     602        mov     ah,1
     603        stc
     604
     605        ret
  • trunk/XTIDE_Universal_BIOS/Src/Device/Serial/SerialDPT.asm

    r150 r179  
    1616;--------------------------------------------------------------------
    1717SerialDPT_Finalize:
     18        or      byte [di+DPT.bFlagsHigh], FLGH_DPT_SERIAL_DEVICE
     19        mov     al, byte [es:si+SerialCommand_IdentifyDevice_PackedPortAndBaud]
     20        mov     byte [ds:di+DPT.bSerialPortAndBaud], al
     21        ret
     22
     23
Note: See TracChangeset for help on using the changeset viewer.