📄 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 + -