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

📄 bddrv.c

📁 linux1.0的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
        break;
    case 2:
        printf("  accelerated DRQ\n");
        break;
    }
#endif
    printf("\n");
    return 0;
}
/*****************************************************************************
*****************************************************************************/
static void ide_do_probe(ide_t *master, ide_t *slave)
{
    unsigned short ioadr;
    unsigned char byte1, byte2;
    blkdev_t *blkdev;

    ioadr = master->blkdev.io.adr[0];
    /* poke interface */
    DEBUG(printf("ide_do_probe: poking interface 0x%X\n", ioadr);)
    outportb(ioadr + ATA_REG_COUNT, 0x55);
    outportb(ioadr + ATA_REG_SECTOR, 0xAA);
    byte1 = inportb(ioadr + ATA_REG_COUNT);
    byte2 = inportb(ioadr + ATA_REG_SECTOR);
    /* nothing there */
    if(byte1 != 0x55 || byte2 != 0xAA)
    {
        DEBUG(printf("nothing there\n");)
        return;
    }
    /* soft reset both drives on this I/F (selects master) */
    DEBUG(printf("found something on I/F 0x%X, "
                 "doing soft reset...\n", ioadr);)
    outportb(ioadr + ATA_REG_DEVCTRL, 0x06);
    nsleep(400);
    /* release soft reset AND enable interrupts from drive */
    outportb(ioadr + ATA_REG_DEVCTRL, 0x00);
    nsleep(400);
    /* wait up to 2 seconds for status =
    BUSY=0  READY=1  DF=?  DSC=?		DRQ=?  CORR=?  IDX=?  ERR=0 */
    blkdev = &master->blkdev;
    if(ide_poll_status(ioadr, 2000, 0xC1, 0x40) != 0)
    {
        DEBUG(printf("ide_do_probe: no master on interface 0x%X\n",
                     ioadr);)
        return;
    }
    /* identify master */
    printf("master drive on interface 0x%X:\n", ioadr);
    ide_identify(master);
    /* select slave */
    blkdev = &slave->blkdev;
    if(ide_select_drive(ioadr, blkdev->unit) != 0)
    {
        DEBUG(printf("ide_do_probe: no slave on interface 0x%X\n",
                     ioadr);)
        return;
    }
    /* identify slave */
    ioadr = slave->blkdev.io.adr[0];
    printf("slave drive on interface 0x%X:\n", ioadr);
    ide_identify(slave);
}
/*****************************************************************************
*****************************************************************************/
static ide_t _drives[4];

static void ide_probe(void)
{
    DEBUG(printf("ide_probe:\n");)
    /* no DMA */
    _drives[0].blkdev.io.dma = _drives[1].blkdev.io.dma = 0;
    _drives[2].blkdev.io.dma = _drives[3].blkdev.io.dma = 0;
    /* IRQs 14 and 15 */
    _drives[0].blkdev.io.irq = _drives[1].blkdev.io.irq = 0x4000;
    _drives[2].blkdev.io.irq = _drives[3].blkdev.io.irq = 0x8000;
    /* 8 bytes at 0x1F0, 1 byte at 0x3F6 */
    _drives[0].blkdev.io.adr[0] = _drives[1].blkdev.io.adr[0] = 0x1F0;
    _drives[0].blkdev.io.span[0] = _drives[1].blkdev.io.span[0] = 8;
    _drives[0].blkdev.io.adr[1] = _drives[1].blkdev.io.adr[1] = 0x3F6;
    _drives[0].blkdev.io.span[1] = _drives[1].blkdev.io.span[1] = 1;
    /* 8 bytes at 0x170, 1 byte at 0x3F6 (xxx - is 0x3F6 correct?) */
    _drives[2].blkdev.io.adr[0] = _drives[3].blkdev.io.adr[0] = 0x170;
    _drives[2].blkdev.io.span[0] = _drives[3].blkdev.io.span[0] = 8;
    _drives[2].blkdev.io.adr[1] = _drives[3].blkdev.io.adr[1] = 0x3F6;
    _drives[2].blkdev.io.span[1] = _drives[3].blkdev.io.span[1] = 1;
    /* */
    _drives[0].blkdev.unit = _drives[2].blkdev.unit = 0xA0;
    _drives[1].blkdev.unit = _drives[3].blkdev.unit = 0xB0;
    /* num_blks, bytes_per_blk, CHS, and ATA-/ATAPI-specific stuff
    gets set by ide_do_probe() */
    ide_do_probe(_drives + 0, _drives + 1);
    ide_do_probe(_drives + 2, _drives + 3);
    DEBUG(printf("\n");)
}
//////////////////////////////////////////////////////////////////////////////
// IDE (ATAPI) CD-ROM DRIVES
//////////////////////////////////////////////////////////////////////////////
/* the command byte within an ATAPI command packet */
#define	ATAPI_CMD_START_STOP	0x1B	/* eject/load */
#define	ATAPI_CMD_READ10	0x28	/* read data sector(s) */
#define	ATAPI_CMD_READTOC	0x43	/* read audio table-of-contents */
#define	ATAPI_CMD_PLAY		0x47	/* play audio */
#define	ATAPI_CMD_PAUSE		0x4B	/* pause/continue audio */
/*****************************************************************************
xxx - finish
*****************************************************************************/
#pragma argsused
static int atapi_error(request_t *req)
{
    static const char *key[] =
        {
            "no sense", "recovered error", "not ready", "medium error",
            "hardware error", "illegal request", "unit attention", "data protect",
            "?", "?", "?", "aborted command",
            "?", "?", "miscompare", "?"
        };
    ide_t *dev;
    unsigned short ioadr;
    unsigned char temp;

    DEBUG(printf("*** atapi_error: ***\n");)
    dev = (ide_t *)req->dev;
    ioadr = dev->blkdev.io.adr[0];
    temp = inportb(ioadr + ATA_REG_STATUS);
    printf("error bit=%u, ", temp & 1);
    temp = inportb(ioadr + ATA_REG_ERROR);
    printf("sense key=%u (%s)\n", temp >> 4, key[temp >>4]);
    printf("MCR=%u, ", (temp & 8) >> 3);
    printf("ABRT=%u, ", (temp & 4) >> 2);
    printf("EOM=%u, ", (temp & 2) >> 1);
    printf("ILI=%u\n", temp & 1);

    (req->errors)++;
    if(req->errors >= 3)
        return -1;
    return 0;
}
/*****************************************************************************
DRQ	REASON	"phase"
 0	  0	ATAPI_PH_ABORT
 0	  1	bad
 0	  2	bad
 0	  3	ATAPI_PH_DONE
 8	  0	ATAPI_PH_DATAOUT
 8	  1	ATAPI_PH_CMDOUT
 8	  2	ATAPI_PH_DATAIN
 8	  3	bad

b0 of REASON register is CoD or C/nD (0=data, 1=command)
b1 of REASON register is IO (0=out to drive, 1=in from drive)
*****************************************************************************/
#define	ATAPI_PH_ABORT		0	/* other possible phases */
#define	ATAPI_PH_DONE		3	/* (1, 2, 11) are invalid */
#define	ATAPI_PH_DATAOUT	8
#define	ATAPI_PH_CMDOUT		9
#define	ATAPI_PH_DATAIN		10

static int atapi_cmd(request_t *req, unsigned char *pkt)
{
    static const char *phase_name[] =
        {
            "ABORT",	"invalid",	"invalid",	"DONE",
            "can't happen",	"can't happen",	"can't happen",	"can't happen",
            "DATA OUT",	"CMD OUT",	"DATA IN",	"invalid"
        };
    ide_t *dev;
    blkdev_t *bdev;
    unsigned short ioadr, num_blks, num_bytes;
    int err;
    unsigned char phase;

    DEBUG(printf("atapi_cmd:\n");)
    dev = (ide_t *)req->dev;
    bdev = &dev->blkdev;
    /* if the ide_t struct had a magic value in it, we could validate it here */
    ioadr = bdev->io.adr[0];
    /* select drive (xxx - need to do this?) */
    err = ide_select_drive(ioadr, bdev->unit);
    if(err != 0)	/* xxx - no retry? */
        return err;
AGAIN:
    /* write ATA register file. Registers 2 (COUNT) and 3 (SECTOR) are not used */
    outportb(ioadr + ATA_REG_FEAT, 0);
    /* max. bytes to transfer on each DRQ */
    outportb(ioadr + ATAPI_REG_LOCNT, 32768u);
    outportb(ioadr + ATAPI_REG_HICNT, 32768u >> 8);
    /* select drive and set LBA bit */
    outportb(ioadr + ATA_REG_DRVHD, 0x40 | bdev->unit);
    nsleep(400);
    /* packet command byte */
    outportb(ioadr + ATA_REG_CMD, ATA_CMD_PKT);
    nsleep(400);
    /* wait up to 0.5 seconds for status =
    BUSY=0  READY=?  DF=?  DSC=?		DRQ=1  CORR=?  IDX=?  ERR=?

    i.e. await DRQ. This can be interrupt-driven for new drives,
    instead of polled, but this code doesn't support it. */
    if(ide_poll_status(ioadr, 500, 0x88, 0x08) != 0)
    {
        printf("atapi_cmd: error: drive did not "
               "accept packet cmd byte\n");
        goto ERR;
    }
    /* "4. When the Device is ready to accept the Command Packet,
    the Device sets CoD and clears IO. DRQ shall then be asserted
    simultaneous or prior to the de-assertion of BSY."
        CoD=1, IO=0, DRQ=1 --> ATAPI_PH_CMDOUT */
    phase = inportb(ioadr + ATA_REG_STATUS) & 0x08;
    phase |= (inportb(ioadr + ATAPI_REG_REASON) & 3);
    if(phase != ATAPI_PH_CMDOUT)
    {
        printf("atapi_cmd: error: drive did not "
               "enter command out phase\n");
        DEBUG(printf("atapi_cmd: ATAPI drive now in phase '%s'\n",
                     (phase < 12) ? phase_name[phase] : "can't happen");)
        goto ERR;
    }
    /* write the 12-byte ATAPI packet, 2 bytes at a time */
    outsw(ioadr + ATA_REG_DATA, (unsigned short *)pkt, 6);
    /* main read loop */
    for(;;)
    {
        /* wait up to 10 seconds for IRQ15 or IRQ14 */
        if(await_interrupt(0xC000, 10000) == 0)
        {
            printf("atapi_cmd: error: "
                   "packet command timed out\n");
            goto ERR;
        }
        /* get the ATAPI "phase".
        Reading the status register here clears the interrupt. */
        phase = inportb(ioadr + ATA_REG_STATUS) & 0x08;
        phase |= (inportb(ioadr + ATAPI_REG_REASON) & 3);
        DEBUG(printf("atapi_cmd: ATAPI drive now in phase '%s'\n",
                     (phase < 12) ? phase_name[phase] : "can't happen");)
        /* DONE phase is OK, if we are truly done...

        "10. When the Device is ready to present the status, the Device places
        the completion status into the Status Register, sets CoD, IO, DRDY and
        clears BSY, DRQ, prior to asserting INTRQ."
        	CoD=1, IO=1, DRQ=0 --> ATAPI_PH_DONE

        xxx - we don't check if DRDY=1

        "11. After detecting INTRQ & DRQ=0 the host reads the Status Register and
        if necessary, the Error Register for the command completion status." */
        if(phase == ATAPI_PH_DONE)
        {
            if(req->num_blks == 0)
                return 0;
            /* ...otherwise, it's an error */
            printf("atapi_cmd: error: data shortage\n");
            goto ERR;
        }
        /* besides DONE, DATA IN is the only valid phase

        "7. When data is available, the Device:(1) places the byte count
        of the data available into the Cylinder High and Low Registers,
        (2) sets IO and clears CoD, (3) sets DRQ and clears BSY, (4) sets INTRQ."
        	IO=1, CoD=0, DRQ=1 --> ATAPI_PH_DATAIN */
        /*else*/ if(phase != ATAPI_PH_DATAIN)
        {
            printf("atapi_cmd: error: "
                   "drive in unexpected phase\n");
ERR:
            /* call atapi_error() if there is an error */
            err = atapi_error(req);
            if(err != 0)
                return err;
            /* ...else try again */
            else
                goto AGAIN;
        }
        /* read!
        xxx - 16 is 32768 (max bytes per DRQ) / 2048 (bytes per sector) */
        num_blks = min(req->num_blks, 16);
        /* if num_blks drops to 0, then we just read and discard, no worries */
        num_bytes = atapi_read_and_discard(ioadr, req->buf,
                                           num_blks * bdev->bytes_per_blk);
        num_blks = num_bytes / bdev->bytes_per_blk;
        /* advance pointers */
        req->buf += num_bytes;
        req->num_blks -= num_blks;
        req->blk += num_blks;
    }
}
/*****************************************************************************
*****************************************************************************/
static int atapi_read_sectors(request_t *req)
{
    unsigned char pkt[12] =
        {
            ATAPI_CMD_READ10, 0,
            0, 0, 0, 0,
            0, 0, 0,
            0, 0, 0,
        };

    DEBUG(printf("atapi_read_sectors:\n");)
    pkt[2]=req->blk >> 24;
    pkt[3]=req->blk >> 16;
    pkt[4]=req->blk >> 8;
    pkt[5]=req->blk;
    //	pkt[6]=req->num_blks >> 16;
    pkt[7]=req->num_blks >> 8;
    pkt[8]=req->num_blks;
    return atapi_cmd(req, pkt);
}
/*****************************************************************************
My CD-ROM is an old piece of shit Mitsumi, and doesn't support this
function, so I have no way of testing it. I don't even know if the
command bytes 0xBE (READ CD) or 0xD5 (READ CD MSF) are correct.

This is a guess, but: if atapi_mode_sense() displays
	CD-DA commands: YES
then the drive can "rip" audio tracks.
*****************************************************************************/
static int atapi_rip_audio(request_t *req)
{
    unsigned char pkt[12] =
        {
#if 1
            0xBE, 0,
            0, 0, 0, 0, /* start LBA */
            0, 0, 1, /* number of blocks */
#else
            0xD5, 0, 0,
            0, 0, 0,/* start MSF */
            0, 0, 1,/* end MSF */
#endif
            /* 9=10h	flag bits
            	b7=synch field, b6:b5=header(s) code, b4=user data,
            	b3=EDC & ECC, b2:b1=error flag(s), b0=reserved */
            0x10,
            /* 10=0	b2:b0 = sub-channel data selection bits, other bits reserved */
            0,
            0,
        };

    DEBUG(printf("atapi_read_sectors:\n");)
    pkt[2]=req->blk >> 24;
    pkt[3]=req->blk >> 16;
    pkt[4]=req->blk >> 8;
    pkt[5]=req->blk;
    pkt[6]=req->num_blks >> 16;
    pkt[7]=req->num_blks >> 8;
    pkt[8]=req->num_blks;
    return atapi_cmd(req, pkt);
}
/*****************************************************************************
*****************************************************************************/
static int atapi_eject(ide_t *dev, bool load)
{
    unsigned char pkt[12] =
        {
            ATAPI_CMD_START_STOP,
            0, 0, 0, 0,
            0, 0, 0, 0,
            0, 0, 0
        };
    request_t req;

    DEBUG(printf("atapi_eject:\n");)
    memset(&req, 0, sizeof(req));
    req.dev = dev;
    pkt[4] = 2 + (load ? 1 : 0);
    return atapi_cmd(&req, pkt);
}
/*****************************************************************************

⌨️ 快捷键说明

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