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

📄 ps2esdi.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* some annoyance in the above routine returns TWO drives?	 Is something else happining in the background?	 Regaurdless we fix the # of drives again. AJK */	/* Integrated ESDI Disk and Controller has only one drive! */	if (adapterID == INTG_ESDI_ID)	/* if not "normal" PS2 ESDI adapter */		ps2esdi_drives = 1;	/* Not three or two, ONE DAMNIT! */	current_int_handler = ps2esdi_normal_interrupt_handler;	ps2esdi_gendisk.nr_real = ps2esdi_drives;	for (i = 0; i < (MAX_HD << 6); i++)		ps2esdi_blocksizes[i] = 1024;	request_dma(dma_arb_level, "ed");	request_region(io_base, 4, "ed");	blksize_size[MAJOR_NR] = ps2esdi_blocksizes;	for (i = 0; i < ps2esdi_drives; i++) {		register_disk(&ps2esdi_gendisk,MKDEV(MAJOR_NR,i<<6),1<<6,				&ps2esdi_fops,				ps2esdi_info[i].head * ps2esdi_info[i].sect *				ps2esdi_info[i].cyl);		ps2esdi_valid[i] = 1;	}}static void __init ps2esdi_get_device_cfg(void){	u_short cmd_blk[TYPE_0_CMD_BLK_LENGTH];	/*BA */ printk("%s: Drive 0\n", DEVICE_NAME);	current_int_handler = ps2esdi_geometry_int_handler;	cmd_blk[0] = CMD_GET_DEV_CONFIG | 0x600;	cmd_blk[1] = 0;	no_int_yet = TRUE;	ps2esdi_out_cmd_blk(cmd_blk);	if (no_int_yet)		sleep_on(&ps2esdi_int);	if (ps2esdi_drives > 1) {		printk("%s: Drive 1\n", DEVICE_NAME);	/*BA */		cmd_blk[0] = CMD_GET_DEV_CONFIG | (1 << 5) | 0x600;		cmd_blk[1] = 0;		no_int_yet = TRUE;		ps2esdi_out_cmd_blk(cmd_blk);		if (no_int_yet)			sleep_on(&ps2esdi_int);	}			/* if second physical drive is present */	return;}/* strategy routine that handles most of the IO requests */static void do_ps2esdi_request(request_queue_t * q){	u_int block, count;	/* since, this routine is called with interrupts cleared - they 	   must be before it finishes  */	sti();#if 0	printk("%s:got request. device : %d minor : %d command : %d  sector : %ld count : %ld, buffer: %p\n",	       DEVICE_NAME,	       CURRENT_DEV, MINOR(CURRENT->rq_dev),	       CURRENT->cmd, CURRENT->sector,	       CURRENT->nr_sectors, CURRENT->buffer);#endif	/* standard macro that ensures that requests are really on the	   list + sanity checks.                     */	INIT_REQUEST;	if (virt_to_bus(CURRENT->buffer + CURRENT->nr_sectors * 512) > 16 * MB) {		printk("%s: DMA above 16MB not supported\n", DEVICE_NAME);		end_request(FAIL);		if (!QUEUE_EMPTY)			do_ps2esdi_request(q);		return;	}			/* check for above 16Mb dmas */	if ((CURRENT_DEV < ps2esdi_drives) &&	    (CURRENT->sector + CURRENT->nr_sectors <=	     ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects)) {#if 0		printk("%s:got request. device : %d minor : %d command : %d  sector : %ld count : %ld\n",		       DEVICE_NAME,		       CURRENT_DEV, MINOR(CURRENT->dev),		       CURRENT->cmd, CURRENT->sector,		       CURRENT->nr_sectors);#endif		block = CURRENT->sector + ps2esdi[MINOR(CURRENT->rq_dev)].start_sect;#if 0		printk("%s: blocknumber : %d\n", DEVICE_NAME, block);#endif		count = CURRENT->nr_sectors;		switch (CURRENT->cmd) {		case READ:			ps2esdi_readwrite(READ, CURRENT_DEV, block, count);			return;			break;		case WRITE:			ps2esdi_readwrite(WRITE, CURRENT_DEV, block, count);			return;			break;		default:			printk("%s: Unknown command\n", DEVICE_NAME);			end_request(FAIL);			if (!QUEUE_EMPTY)				do_ps2esdi_request(q);			break;		}		/* handle different commands */	}	/* is request is valid */ 	else {		printk("Grrr. error. ps2esdi_drives: %d, %lu %lu\n", ps2esdi_drives,		       CURRENT->sector, ps2esdi[MINOR(CURRENT->rq_dev)].nr_sects);		end_request(FAIL);		if (!QUEUE_EMPTY)			do_ps2esdi_request(q);	}}				/* main strategy routine *//* resets the ESDI adapter */static void reset_ctrl(void){	u_long expire;	u_short status;	/* enable interrupts on the controller */	status = inb(ESDI_INTRPT);	outb((status & 0xe0) | ATT_EOI, ESDI_ATTN);	/* to be sure we don't have							   any interrupt pending... */	outb_p(CTRL_ENABLE_INTR, ESDI_CONTROL);	/* read the ESDI status port - if the controller is not busy,	   simply do a soft reset (fast) - otherwise we'll have to do a	   hard (slow) reset.  */	if (!(inb_p(ESDI_STATUS) & STATUS_BUSY)) {		/*BA */ printk("%s: soft reset...\n", DEVICE_NAME);		outb_p(CTRL_SOFT_RESET, ESDI_ATTN);	}	/* soft reset */ 	else {		/*BA */		printk("%s: hard reset...\n", DEVICE_NAME);		outb_p(CTRL_HARD_RESET, ESDI_CONTROL);		expire = jiffies + 2*HZ;		while (time_before(jiffies, expire));		outb_p(1, ESDI_CONTROL);	}			/* hard reset */}				/* reset the controller *//* called by the strategy routine to handle read and write requests */static void ps2esdi_readwrite(int cmd, u_char drive, u_int block, u_int count){	u_short track, head, cylinder, sector;	u_short cmd_blk[TYPE_1_CMD_BLK_LENGTH];	/* do some relevant arithmatic */	CURRENT->current_nr_sectors =	    (count < (2 * MAX_16BIT / SECT_SIZE)) ? count : (2 * MAX_16BIT / SECT_SIZE);	track = block / ps2esdi_info[drive].sect;	head = track % ps2esdi_info[drive].head;	cylinder = track / ps2esdi_info[drive].head;	sector = block % ps2esdi_info[drive].sect;#if 0	printk("%s: cyl=%d head=%d sect=%d\n", DEVICE_NAME, cylinder, head, sector);#endif	/* call the routine that actually fills out a command block */	ps2esdi_fill_cmd_block	    (cmd_blk,	     (cmd == READ) ? CMD_READ : CMD_WRITE,	     cylinder, head, sector,	     CURRENT->current_nr_sectors, drive);	/* send the command block to the controller */	if (ps2esdi_out_cmd_blk(cmd_blk)) {		printk("%s: Controller failed\n", DEVICE_NAME);		if ((++CURRENT->errors) < MAX_RETRIES)			return do_ps2esdi_request(NULL);		else {			end_request(FAIL);			if (!QUEUE_EMPTY)				do_ps2esdi_request(NULL);		}	}	/* check for failure to put out the command block */ 	else {#if 0		printk("%s: waiting for xfer\n", DEVICE_NAME);#endif		/* turn disk lights on */		LITE_ON;	}}				/* ps2esdi_readwrite *//* fill out the command block */static void ps2esdi_fill_cmd_block(u_short * cmd_blk, u_short cmd, u_short cyl, u_short head, u_short sector, u_short length, u_char drive){	cmd_blk[0] = (drive << 5) | cmd;	cmd_blk[1] = length;	cmd_blk[2] = ((cyl & 0x1f) << 11) | (head << 5) | sector;	cmd_blk[3] = (cyl & 0x3E0) >> 5;}				/* fill out the command block *//* write a command block to the controller */static int ps2esdi_out_cmd_blk(u_short * cmd_blk){	int i, j;	u_char status;	/* enable interrupts */	outb(CTRL_ENABLE_INTR, ESDI_CONTROL);	/* do not write to the controller, if it is busy */	for (i = jiffies + ESDI_STAT_TIMEOUT; time_after(i, jiffies) && (inb(ESDI_STATUS) &							  STATUS_BUSY););#if 0	printk("%s: i(1)=%d\n", DEVICE_NAME, i);#endif	/* if device is still busy - then just time out */	if (inb(ESDI_STATUS) & STATUS_BUSY) {		printk("%s: ps2esdi_out_cmd timed out (1)\n", DEVICE_NAME);		return ERROR;	}			/* timeout ??? */	/* Set up the attention register in the controller */	outb(((*cmd_blk) & 0xE0) | 1, ESDI_ATTN);#if 0	printk("%s: sending %d words to controller\n", DEVICE_NAME, (((*cmd_blk) >> 14) + 1) << 1);#endif	/* one by one send each word out */	for (i = (((*cmd_blk) >> 14) + 1) << 1; i; i--) {		status = inb(ESDI_STATUS);		for (j = jiffies + ESDI_STAT_TIMEOUT;		     time_after(j, jiffies) && (status & STATUS_BUSY) &&		   (status & STATUS_CMD_INF); status = inb(ESDI_STATUS));		if ((status & (STATUS_BUSY | STATUS_CMD_INF)) == STATUS_BUSY) {#if 0			printk("%s: sending %04X\n", DEVICE_NAME, *cmd_blk);#endif			outw(*cmd_blk++, ESDI_CMD_INT);		} else {			printk("%s: ps2esdi_out_cmd timed out while sending command (status=%02X)\n",			       DEVICE_NAME, status);			return ERROR;		}	}			/* send all words out */	return OK;}				/* send out the commands *//* prepare for dma - do all the necessary setup */static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode){	u_int tc;		buffer=(char *)virt_to_bus(buffer);#if 0	printk("ps2esdi: b_wait: %p\n", CURRENT->bh->b_wait);#endif	cli();	outb(dma_arb_level | DMA_MASK_CHAN, PORT_DMA_FN);	outb(dma_arb_level | DMA_WRITE_ADDR, PORT_DMA_FN);	outb((u_int) buffer & (u_int) 0xff, PORT_DMA_EX);	outb(((u_int) buffer >> 8) & (u_int) 0xff, PORT_DMA_EX);	outb(((u_int) buffer >> 16) & (u_int) 0xff, PORT_DMA_EX);	outb(dma_arb_level | DMA_WRITE_TC, PORT_DMA_FN);	tc = (length * SECT_SIZE / 2) - 1;	outb(tc & 0xff, PORT_DMA_EX);	outb((tc >> 8) & 0xff, PORT_DMA_EX);	outb(dma_arb_level | DMA_WRITE_MODE, PORT_DMA_FN);	outb(dma_xmode, PORT_DMA_EX);	outb(dma_arb_level | DMA_UNMASK_CHAN, PORT_DMA_FN);	sti();}				/* prepare for dma */static void ps2esdi_interrupt_handler(int irq, void *dev_id,				      struct pt_regs *regs){	u_int int_ret_code;	if (inb(ESDI_STATUS) & STATUS_INTR) {		int_ret_code = inb(ESDI_INTRPT);		if (current_int_handler) {			/* Disable adapter interrupts till processing is finished */			outb(CTRL_DISABLE_INTR, ESDI_CONTROL);			current_int_handler(int_ret_code);		} else			printk("%s: help ! No interrupt handler.\n", DEVICE_NAME);	} else {		return;	}}static void ps2esdi_initial_reset_int_handler(u_int int_ret_code){	switch (int_ret_code & 0xf) {	case INT_RESET:		/*BA */		printk("%s: initial reset completed.\n", DEVICE_NAME);		outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);		wake_up(&ps2esdi_int);		break;	case INT_ATTN_ERROR:		printk("%s: Attention error. interrupt status : %02X\n", DEVICE_NAME,		       int_ret_code);		printk("%s: status: %02x\n", DEVICE_NAME, inb(ESDI_STATUS));		break;	default:		printk("%s: initial reset handler received interrupt: %02X\n",		       DEVICE_NAME, int_ret_code);		outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);		break;	}	outb(CTRL_ENABLE_INTR, ESDI_CONTROL);}static void ps2esdi_geometry_int_handler(u_int int_ret_code){	u_int status, drive_num;	unsigned long rba;	int i;	drive_num = int_ret_code >> 5;	switch (int_ret_code & 0xf) {	case INT_CMD_COMPLETE:		for (i = ESDI_TIMEOUT; i & !(inb(ESDI_STATUS) & STATUS_STAT_AVAIL); i--);		if (!(inb(ESDI_STATUS) & STATUS_STAT_AVAIL)) {			printk("%s: timeout reading status word\n", DEVICE_NAME);			outb((int_ret_code & 0xe0) | ATT_EOI, ESDI_ATTN);			break;		}		status = inw(ESDI_STT_INT);		if ((status & 0x1F) == CMD_GET_DEV_CONFIG) {#define REPLY_WORDS 5		/* we already read word 0 */			u_short reply[REPLY_WORDS];			if (ps2esdi_read_status_words((status >> 8) - 1, REPLY_WORDS, reply)) {				/*BA */				printk("%s: Device Configuration Status for drive %u\n",				       DEVICE_NAME, drive_num);				printk("%s: Spares/cyls: %u", DEVICE_NAME, reply[0] >> 8);				printk				    ("Config bits: %s%s%s%s%s\n",				     (reply[0] & CONFIG_IS) ? "Invalid Secondary, " : "",				     ((reply[0] & CONFIG_ZD) && !(reply[0] & CONFIG_IS))				 ? "Zero Defect, " : "Defects Present, ",				     (reply[0] & CONFIG_SF) ? "Skewed Format, " : "",				     (reply[0] & CONFIG_FR) ? "Removable, " : "Non-Removable, ",				     (reply[0] & CONFIG_RT) ? "No Retries" : "Retries");				rba = reply[1] | ((unsigned long) reply[2] << 16);				printk("%s: Number of RBA's: %lu\n", DEVICE_NAME, rba);				printk("%s: Physical number of cylinders: %u, Sectors/Track: %u, Heads: %u\n",				       DEVICE_NAME, reply[3], reply[4] >> 8, reply[4] & 0xff);				if (!ps2esdi_info[drive_num].head) {					ps2esdi_info[drive_num].head = 64;					ps2esdi_info[drive_num].sect = 32;					ps2esdi_info[drive_num].cyl = rba / (64 * 32);					ps2esdi_info[drive_num].wpcom = 0;					ps2esdi_info[drive_num].lzone = ps2esdi_info[drive_num].cyl;					ps2esdi_info[drive_num].ctl = 8;					if (tp720esdi) {	/* store the retrieved parameters */						ps2esdi_info[0].head = reply[4] & 0Xff;						ps2esdi_info[0].sect = reply[4] >> 8;						ps2esdi_info[0].cyl = reply[3];						ps2esdi_info[0].wpcom = 0;						ps2esdi_info[0].lzone = reply[3];					} else {						if (!intg_esdi)							ps2esdi_drives++;					}				}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -