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

📄 xd.c

📁 主要内容为linux内核代码
💻 C
📖 第 1 页 / 共 2 页
字号:
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 + -