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

📄 ps2esdi.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	/* BA */	printk("%s: DMA arbitration level : %d\n",	       DEVICE_NAME, dma_arb_level);	LITE_ON;	current_int_handler = ps2esdi_initial_reset_int_handler;	reset_ctrl();	reset_status = 0;	reset_start = jiffies;	while (!reset_status) {		init_timer(&esdi_timer);		esdi_timer.expires = jiffies + HZ;		esdi_timer.data = 0;		add_timer(&esdi_timer);		sleep_on(&ps2esdi_int);	}	reset_end = jiffies;	LITE_OFF;	printk("%s: reset interrupt after %d jiffies,  %u.%02u secs\n",	       DEVICE_NAME, reset_end - reset_start, (reset_end - reset_start) / HZ,	       (reset_end - reset_start) % HZ);	/* Integrated ESDI Disk and Controller has only one drive! */	if (adapterID == INTG_ESDI_ID) {/* if not "normal" PS2 ESDI adapter */		ps2esdi_drives = 1;	/* then we have only one physical disk! */		intg_esdi = 1;	}	/* finally this part sets up some global data structures etc. */	ps2esdi_get_device_cfg();	/* 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;	if (request_dma(dma_arb_level, "ed") !=0) {		printk(KERN_WARNING "PS2ESDI: Can't request dma-channel %d\n"			,(int) dma_arb_level);		error = -EBUSY;		goto err_out3;	}	blk_queue_max_sectors(ps2esdi_queue, 128);	error = -ENOMEM;	for (i = 0; i < ps2esdi_drives; i++) {		struct gendisk *disk = alloc_disk(64);		if (!disk)			goto err_out4;		disk->major = PS2ESDI_MAJOR;		disk->first_minor = i<<6;		sprintf(disk->disk_name, "ed%c", 'a'+i);		sprintf(disk->devfs_name, "ed/target%d", i);		disk->fops = &ps2esdi_fops;		ps2esdi_gendisk[i] = disk;	}	for (i = 0; i < ps2esdi_drives; i++) {		struct gendisk *disk = ps2esdi_gendisk[i];		set_capacity(disk, ps2esdi_info[i].head * ps2esdi_info[i].sect *				ps2esdi_info[i].cyl);		disk->queue = ps2esdi_queue;		disk->private_data = &ps2esdi_info[i];		add_disk(disk);	}	return 0;err_out4:	while (i--)		put_disk(ps2esdi_gendisk[i]);err_out3:	release_region(io_base, 4);err_out2:	free_irq(PS2ESDI_IRQ, &ps2esdi_gendisk);err_out1:	if(ps2esdi_slot) {		mca_mark_as_unused(ps2esdi_slot);		mca_set_adapter_procfn(ps2esdi_slot, NULL, NULL);	}	return error;}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){	struct request *req;	/* since, this routine is called with interrupts cleared - they 	   must be before it finishes  */	req = elv_next_request(q);	if (!req)		return;#if 0	printk("%s:got request. device : %s command : %d  sector : %ld count : %ld, buffer: %p\n",	       DEVICE_NAME,	       req->rq_disk->disk_name,	       req->cmd, req->sector,	       req->current_nr_sectors, req->buffer);#endif	/* check for above 16Mb dmas */	if (isa_virt_to_bus(req->buffer + req->current_nr_sectors * 512) > 16 * MB) {		printk("%s: DMA above 16MB not supported\n", DEVICE_NAME);		end_request(req, FAIL);		return;	}	if (req->sector+req->current_nr_sectors > get_capacity(req->rq_disk)) {		printk("Grrr. error. ps2esdi_drives: %d, %llu %llu\n",		    ps2esdi_drives, req->sector,		    (unsigned long long)get_capacity(req->rq_disk));		end_request(req, FAIL);		return;	}	switch (rq_data_dir(req)) {	case READ:		ps2esdi_readwrite(READ, req);		break;	case WRITE:		ps2esdi_readwrite(WRITE, req);		break;	default:		printk("%s: Unknown command\n", req->rq_disk->disk_name);		end_request(req, FAIL);		break;	}		/* handle different commands */}				/* 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, struct request *req){	struct ps2esdi_i_struct *p = req->rq_disk->private_data;	unsigned block = req->sector;	unsigned count = req->current_nr_sectors;	int drive = p - ps2esdi_info;	u_short track, head, cylinder, sector;	u_short cmd_blk[TYPE_1_CMD_BLK_LENGTH];	/* do some relevant arithmatic */	track = block / p->sect;	head = track % p->head;	cylinder = track / p->head;	sector = block % p->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, count, drive);	/* send the command block to the controller */	current_req = req;	spin_unlock_irq(&ps2esdi_lock);	if (ps2esdi_out_cmd_blk(cmd_blk)) {		spin_lock_irq(&ps2esdi_lock);		printk("%s: Controller failed\n", DEVICE_NAME);		if ((++req->errors) >= MAX_RETRIES)			end_request(req, FAIL);	}	/* check for failure to put out the command block */ 	else {		spin_lock_irq(&ps2esdi_lock);#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;	unsigned long jif;	u_char status;	/* enable interrupts */	outb(CTRL_ENABLE_INTR, ESDI_CONTROL);	/* do not write to the controller, if it is busy */	for (jif = jiffies + ESDI_STAT_TIMEOUT;		time_after(jif, jiffies) &&			(inb(ESDI_STATUS) & STATUS_BUSY); )		;#if 0	printk("%s: i(1)=%ld\n", DEVICE_NAME, jif);#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 (jif = jiffies + ESDI_STAT_TIMEOUT;		     time_after(jif, 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){	unsigned long flags = claim_dma_lock();	mca_disable_dma(dma_arb_level);	mca_set_dma_addr(dma_arb_level, isa_virt_to_bus(buffer));	mca_set_dma_count(dma_arb_level, length * 512 / 2);	mca_set_dma_mode(dma_arb_level, dma_xmode);	mca_enable_dma(dma_arb_level);	release_dma_lock(flags);}				/* prepare for dma */static irqreturn_t 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 IRQ_NONE;	}	return IRQ_HANDLED;}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);

⌨️ 快捷键说明

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