📄 bddrv.c
字号:
*****************************************************************************/
static int atapi_pause(ide_t *dev, bool cont)
{
unsigned char pkt[12] =
{
ATAPI_CMD_PAUSE,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0
};
request_t req;
DEBUG(printf("atapi_pause\n");)
memset(&req, 0, sizeof(req));
req.dev = dev;
pkt[8] = cont ? 1 : 0;
return atapi_cmd(&req, pkt);
}
/*****************************************************************************
Use MODE SENSE (0x5A) to read page 0x2A
("CD-ROM Capabilities & Mechanical Status Page")
*****************************************************************************/
static int atapi_mode_sense(ide_t *dev)
{
unsigned char buf[2048/*21*/], pkt[12] =
{
0x5A, 0, 0x2A,
0, 0, 0, 0,
0, 24,//21 //21 + 8,
0, 0, 0
};
request_t req;
DEBUG(printf("atapi_mode_sense:\n");)
memset(&req, 0, sizeof(req));
req.dev = dev;
// req.num_blks = 1;
req.buf = buf;
(void)atapi_cmd(&req, pkt);
dump(buf + 8, 21);
printf("\nmulti-session:\t\t%s\n",
(buf[12] & 0x40) ? "YES" : "NO");
printf("mode 2/form 2:\t\t%s\n",
(buf[12] & 0x20) ? "YES" : "NO");
printf("mode 2/form 1:\t\t%s\n",
(buf[12] & 0x10) ? "YES" : "NO");
printf("XA:\t\t\t%s\n",
(buf[12] & 0x02) ? "YES" : "NO");
printf("audio play:\t\t%s\n",
(buf[12] & 0x01) ? "YES" : "NO");
printf("UPC:\t\t\t%s\n",
(buf[13] & 0x40) ? "YES" : "NO");
printf("ISRC:\t\t\t%s\n",
(buf[13] & 0x20) ? "YES" : "NO");
printf("C2 pointers:\t\t%s\n",
(buf[13] & 0x10) ? "YES" : "NO");
printf("R-W deinterleave and\n correction:\t\t%s\n",
(buf[13] & 0x08) ? "YES" : "NO");
printf("R-W:\t\t\t%s\n",
(buf[13] & 0x04) ? "YES" : "NO");
printf("accurate CD-DA stream:\t%s\n",
(buf[13] & 0x02) ? "YES" : "NO");
printf("CD-DA commands:\t\t%s\n",
(buf[13] & 0x01) ? "YES" : "NO");
printf("loading mechanism type:\t%u\n",
buf[14] >> 5);
printf("eject:\t\t\t%s\n",
(buf[14] & 0x08) ? "YES" : "NO");
printf("prevent jumper:\t\t%s\n",
(buf[14] & 0x04) ? "YES" : "NO");
printf("lock state:\t\t%s\n",
(buf[14] & 0x02) ? "YES" : "NO");
printf("lock:\t\t\t%s\n",
(buf[14] & 0x01) ? "YES" : "NO");
printf("separate channel:\t%s\n",
(buf[15] & 0x02) ? "YES" : "NO");
printf("separate volume:\t%s\n",
(buf[15] & 0x01) ? "YES" : "NO");
printf("max speed:\t\t%u KBps\n", read_be16(buf + 16));
printf("volume levels:\t\t%u\n", read_be16(buf + 18));
printf("buffer size:\t\t%uK\n", read_be16(buf + 20));
printf("current speed:\t\t%u KBps\n", read_be16(buf + 22));
return 0;
}
/*****************************************************************************
*****************************************************************************/
static int atapi_toc_ent(ide_t *dev, unsigned char *toc_ent,
unsigned short toc_ent_len)
{
unsigned char pkt[12] =
{
0x43, /* ATAPI_CMD_READTOC */
2, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0
};
request_t req;
DEBUG(printf("atapi_toc_ent\n");)
memset(&req, 0, sizeof(req));
req.dev = dev;
/* xxx - pass toc_ent_len in req, somehow */
// req.num_blks = 1;
req.buf = toc_ent;
pkt[7] = toc_ent_len >> 8;
pkt[8] = toc_ent_len;
return atapi_cmd(&req, pkt);
}
/*****************************************************************************
*****************************************************************************/
#define MAX_TRACKS 32
typedef struct /* one frame == 1/75 sec */
{
unsigned char min, sec, frame;
} msf_t;
static int atapi_toc(ide_t *dev)
{
unsigned char *entry, buf[4 + 8 * MAX_TRACKS];
int temp;
msf_t track[MAX_TRACKS];
unsigned num_tracks;
DEBUG(printf("atapi_toc:\n");)
/* read just the 4-byte header at first
16-bit table-of-contents length (?)
8-bit first track
8-bit last track */
temp = 4;
temp = atapi_toc_ent(dev, buf, temp);
if(temp != 0)
return temp;
num_tracks = buf[3] - buf[2] + 1;
if(num_tracks <= 0 || num_tracks > 99)
{
printf("atapi_toc: error: bad number of tracks %d\n",
num_tracks);
return -1;
}
if(num_tracks > MAX_TRACKS)
{
printf("atapi-toc: warning: too many tracks (%u); "
"reducing to %u.\n", num_tracks, MAX_TRACKS);
num_tracks = MAX_TRACKS;
}
/* read 4-byte header and 8-byte table-of-contents entries */
temp = 4 + 8 * (num_tracks + 1);
temp = atapi_toc_ent(dev, buf, temp);
if(temp != 0)
return temp;
/* point to first TOC entry */
entry = buf + 4;
/* read num_tracks+1 entries
the last entry is for the disk lead-out */
for(temp = 0; temp < num_tracks + 2; temp++)
{
/* get track start time (minute, second, frame) from bytes 5..7 of entry */
track[temp].min = entry[5];
track[temp].sec = entry[6];
track[temp].frame = entry[7];
printf("%02u:%02u:%02u ", track[temp].min,
track[temp].sec, track[temp].frame);
/* advance to next entry */
entry += 8;
}
printf("\n");
return 0;
}
//////////////////////////////////////////////////////////////////////////////
// DMA ROUTINES
//////////////////////////////////////////////////////////////////////////////
#define NUM_DMAS 8
#define DMA_READ 0x44
#define DMA_WRITE 0x48
/* 8-bit DMAC registers */
#define DMA_BASE 0
#define DMA_MASK 0x0A /* mask register (write only) */
#define DMA_MODE 0x0B /* mode register */
#define DMA_FF 0x0C /* MSB/LSB flip flop */
#define DMA_RESET 0x0D /* master clear */
/* Upper 4 bits (8 bits ?) of 20-bit (24-bit?) address
come from the DMAC page registers: */
static const unsigned char _page_reg_ioadr[NUM_DMAS] =
{
0x87, 0x83, 0x81, 0x82, 0, 0x8B, 0x89, 0x8A
};
/****************************************************************************
****************************************************************************/
static int dma_read(unsigned char chan, unsigned long linear,
unsigned long tc)
{
unsigned char scaled_chan, cmd;
/* validate chan */
if(chan > 3)
return -1;
/* set cmd byte */
cmd = DMA_READ + (chan & 3);
/* make sure transfer doesn't exceed 16 meg or cross a 64K boundary */
if(linear + tc >= 0x1000000L)
return -1;
if((linear & 0x10000L) != ((linear + tc) & 0x10000L))
return -1;
/* 8-bit transfers */
scaled_chan = chan << 1;
outportb(DMA_FF, 0); /* set base adr */
outportb(DMA_BASE + scaled_chan, linear);
outportb(DMA_BASE + scaled_chan, linear >> 8);
outportb(DMA_BASE + 1 + /* set xfer len */
scaled_chan, tc);
outportb(DMA_BASE + 1 + scaled_chan, tc >> 8);
outportb(_page_reg_ioadr[chan], /* set page */
linear >> 16);
outportb(DMA_MODE, cmd); /* do it */
outportb(DMA_MASK, chan);
return 0;
}
/****************************************************************************
****************************************************************************/
static int dma_write(unsigned char chan, unsigned long linear,
unsigned long tc)
{
unsigned char scaled_chan, cmd;
/* validate chan */
if(chan > 3)
return -1;
/* set cmd byte */
cmd = DMA_WRITE + (chan & 3);
/* make sure transfer doesn't exceed 16 meg or cross a 64K boundary */
if(linear + tc >= 0x1000000L)
return -1;
if((linear & 0x10000L) != ((linear + tc) & 0x10000L))
return -1;
/* 8-bit transfers */
scaled_chan = chan << 1;
outportb(DMA_FF, 0); /* set base adr */
outportb(DMA_BASE + scaled_chan, linear);
outportb(DMA_BASE + scaled_chan, linear >> 8);
outportb(DMA_BASE + 1 + /* set xfer len */
scaled_chan, tc);
outportb(DMA_BASE + 1 + scaled_chan, tc >> 8);
outportb(_page_reg_ioadr[chan], /* set page */
linear >> 16);
outportb(DMA_MODE, cmd); /* do it */
outportb(DMA_MASK, chan);
return 0;
}
//////////////////////////////////////////////////////////////////////////////
// FLOPPY ROUTINES
//////////////////////////////////////////////////////////////////////////////
/* offsets from 0x3F0 */
#define FDC_DOR 2 /* Digital Output Register */
#define FDC_MSR 4 /* Main Status Register */
#define FDC_DATA 5 /* Data Register */
#define FDC_DIR 7 /* Digital Input Register (input) */
#define FDC_CCR 7 /* Configuration Control Register (output) */
typedef struct
{
/* generic block device info */
blkdev_t blkdev;
/* information specific to floppy drive */
unsigned short timeout;
unsigned char curr_track, sr0;
} floppy_t;
/*****************************************************************************
floppy controller chips:
Intel 8272a ==NEC 765
NEC 765ED Non-Intel 1MB-compatible FDC, can't detect
Intel 87072 ==8272a + FIFO + DUMPREGS
82072a only on Sparcs?
82077AA no LOCK (?)
82077AA-1
82078 44-pin 82078 or 64-pin 82078SL
82078-1 2 Mbps
S82078B first seen on Adaptec AVA-2825 VLB SCSI/EIDE/Floppy ctrl
87306
*****************************************************************************/
static void floppy_send_byte(unsigned short ioadr, unsigned char byte)
{
unsigned char msr;
unsigned timeout;
for(timeout = 128; timeout != 0; timeout--)
{
msr = inportb(ioadr + FDC_MSR);
if((msr & 0xC0) == 0x80)
{
outportb(ioadr + FDC_DATA, byte);
return;
}
}
/* xxx - else? */
}
/*****************************************************************************
*****************************************************************************/
static int floppy_get_byte(unsigned short ioadr)
{
unsigned char msr;
unsigned timeout;
for(timeout = 128; timeout != 0; timeout--)
{
msr = inportb(ioadr + FDC_MSR);
if((msr & 0xD0) == 0xD0)
return inportb(ioadr + FDC_DATA);
}
return -1; /* timeout */
}
/*****************************************************************************
*****************************************************************************/
static void floppy_motor_on(floppy_t *dev)
{
unsigned short ioadr, t;
unsigned char unit;
DEBUG(printf("floppy_motor_on:\n");)
ioadr = dev->blkdev.io.adr[0];
unit = dev->blkdev.unit;
t = dev->timeout;
/* cancel motor-off timeout.
-1 tells timer interrupt not to decrement */
dev->timeout = -1;
if(t != 0)
return; /* motor already on */
/* xxx - top four bits enable motors, b3 enables DMA and I/O,
b2 enables the the FDC chip, b1 and b0 are drive select
xxx - need a static global variable to cache the value written to FDC_DOR
xxx - floppy_select_drive() should be a separate function, maybe */
outportb(ioadr + FDC_DOR, 0x1C);//unit?);
/* delay 500ms for motor to spin up
xxx - use interrupts here? */
msleep(500);
}
/*****************************************************************************
*****************************************************************************/
static void floppy_motor_off(floppy_t *dev)
{
DEBUG(printf("floppy_motor_off:\n");)
dev->timeout = 36; /* 18 ticks, ~2 sec */
}
/*****************************************************************************
*****************************************************************************/
static int floppy_await_interrupt(floppy_t *fdev)
{
unsigned short irq, ioadr;
unsigned char status[7];
int temp;
ioadr = fdev->blkdev.io.adr[0];
irq = fdev->blkdev.io.irq;
DEBUG(printf("floppy_await_interrupt:\n");)
/* wait up to 1 second for IRQ 6 */
temp = await_interrupt(irq, 1000);
if(temp == 0) /* timeout */
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -