📄 xd.c
字号:
xd_gendisk.part[minor].nr_sects = 0; }; grok_partitions(&xd_gendisk, target, 1<<6, xd_info[target].heads * xd_info[target].cylinders * xd_info[target].sectors); xd_valid[target] = 1; wake_up(&xd_wait_open); return 0;}/* xd_readwrite: handle a read/write request */static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count){ u_char cmdblk[6],sense[4]; u_short track,cylinder; u_char head,sector,control,mode = PIO_MODE,temp; char **real_buffer; register int i; #ifdef DEBUG_READWRITE printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);#endif /* DEBUG_READWRITE */ control = xd_info[drive].control; if (!xd_dma_buffer) xd_dma_buffer = (char *)xd_dma_mem_alloc(xd_maxsectors * 0x200); while (count) { temp = count < xd_maxsectors ? count : xd_maxsectors; track = block / xd_info[drive].sectors; head = track % xd_info[drive].heads; cylinder = track / xd_info[drive].heads; sector = block % xd_info[drive].sectors;#ifdef DEBUG_READWRITE printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);#endif /* DEBUG_READWRITE */ if (xd_dma_buffer) { mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)(xd_dma_buffer),temp * 0x200); real_buffer = &xd_dma_buffer; for (i=0; i < (temp * 0x200); i++) xd_dma_buffer[i] = buffer[i]; } else real_buffer = &buffer; xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control); switch (xd_command(cmdblk,mode,(u_char *)(*real_buffer),(u_char *)(*real_buffer),sense,XD_TIMEOUT)) { case 1: printk("xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write")); xd_recalibrate(drive); return (0); case 2: if (sense[0] & 0x30) { printk("xd%c: %s - ",'a'+drive,(operation == READ ? "reading" : "writing")); switch ((sense[0] & 0x30) >> 4) { case 0: printk("drive error, code = 0x%X",sense[0] & 0x0F); break; case 1: printk("controller error, code = 0x%X",sense[0] & 0x0F); break; case 2: printk("command error, code = 0x%X",sense[0] & 0x0F); break; case 3: printk("miscellaneous error, code = 0x%X",sense[0] & 0x0F); break; } } if (sense[0] & 0x80) printk(" - CHS = %d/%d/%d\n",((sense[2] & 0xC0) << 2) | sense[3],sense[1] & 0x1F,sense[2] & 0x3F); /* reported drive number = (sense[1] & 0xE0) >> 5 */ else printk(" - no valid disk address\n"); return (0); } if (xd_dma_buffer) for (i=0; i < (temp * 0x200); i++) buffer[i] = xd_dma_buffer[i]; count -= temp, buffer += temp * 0x200, block += temp; } return (1);}/* xd_recalibrate: recalibrate a given drive and reset controller if necessary */static void xd_recalibrate (u_char drive){ u_char cmdblk[6]; xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0); if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8)) printk("xd%c: warning! error recalibrating, controller may be unstable\n", 'a'+drive);}/* xd_interrupt_handler: interrupt service routine */static void xd_interrupt_handler(int irq, void *dev_id, struct pt_regs * regs){ 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: unexpected interrupt\n");}/* xd_setup_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){ unsigned long f; if (nodma) return (PIO_MODE); if (((unsigned long) buffer & 0xFFFF0000) != (((unsigned long) buffer + count) & 0xFFFF0000)) {#ifdef DEBUG_OTHER printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");#endif /* DEBUG_OTHER */ return (PIO_MODE); } f=claim_dma_lock(); disable_dma(xd_dma); clear_dma_ff(xd_dma); set_dma_mode(xd_dma,mode); set_dma_addr(xd_dma, (unsigned long) buffer); set_dma_count(xd_dma,count); release_dma_lock(f); return (DMA_MODE); /* use DMA and INT */}/* 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_wakeup is called from timer interrupt */static void xd_wakeup (unsigned long unused){ wake_up(&xdc_wait);}/* xd_wakeup is called from timer interrupt */static void xd_watchdog (unsigned long unused){ xd_error = 1; wake_up(&xd_wait_int);}/* 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; int success; xdc_busy = 1; while ((success = ((inb(port) & mask) != flags)) && time_before(jiffies, expiry)) { xd_timer.expires = jiffies; cli(); add_timer(&xd_timer); sleep_on(&xdc_wait); del_timer(&xd_timer); sti(); } xdc_busy = 0; return (success);}static inline u_int xd_wait_for_IRQ (void){ unsigned long flags; xd_watchdog_int.expires = jiffies + 8 * HZ; add_timer(&xd_watchdog_int); flags=claim_dma_lock(); enable_dma(xd_dma); release_dma_lock(flags); sleep_on(&xd_wait_int); del_timer(&xd_watchdog_int); xdc_busy = 0; flags=claim_dma_lock(); disable_dma(xd_dma); release_dma_lock(flags); if (xd_error) { printk("xd: missed IRQ - command aborted\n"); xd_error = 0; return (1); } return (0);}/* 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) { if (xd_wait_for_IRQ()) return (1); } else outb(outdata ? *outdata++ : 0,XD_DATA); break; case STAT_INPUT: if (mode == DMA_MODE) { if (xd_wait_for_IRQ()) return (1); } 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: 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 __init 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 * 8)) { xd_timer.expires = jiffies + XD_INIT_DISK_DELAY; add_timer(&xd_timer); sleep_on(&xdc_wait); init_drive(count); count++; xd_timer.expires = jiffies + XD_INIT_DISK_DELAY; add_timer(&xd_timer); sleep_on(&xdc_wait); } } return (count);}static void __init xd_manual_geo_set (u_char drive){ xd_info[drive].heads = (u_char)(xd_geo[3 * drive + 1]); xd_info[drive].cylinders = (u_short)(xd_geo[3 * drive]); xd_info[drive].sectors = (u_char)(xd_geo[3 * drive + 2]);}static void __init xd_dtc_init_controller (unsigned int address){ switch (address) { case 0x00000: case 0xC8000: break; /*initial: 0x320 */ case 0xCA000: xd_iobase = 0x324; case 0xD0000: /*5150CX*/ case 0xD8000: break; /*5150CX & 5150XL*/ default: printk("xd_dtc_init_controller: unsupported BIOS address %06x\n",address); break; } xd_maxsectors = 0x01; /* my card seems to have trouble doing multi-block transfers? */ outb(0,XD_RESET); /* reset the controller */}static void __init xd_dtc5150cx_init_drive (u_char drive){ /* values from controller's BIOS - BIOS chip may be removed */ static u_short geometry_table[][4] = { {0x200,8,0x200,0x100}, {0x267,2,0x267,0x267}, {0x264,4,0x264,0x80}, {0x132,4,0x132,0x0}, {0x132,2,0x80, 0x132}, {0x177,8,0x177,0x0}, {0x132,8,0x84, 0x0}, {}, /* not used */ {0x132,6,0x80, 0x100}, {0x200,6,0x100,0x100}, {0x264,2,0x264,0x80}, {0x280,4,0x280,0x100}, {0x2B9,3,0x2B9,0x2B9}, {0x2B9,5,0x2B9,0x2B9}, {0x280,6,0x280,0x100}, {0x132,4,0x132,0x0}}; u_char n; n = inb(XD_JUMPER); n = (drive ? n : (n >> 2)) & 0x33; n = (n | (n >> 2)) & 0x0F; if (xd_geo[3*drive]) xd_manual_geo_set(drive); else if (n != 7) { xd_info[drive].heads = (u_char)(geometry_table[n][1]); /* heads */ xd_info[drive].cylinders = geometry_table[n][0]; /* cylinders */ xd_info[drive].sectors = 17; /* sectors */#if 0 xd_info[drive].rwrite = geometry_table[n][2]; /* reduced write */ xd_info[drive].precomp = geometry_table[n][3] /* write precomp */ xd_info[drive].ecc = 0x0B; /* ecc length */#endif /* 0 */ } else { printk("xd%c: undetermined drive geometry\n",'a'+drive); return; } xd_info[drive].control = 5; /* control byte */ xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,geometry_table[n][2],geometry_table[n][3],0x0B); xd_recalibrate(drive);}static void __init 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 (xd_geo[3*drive]) xd_manual_geo_set(drive);#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 xd%c\n", 'a'+drive); } else printk("xd_dtc_init_drive: error reading geometry for xd%c\n", 'a'+drive);}static void __init xd_wd_init_controller (unsigned int address){ switch (address) { case 0x00000: case 0xC8000: break; /*initial: 0x320 */ 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 %06x\n",address); break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -