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

📄 ide-cd.c

📁 ep9315平台下硬盘驱动的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
{	struct packet_command pc;	struct request *rq = HWGROUP(drive)->rq;	int nsect, sector, nframes, frame, nskip;	/* Number of sectors to transfer. */	nsect = rq->nr_sectors;	/* Starting sector. */	sector = rq->sector;	/* If the requested sector doesn't start on a cdrom block boundary,	   we must adjust the start of the transfer so that it does,	   and remember to skip the first few sectors.	   If the CURRENT_NR_SECTORS field is larger than the size	   of the buffer, it will mean that we're to skip a number	   of sectors equal to the amount by which CURRENT_NR_SECTORS	   is larger than the buffer size. */	nskip = (sector % SECTORS_PER_FRAME);	if (nskip > 0) {		/* Sanity check... */		if (rq->current_nr_sectors != (rq->bh->b_size >> SECTOR_BITS) &&			(rq->sector % CD_FRAMESIZE != 0)) {			printk ("%s: cdrom_start_read_continuation: buffer botch (%lu)\n",				drive->name, rq->current_nr_sectors);			cdrom_end_request(drive, 0);			return ide_stopped;		}		sector -= nskip;		nsect += nskip;		rq->current_nr_sectors += nskip;	}	/* Convert from sectors to cdrom blocks, rounding up the transfer	   length if needed. */	nframes = (nsect + SECTORS_PER_FRAME-1) / SECTORS_PER_FRAME;	frame = sector / SECTORS_PER_FRAME;	/* Largest number of frames was can transfer at once is 64k-1. For	   some drives we need to limit this even more. */	nframes = MIN (nframes, (CDROM_CONFIG_FLAGS (drive)->limit_nframes) ?		(65534 / CD_FRAMESIZE) : 65535);	/* Set up the command */	memset (&pc.c, 0, sizeof (pc.c));	pc.c[0] = GPCMD_READ_10;	pc.c[7] = (nframes >> 8);	pc.c[8] = (nframes & 0xff);	put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]);	pc.timeout = WAIT_CMD;	/* Send the command to the drive and return. */	return cdrom_transfer_packet_command(drive, &pc, &cdrom_read_intr);}#define IDECD_SEEK_THRESHOLD	(1000)			/* 1000 blocks */#define IDECD_SEEK_TIMER	(5 * WAIT_MIN_SLEEP)	/* 100 ms */#define IDECD_SEEK_TIMEOUT     WAIT_CMD			/* 10 sec */static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive){	struct cdrom_info *info = drive->driver_data;	int stat;	static int retry = 10;	ide_startstop_t startstop;	if (cdrom_decode_status (&startstop, drive, 0, &stat))		return startstop;	CDROM_CONFIG_FLAGS(drive)->seeking = 1;	if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) {		if (--retry == 0) {			/*			 * this condition is far too common, to bother			 * users about it			 */#if 0			printk("%s: disabled DSC seek overlap\n", drive->name);#endif			drive->dsc_overlap = 0;		}	}	return ide_stopped;}static ide_startstop_t cdrom_start_seek_continuation (ide_drive_t *drive){	struct packet_command pc;	struct request *rq = HWGROUP(drive)->rq;	int sector, frame, nskip;	sector = rq->sector;	nskip = (sector % SECTORS_PER_FRAME);	if (nskip > 0)		sector -= nskip;	frame = sector / SECTORS_PER_FRAME;	memset (&pc.c, 0, sizeof (pc.c));	pc.c[0] = GPCMD_SEEK;	put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]);	pc.timeout = WAIT_CMD;	return cdrom_transfer_packet_command(drive, &pc, &cdrom_seek_intr);}static ide_startstop_t cdrom_start_seek (ide_drive_t *drive, unsigned int block){	struct cdrom_info *info = drive->driver_data;	info->dma = 0;	info->cmd = 0;	info->start_seek = jiffies;	return cdrom_start_packet_command(drive, 0, cdrom_start_seek_continuation);}static inline int cdrom_merge_requests(struct request *rq, struct request *nxt){	int ret = 1;	/*	 * partitions not really working, but better check anyway...	 */	if (rq->cmd == nxt->cmd && rq->rq_dev == nxt->rq_dev) {		rq->nr_sectors += nxt->nr_sectors;		rq->hard_nr_sectors += nxt->nr_sectors;		rq->bhtail->b_reqnext = nxt->bh;		rq->bhtail = nxt->bhtail;		list_del(&nxt->queue);		blkdev_release_request(nxt);		ret = 0;	}	return ret;}/* * the current request will always be the first one on the list */static void cdrom_attempt_remerge(ide_drive_t *drive, struct request *rq){	struct list_head *entry;	struct request *nxt;	unsigned long flags;	spin_lock_irqsave(&io_request_lock, flags);	while (1) {		entry = rq->queue.next;		if (entry == &drive->queue.queue_head)			break;		nxt = blkdev_entry_to_request(entry);		if (rq->sector + rq->nr_sectors != nxt->sector)			break;		else if (rq->nr_sectors + nxt->nr_sectors > SECTORS_MAX)			break;		if (cdrom_merge_requests(rq, nxt))			break;	}	spin_unlock_irqrestore(&io_request_lock, flags);}/* Fix up a possibly partially-processed request so that we can   start it over entirely, or even put it back on the request queue. */static void restore_request (struct request *rq){	if (rq->buffer != rq->bh->b_data) {		int n = (rq->buffer - rq->bh->b_data) / SECTOR_SIZE;		rq->buffer = rq->bh->b_data;		rq->nr_sectors += n;		rq->sector -= n;	}	rq->current_nr_sectors = rq->bh->b_size >> SECTOR_BITS;	rq->hard_nr_sectors = rq->nr_sectors;	rq->hard_sector = rq->sector;}/* * Start a read request from the CD-ROM. */static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block){	struct cdrom_info *info = drive->driver_data;	struct request *rq = HWGROUP(drive)->rq;	int minor = MINOR(rq->rq_dev);	/* If the request is relative to a partition, fix it up to refer to the	   absolute address.  */	if (minor & PARTN_MASK) {		rq->sector = block;		minor &= ~PARTN_MASK;		rq->rq_dev = MKDEV(MAJOR(rq->rq_dev), minor);	}	/* We may be retrying this request after an error.  Fix up	   any weirdness which might be present in the request packet. */	restore_request(rq);	/* Satisfy whatever we can of this request from our cached sector. */	if (cdrom_read_from_buffer(drive))		return ide_stopped;	cdrom_attempt_remerge(drive, rq);	/* Clear the local sector buffer. */	info->nsectors_buffered = 0;	/* use dma, if possible. */	if (drive->using_dma && (rq->sector % SECTORS_PER_FRAME == 0) &&				(rq->nr_sectors % SECTORS_PER_FRAME == 0))		info->dma = 1;	else		info->dma = 0;	info->cmd = READ;	/* Start sending the read request to the drive. */	return cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation);}/**************************************************************************** * Execute all other packet commands. *//* Forward declarations. */static int cdrom_lockdoor(ide_drive_t *drive, int lockflag,			  struct request_sense *sense);/* Interrupt routine for packet command completion. */static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive){	int ireason, len, stat, thislen;	struct request *rq = HWGROUP(drive)->rq;	struct packet_command *pc = (struct packet_command *)rq->buffer;	ide_startstop_t startstop;	u8 lowcyl = 0, highcyl = 0;	/* Check for errors. */	if (cdrom_decode_status(&startstop, drive, 0, &stat))		return startstop;	/* Read the interrupt reason and the transfer length. */	ireason = HWIF(drive)->INB(IDE_IREASON_REG);	lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);	highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);	len = lowcyl + (256 * highcyl);	/* If DRQ is clear, the command has completed.	   Complain if we still have data left to transfer. */	if ((stat & DRQ_STAT) == 0) {		/* Some of the trailing request sense fields are optional, and		   some drives don't send them.  Sigh. */		if (pc->c[0] == GPCMD_REQUEST_SENSE &&		    pc->buflen > 0 &&		    pc->buflen <= 5) {			while (pc->buflen > 0) {				*pc->buffer++ = 0;				--pc->buflen;			}		}		if (pc->buflen == 0)			cdrom_end_request(drive, 1);		else {			/* Comment this out, because this always happens 			   right after a reset occurs, and it is annoying to 			   always print expected stuff.  */			/*			printk ("%s: cdrom_pc_intr: data underrun %d\n",				drive->name, pc->buflen);			*/			pc->stat = 1;			cdrom_end_request(drive, 1);		}		return ide_stopped;	}	/* Figure out how much data to transfer. */	thislen = pc->buflen;	if (thislen > len) thislen = len;	/* The drive wants to be written to. */	if ((ireason & 3) == 0) {		/* Transfer the data. */		HWIF(drive)->atapi_output_bytes(drive, pc->buffer, thislen);		/* If we haven't moved enough data to satisfy the drive,		   add some padding. */		while (len > thislen) {			int dum = 0;			HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof(dum));			len -= sizeof(dum);		}		/* Keep count of how much data we've moved. */		pc->buffer += thislen;		pc->buflen -= thislen;	}	/* Same drill for reading. */	else if ((ireason & 3) == 2) {		/* Transfer the data. */		HWIF(drive)->atapi_input_bytes(drive, pc->buffer, thislen);		/* If we haven't moved enough data to satisfy the drive,		   add some padding. */		while (len > thislen) {			int dum = 0;			HWIF(drive)->atapi_input_bytes(drive, &dum, sizeof(dum));			len -= sizeof(dum);		}		/* Keep count of how much data we've moved. */		pc->buffer += thislen;		pc->buflen -= thislen;	} else {		printk ("%s: cdrom_pc_intr: The drive "			"appears confused (ireason = 0x%2x)\n",			drive->name, ireason);		pc->stat = 1;	}	/* Now we wait for another interrupt. */	ide_set_handler(drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry);	return ide_started;}static ide_startstop_t cdrom_do_pc_continuation (ide_drive_t *drive){	struct request *rq = HWGROUP(drive)->rq;	struct packet_command *pc = (struct packet_command *)rq->buffer;	if (!pc->timeout)		pc->timeout = WAIT_CMD;	/* Send the command to the drive and return. */	return cdrom_transfer_packet_command(drive, pc, &cdrom_pc_intr);}static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive){	int len;	struct request *rq = HWGROUP(drive)->rq;	struct packet_command *pc = (struct packet_command *)rq->buffer;	struct cdrom_info *info = drive->driver_data;	info->dma = 0;	info->cmd = 0;	pc->stat = 0;	len = pc->buflen;	/* Start sending the command to the drive. */	return cdrom_start_packet_command(drive, len, cdrom_do_pc_continuation);}/* Sleep for TIME jiffies.   Not to be called from an interrupt handler. */staticvoid cdrom_sleep (int time){	int sleep = time;	do {		set_current_state(TASK_INTERRUPTIBLE);		sleep = schedule_timeout(sleep);	} while (sleep);}staticint cdrom_queue_packet_command(ide_drive_t *drive, struct packet_command *pc){	struct request_sense sense;	struct request req;	int retries = 10;	if (pc->sense == NULL)		pc->sense = &sense;	/* Start of retry loop. */	do {		ide_init_drive_cmd (&req);		req.cmd = PACKET_COMMAND;		req.buffer = (char *)pc;		ide_do_drive_cmd(drive, &req, ide_wait);		/* FIXME: we should probably abort/retry or something 		 * in case of failure */		if (pc->stat != 0) {			/* The request failed.  Retry if it was due to a unit			   attention status			   (usually means media was changed). */			struct request_sense *reqbuf = pc->sense;			if (reqbuf->sense_key == UNIT_ATTENTION)				cdrom_saw_media_change(drive);			else if (reqbuf->sense_key == NOT_READY &&				 reqbuf->asc == 4 && reqbuf->ascq != 4) {				/* The drive is in the process of loading				   a disk.  Retry, but wait a little to give				   the drive time to complete the load. */				cdrom_sleep(2 * HZ);			} else {				/* Otherwise, don't retry. */				retries = 0;			}			--retries;		}

⌨️ 快捷键说明

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