⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fl_drver.c

📁 ertfs文件系统里面既有完整ucos程序
💻 C
📖 第 1 页 / 共 5 页
字号:
* Inputs:
*   ticks - Fail if more than ticks elapses
*
*  
* Returns:
*   TRUE if the dma transfer was sucessful.
* 
* Description:
*   This function is called when the driver is waiting for a dma transfer to
*   complete. The transfer was set up by fl_dma_setup().
*
*   This routine calls pc_wait_int(ticks) for the floppy to interrupt 
*   and then verifies that the dma channel has reach terminal count.
*   need to do is wait for the floppy interrupt. We seperated the two 
*
*   Note: In a system using programmed transfer the transfer loop 
*   would go inside here. The addresses and could would come from 
*   fl_dma_init().
*
*/

/* DMA registers */
#define STATUS_REGISTER     0x08
#define MASK_REGISTER       0x0a
#define MODE_REGISTER       0x0b
#define FLIPFLOP_REGISTER   0x0c
#define BANK_REGISTER       0x81

/* Channel 2 register bank */
#define ADDRESS_REGISTER    0x04
#define int_REGISTER       0x05

static BOOLEAN fl_waitdma(int ticks)                                     /*__fn__*/
{
byte status;
    if (fl_waitint(ticks))
    {
        /*      Check terminal count flag  */
        status = (byte) INBYTE(STATUS_REGISTER);
        if (status & BIT2)
        {
            return(TRUE);
        }
        else 
        {
            return(FALSE);
        }
    }
    return(FALSE);
}

/*
* Name:
*    fl_dma_init() - Initialize a dma transfer
*
* Summary:
*    BOOLEAN fl_dma_init(DMAPTYPE in_address, word length, BOOLEAN reading)
*
* Inputs:
*   in_address - Address to transfer data to/from
*   length     - Length in bytes to transfer
*   reading    - If TRUE, floppy to memory, else mem to floppy
* Returns:
*   TRUE if the setup was successful. FALSE on a boundary wrap.
* 
* Description:
*   This function is called to set up a dma transfer. 
*
* Porting instructions:
*   This routine should be ported to support your dma controller. If you are
*   using programmed IO the input values should be stored away for use by
*   the transfer routine in fl_waitdma()
*/

dword kvtodma(DMAPTYPE in_address)
{
dword laddress;
#if (FLAT_ADDRESSING || IS_MS_PM || IS_BCC_PM || IS_WC_PM || IS_HC_PM) 
    laddress = (dword) in_address;
#else
    laddress = (dword) POINTER_SEGMENT(in_address);
    laddress <<= 4;
    laddress += (dword) POINTER_OFFSET(in_address);
#endif
    return(laddress);
}

static BOOLEAN fl_dma_init(DMAPTYPE in_address, word length, BOOLEAN reading) /*__fn__*/
{
byte dma_page;
byte addr_low;
byte addr_high;
dword laddress;
word *p;
byte mode;


    length -= (word)1;
    laddress = kvtodma(in_address);


    p = (word *) &laddress;
//    dma_page = (byte) (*(p+1) & 0xf);
    dma_page = (byte) (*(p+1) & 0xff);
    addr_high = (byte) ((*p) >> 8);
    addr_low = (byte) ((*p) & 0xff);

    /* Convert from generic xfer request to dma processor specific */
    if (reading)
        mode = 0x46;        /* SINGLE MODE, READ, CHANNEL 2 */
    else
        mode = 0x4a;        /* SINGLE MODE, WRITE, CHANNEL 2 */


    ks_disable();
    OUTBYTE(MASK_REGISTER,BIT2|0x02);  /* disable channel 2 */
    ks_enable();

    OUTBYTE(MODE_REGISTER,mode);

    /* Write the bank switch register */ 
    OUTBYTE(BANK_REGISTER,dma_page);
    /* Write the address */ 
    OUTBYTE(FLIPFLOP_REGISTER,0x00);  /* clear flfl before writing address */
    /* Write the address. low byte high byte */
    OUTBYTE(ADDRESS_REGISTER,addr_low);
    OUTBYTE(ADDRESS_REGISTER,addr_high);

    /* Write the length. low byte high byte */
    OUTBYTE(FLIPFLOP_REGISTER,0x00);  /* clear flfl before writing count */
    OUTBYTE(int_REGISTER, (byte) (length & 0xff));
    OUTBYTE(int_REGISTER, (byte) (length >> 8));
    OUTBYTE(MASK_REGISTER,0x02);  /* re-enable channel 2 */
    return (TRUE);
}

//DM: added conditional to comment out if !PME
#if !defined(PME)
/*
* Name:
*    fl_dma_chk() -           Returns the number of blocks beyond the current
*                               addesss in the address's dma page
* Summary:
*   word fl_dma_chk(byte far *in_address)
*   
*
* Inputs:
*   in_address - Address to check
*
*  
* Returns:
*   The number of blocks beyond the current in the dma page.
* 
* Description:
*   This function is called when the driver is preparing for a dma transfer.
*   It returns the number of blocks left in the page beyond the current
*   address.
*
*/

static word fl_dma_chk(DMAPTYPE in_address)                    /*__fn__*/
{
word utemp;
dword laddress;

    laddress = kvtodma(in_address);
    utemp = (word) (laddress & 0xffff);

    if (utemp == 0)
        return(128);
    else
    {
        /* bytes between here and the top */
        utemp = (word) (0xffff - utemp);
        utemp += (word)1;
        return((word)(utemp >> 9));
    }
}
#endif // PME
#endif // USE_DMA

/* Register access functions -
*
*   The following functions access the the 37c65 floppy disk registers
*   We segregated these into simple routines to make it easier on NON-AT
*   systems.
*
*
*/
/* Write data rate register */
static void  fl_write_drr(byte value)                             /*__fn__*/
{
    OUTBYTE(0x3f7, value);
}
/* Read data rate register */
static byte fl_read_drr()                                           /*__fn__*/
{
    return((byte) INBYTE(0x3f7));
}
/* Write to digital output register */
static void  fl_write_dor(byte value)                             /*__fn__*/
{
    OUTBYTE(0x3f2, value);
}
/* Write to data register */
static void  fl_write_data(byte value)                             /*__fn__*/
{
    OUTBYTE(0x3f5, value);
}
/* Read data register */
static byte fl_read_data()                                        /*__fn__*/
{
    return((byte) INBYTE(0x3f5));
}
/* Read master status register */
static byte fl_read_msr()                                        /*__fn__*/
{
    return((byte) INBYTE(0x3f4));
}


int ph_first_floppy(void)
{
    return(0);  /* This can't happen */
}
int ph_last_floppy(void)
{
    return(0); 
}



#if (!USE_DMA)

int polled_read(byte KS_FAR *buffer, word n, byte cmd)
{
unsigned int timeout2;
word seg_1,offs;

timeout2 = 10;
seg_1 = FP_SEG(buffer);
offs = FP_OFF(buffer);

#if (GNU)
/*  Comment out this code so it doesn't make gcc choke.
We could do this with conditional #includes, but GNU preprocessor
chokes anyway
#endif   
#if (EBSENV)   // This commented stuff gets noticed by ifstrip.
*/             // NOTE: These hacks do NOT allow us to build RTFS
#endif         // in our environment under GNU.         -Ansel.
__asm
{
    cli             ; disable interrupts
    mov dx, 3f5h    ; send cmd to the data port to complete the command block
    mov al, cmd
    out dx, al      ; command now send
    push di         ; di register needs to be saved under C environment
    mov ax, seg_1   ; es is segment of destination buffer
    mov es, ax      ; 
    mov di, offs    ; di is offset of destination

    mov cx, n       ; # bytes to transfer. cx is decremented by loop instruction

more:
    mov dx, 3f4h    ; dx contains main status register address
    mov bx,0        ; bx is 0. we'll timeout when it counts backwords to zero 
                    ; again
poll:
    dec bx           ; note: zero-- ==s 0xffff 
    jnz check        ; no timeout. chech the msr for xfer conditions
    mov ax, timeout2 ; we hit 0. decrement the second level timeout counter
    dec ax           ;
    jz  done         ; if 2nd level counter hit zero bail
    mov timeout2, ax ; save the decremented second level timer
    mov bx,0         ; reset the first level timer
check:
    in al, dx        ; read the main status refgister
                     ; test bits in the main status register
    test al, 10h     ; if not BUSY the command hasn't started
    jz poll
    test al, 80h     ; if not RQM it's not ready for io 
    jz poll
    test al, 40h     ; if not DIO it isn't in to host mode (probably hosed)
    jz poll
    test al, 20h     ; if not NDMA it isn't in ndam mode (definately hosed)
    jz done
                     ; If we get here we're ok. read the data
    mov dx, 3f5h     ; address of data port
    in al, dx        ; data to al

    mov es:[di], al  ; al to the destination buffer
    inc di           ; update the buffer
    loop more        ; decrement cx. if non zero go to more
done:
    mov n, cx        ; move cx to n so we can return it. It should be zero. 
                     ; otherwise it is a residual count indicating we broke
                     ; out early
    pop di           ; restore the di register for the c environment
    sti
}
#if (EBSENV)   // Please see the notice at the top of this assembly code.
/*             
#endif         
#if (GNU)
*/
#endif         
return(n);
}


int polled_write(byte KS_FAR *buffer, word n, byte cmd)
{
unsigned int timeout2;
word seg_1,offs;

timeout2 = 10;
seg_1 = FP_SEG(buffer);
offs = FP_OFF(buffer);

#if (GNU)
/*  Comment out this code so it doesn't make gcc choke.
We could do this with conditional #includes, but that GNU preprocessor
still chokes on it
#endif  
#if (EBSENV)   // This commented stuff gets noticed by ifstrip.
*/             // NOTE: These hacks do NOT allow us to build RTFS
#endif         // in our environment under GNU.         -Ansel.
__asm
{
    cli             ; disable interrupts
    mov dx, 3f5h    ; send cmd to the data port to complete the command block
    mov al, cmd
    out dx, al      ; command now send
    push si         ; si register needs to be saved under C environment
    mov ax, seg_1   ; es is segment of source buffer
    mov es, ax      ; 
    mov si, offs    ; si is offset of source

    mov cx, n       ; # bytes to transfer. cx is decremented by loop instruction

more:
    mov dx, 3f4h    ; dx contains main status register address
    mov bx,0        ; bx is 0. we'll timeout when it counts backwords to zero 
                    ; again
poll:
    dec bx           ; note: zero-- ==s 0xffff 
    jnz check        ; no timeout. chech the msr for xfer conditions
    mov ax, timeout2 ; we hit 0. decrement the second level timeout counter
    dec ax           ;
    jz  done         ; if 2nd level counter hit zero bail
    mov timeout2, ax ; save the decremented second level timer
    mov bx,0         ; reset the first level timer
check:
    in al, dx        ; read the main status refgister
                     ; test bits in the main status register
    test al, 10h     ; if not BUSY the command hasn't started
    jz poll
    test al, 80h     ; if not RQM it's not ready for io 
    jz poll
    test al, 40h     ; if DIO it isn't in from host mode (probably hosed)
    jnz poll
    test al, 20h     ; if not NDMA it isn't in ndam mode (definately hosed)
    jz done
                     ; If we get here we're ok. write the data

    mov al, es:[si]  ; source buffer to al
    inc si           ; update the buffer
    mov dx, 3f5h     ; address of data port
    out dx, al      ; command now send

    loop more        ; decrement cx. if non zero go to more
done:
    mov n, cx        ; move cx to n so we can return it. It should be zero. 
                     ; otherwise it is a residual count indicating we broke
                     ; out early
    pop di           ; restore the di register for the c environment
    sti
}
#if (EBSENV)   // Please see the notice at the top of this assembly code.
/*             
#endif         
#if (GNU)
*/
#endif         
return(n);
}

#endif  /* (!USE_DMA) */





int floppy_perform_device_ioctl(int driveno, int opcode, PFVOID pargs)
{
DDRIVE *pdr;
DEV_GEOMETRY gc;        // used by DEVCTL_GET_GEOMETRY
int size;
byte fltype;

    pdr = pc_drno_to_drive_struct(driveno);
    if (!pdr)
        return (-1);

    switch (opcode)
    {
        /* Getgeometry and format share common code */
        case DEVCTL_GET_GEOMETRY:
        case DEVCTL_FORMAT:

        /* Prepare to return an initialized format parameter structure */
        pc_memfill(&gc, sizeof(gc), '\0');
        /* Forc

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -