📄 xd.c
字号:
static void xd_interrupt_handler (int unused)
{
if (inb(XD_STATUS) & STAT_INTERRUPT) { /* check if it was our device */
#ifdef DEBUG_OTHER
printk("xd_interrupt_handler: interrupt detected\n");
#endif /* DEBUG_OTHER */
outb(0,XD_CONTROL); /* acknowledge interrupt */
wake_up(&xd_wait_int); /* and wake up sleeping processes */
}
else
printk("xd_interrupt_handler: unexpected interrupt\n");
}
/* xd_dma: set up the DMA controller for a data transfer */
static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
{
if (buffer < ((u_char *) 0x1000000 - count)) { /* transfer to address < 16M? */
if (((u_int) buffer & 0xFFFF0000) != ((u_int) buffer + count) & 0xFFFF0000) {
#ifdef DEBUG_OTHER
printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
#endif /* DEBUG_OTHER */
return (PIO_MODE);
}
disable_dma(xd_dma);
clear_dma_ff(xd_dma);
set_dma_mode(xd_dma,mode);
set_dma_addr(xd_dma,(u_int) buffer);
set_dma_count(xd_dma,count);
return (DMA_MODE); /* use DMA and INT */
}
#ifdef DEBUG_OTHER
printk("xd_setup_dma: using PIO, cannot DMA above 16 meg\n");
#endif /* DEBUG_OTHER */
return (PIO_MODE);
}
/* xd_build: put stuff into an array in a format suitable for the controller */
static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control)
{
cmdblk[0] = command;
cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F);
cmdblk[2] = ((cylinder & 0x300) >> 2) | (sector & 0x3F);
cmdblk[3] = cylinder & 0xFF;
cmdblk[4] = count;
cmdblk[5] = control;
return (cmdblk);
}
/* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */
static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout)
{
u_long expiry = jiffies + timeout;
while (((inb(port) & mask) != flags) && (jiffies < expiry))
;
return (jiffies >= expiry);
}
/* xd_command: handle all data transfers necessary for a single command */
static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout)
{
u_char cmdblk[6],csb,complete = 0;
#ifdef DEBUG_COMMAND
printk("xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
#endif /* DEBUG_COMMAND */
outb(0,XD_SELECT);
outb(mode,XD_CONTROL);
if (xd_waitport(XD_STATUS,STAT_SELECT,STAT_SELECT,timeout))
return (1);
while (!complete) {
if (xd_waitport(XD_STATUS,STAT_READY,STAT_READY,timeout))
return (1);
switch (inb(XD_STATUS) & (STAT_COMMAND | STAT_INPUT)) {
case 0: if (mode == DMA_MODE) {
enable_dma(xd_dma);
sleep_on(&xd_wait_int);
disable_dma(xd_dma);
}
else
outb(outdata ? *outdata++ : 0,XD_DATA);
break;
case STAT_INPUT: if (mode == DMA_MODE) {
enable_dma(xd_dma);
sleep_on(&xd_wait_int);
disable_dma(xd_dma);
}
else
if (indata)
*indata++ = inb(XD_DATA);
else
inb(XD_DATA);
break;
case STAT_COMMAND: outb(command ? *command++ : 0,XD_DATA); break;
case STAT_COMMAND
| STAT_INPUT: complete = 1; break;
}
}
csb = inb(XD_DATA);
if (xd_waitport(XD_STATUS,0,STAT_SELECT,timeout)) /* wait until deselected */
return (1);
if (csb & CSB_ERROR) { /* read sense data if error */
xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0);
if (xd_command(cmdblk,0,sense,0,0,XD_TIMEOUT))
printk("xd_command: warning! sense command failed!\n");
}
#ifdef DEBUG_COMMAND
printk("xd_command: completed with csb = 0x%X\n",csb);
#endif /* DEBUG_COMMAND */
return (csb & CSB_ERROR);
}
static u_char xd_initdrives (void (*init_drive)(u_char drive))
{
u_char cmdblk[6],i,count = 0;
for (i = 0; i < XD_MAXDRIVES; i++) {
xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0);
if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2)) {
init_drive(count);
count++;
}
}
return (count);
}
static void xd_dtc_init_controller (u_char *address)
{
switch ((u_long) address) {
case 0xC8000: xd_iobase = 0x320; break;
case 0xCA000: xd_iobase = 0x324; break;
default: printk("xd_dtc_init_controller: unsupported BIOS address %p\n",address);
xd_iobase = 0x320; break;
}
xd_irq = 5; /* the IRQ _can_ be changed on this card, but requires a hardware mod */
xd_dma = 3;
xd_maxsectors = 0x01; /* my card seems to have trouble doing multi-block transfers? */
outb(0,XD_RESET); /* reset the controller */
}
static void xd_dtc_init_drive (u_char drive)
{
u_char cmdblk[6],buf[64];
xd_build(cmdblk,CMD_DTCGETGEOM,drive,0,0,0,0,0);
if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
xd_info[drive].heads = buf[0x0A]; /* heads */
xd_info[drive].cylinders = ((u_short *) (buf))[0x04]; /* cylinders */
xd_info[drive].sectors = 17; /* sectors */
#if 0
xd_info[drive].rwrite = ((u_short *) (buf + 1))[0x05]; /* reduced write */
xd_info[drive].precomp = ((u_short *) (buf + 1))[0x06]; /* write precomp */
xd_info[drive].ecc = buf[0x0F]; /* ecc length */
#endif /* 0 */
xd_info[drive].control = 0; /* control byte */
xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf + 1))[0x05],((u_short *) (buf + 1))[0x06],buf[0x0F]);
xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7);
if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
printk("xd_dtc_init_drive: error setting step rate for drive %d\n",drive);
}
else
printk("xd_dtc_init_drive: error reading geometry for drive %d\n",drive);
}
static void xd_wd_init_controller (u_char *address)
{
switch ((u_long) address) {
case 0xC8000: xd_iobase = 0x320; break;
case 0xCA000: xd_iobase = 0x324; break;
case 0xCC000: xd_iobase = 0x328; break;
case 0xCE000: xd_iobase = 0x32C; break;
case 0xD0000: xd_iobase = 0x328; break;
case 0xD8000: xd_iobase = 0x32C; break;
default: printk("xd_wd_init_controller: unsupported BIOS address %p\n",address);
xd_iobase = 0x320; break;
}
xd_irq = 5; /* don't know how to auto-detect this yet */
xd_dma = 3;
xd_maxsectors = 0x01; /* this one doesn't wrap properly either... */
/* outb(0,XD_RESET); */ /* reset the controller */
}
static void xd_wd_init_drive (u_char drive)
{
u_char cmdblk[6],buf[0x200];
xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0);
if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
xd_info[drive].heads = buf[0x1AF]; /* heads */
xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6]; /* cylinders */
xd_info[drive].sectors = 17; /* sectors */
#if 0
xd_info[drive].rwrite = ((u_short *) (buf))[0xD8]; /* reduced write */
xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA]; /* write precomp */
xd_info[drive].ecc = buf[0x1B4]; /* ecc length */
#endif /* 0 */
xd_info[drive].control = buf[0x1B5]; /* control byte */
xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
}
else
printk("xd_wd_init_drive: error reading geometry for drive %d\n",drive);
}
static void xd_seagate_init_controller (u_char *address)
{
switch ((u_long) address) {
case 0xC8000: xd_iobase = 0x320; break;
case 0xD0000: xd_iobase = 0x324; break;
case 0xD8000: xd_iobase = 0x328; break;
case 0xE0000: xd_iobase = 0x32C; break;
default: printk("xd_seagate_init_controller: unsupported BIOS address %p\n",address);
xd_iobase = 0x320; break;
}
xd_irq = 5; /* the IRQ and DMA channel are fixed on the Seagate controllers */
xd_dma = 3;
xd_maxsectors = 0x40;
outb(0,XD_RESET); /* reset the controller */
}
static void xd_seagate_init_drive (u_char drive)
{
u_char cmdblk[6],buf[0x200];
xd_build(cmdblk,CMD_ST11GETGEOM,drive,0,0,0,1,0);
if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
xd_info[drive].heads = buf[0x04]; /* heads */
xd_info[drive].cylinders = (buf[0x02] << 8) | buf[0x03]; /* cylinders */
xd_info[drive].sectors = buf[0x05]; /* sectors */
xd_info[drive].control = 0; /* control byte */
}
else
printk("xd_seagate_init_drive: error reading geometry from drive %d\n",drive);
}
/* Omti support courtesy Dirk Melchers */
static void xd_omti_init_controller (u_char *address)
{
switch ((u_long) address) {
case 0xC8000: xd_iobase = 0x320; break;
case 0xD0000: xd_iobase = 0x324; break;
case 0xD8000: xd_iobase = 0x328; break;
case 0xE0000: xd_iobase = 0x32C; break;
default: printk("xd_omti_init_controller: unsupported BIOS address %p\n",address);
xd_iobase = 0x320; break;
}
xd_irq = 5; /* the IRQ and DMA channel are fixed on the Omti controllers */
xd_dma = 3;
xd_maxsectors = 0x40;
outb(0,XD_RESET); /* reset the controller */
}
static void xd_omti_init_drive (u_char drive)
{
/* gets infos from drive */
xd_override_init_drive(drive);
/* set other parameters, Hardcoded, not that nice :-) */
xd_info[drive].control = 2;
}
/* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
static void xd_override_init_drive (u_char drive)
{
u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
u_char cmdblk[6],i;
for (i = 0; i < 3; i++) {
while (min[i] != max[i] - 1) {
test[i] = (min[i] + max[i]) / 2;
xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0);
if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
min[i] = test[i];
else
max[i] = test[i];
}
test[i] = min[i];
}
xd_info[drive].heads = (u_char) min[0] + 1;
xd_info[drive].cylinders = (u_short) min[1] + 1;
xd_info[drive].sectors = (u_char) min[2] + 1;
xd_info[drive].control = 0;
}
/* xd_setup: initialise from command line parameters */
void xd_setup (char *command,int *integers)
{
xd_override = 1;
xd_type = integers[1];
xd_irq = integers[2];
xd_iobase = integers[3];
xd_dma = integers[4];
xd_maxsectors = 0x01;
}
/* xd_setparam: set the drive characteristics */
static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)
{
u_char cmdblk[14];
xd_build(cmdblk,command,drive,0,0,0,0,0);
cmdblk[6] = (u_char) (cylinders >> 8) & 0x03;
cmdblk[7] = (u_char) (cylinders & 0xFF);
cmdblk[8] = heads & 0x1F;
cmdblk[9] = (u_char) (rwrite >> 8) & 0x03;
cmdblk[10] = (u_char) (rwrite & 0xFF);
cmdblk[11] = (u_char) (wprecomp >> 8) & 0x03;
cmdblk[12] = (u_char) (wprecomp & 0xFF);
cmdblk[13] = ecc;
if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
printk("xd_setparam: error setting characteristics for drive %d\n",drive);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -