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

📄 ide-cd.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 5 页
字号:
	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) != 0) {		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;	/* 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;	/* Check for errors. */	if (cdrom_decode_status (&startstop, drive, 0, &stat))		return startstop;	/* Read the interrupt reason and the transfer length. */	ireason = IN_BYTE (IDE_NSECTOR_REG);	len = IN_BYTE (IDE_LCYL_REG) + 256 * IN_BYTE (IDE_HCYL_REG);	/* 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 (1, drive);		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 (1, drive);		}		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. */		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;			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. */		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;			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;		if (ide_do_drive_cmd (drive, &req, ide_wait)) {			printk("%s: do_drive_cmd returned stat=%02x,err=%02x\n",				drive->name, req.buffer[0], req.buffer[1]);			/* FIXME: we should probably abort/retry or something */		}		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;		}		/* End of retry loop. */	} while (pc->stat != 0 && retries >= 0);	/* Return an error if the command failed. */	return pc->stat ? -EIO : 0;}/* * Write handling */static inline int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason){	/* Two notes about IDE interrupt reason here - 0 means that	 * the drive wants to receive data from us, 2 means that	 * the drive is expecting data from us.	 */	ireason &= 3;	if (ireason == 2) {		/* Whoops... The drive wants to send data. */		printk("%s: cdrom_write_intr: wrong transfer direction!\n",			drive->name);		/* Throw some data at the drive so it doesn't hang		   and quit this request. */		while (len > 0) {			int dum = 0;			atapi_output_bytes(drive, &dum, sizeof(dum));			len -= sizeof(dum);		}	} else {		/* Drive wants a command packet, or invalid ireason... */		printk("%s: cdrom_write_intr: bad interrupt reason %d\n",			drive->name, ireason);	}	cdrom_end_request(0, drive);	return 1;}static ide_startstop_t cdrom_write_intr(ide_drive_t *drive){	int stat, ireason, len, sectors_to_transfer;	struct cdrom_info *info = drive->driver_data;	int i, dma_error = 0, dma = info->dma;	ide_startstop_t startstop;	struct request *rq = HWGROUP(drive)->rq;	/* Check for errors. */	if (dma) {		info->dma = 0;		if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive))) {			printk("ide-cd: write dma error\n");			HWIF(drive)->dmaproc(ide_dma_off, drive);		}	}	if (cdrom_decode_status(&startstop, drive, 0, &stat)) {		printk("ide-cd: write_intr decode_status bad\n");		return startstop;	} 	if (dma) {		if (dma_error)			return ide_error(drive, "dma error", stat);		rq = HWGROUP(drive)->rq;		for (i = rq->nr_sectors; i > 0;) {			i -= rq->current_nr_sectors;			ide_end_request(1, HWGROUP(drive));		}		return ide_stopped;	}	/* Read the interrupt reason and the transfer length. */	ireason = IN_BYTE(IDE_NSECTOR_REG);	len = IN_BYTE(IDE_LCYL_REG) + 256 * IN_BYTE(IDE_HCYL_REG);	/* If DRQ is clear, the command has completed. */	if ((stat & DRQ_STAT) == 0) {		/* If we're not done writing, complain.		 * Otherwise, complete the command normally.		 */		if (rq->current_nr_sectors > 0) {			printk("%s: write_intr: data underrun (%ld blocks)\n",				drive->name, rq->current_nr_sectors);			cdrom_end_request(0, drive);		} else			cdrom_end_request(1, drive);		return ide_stopped;	}	/* Check that the drive is expecting to do the same thing we are. */	if (ireason & 3)		if (cdrom_write_check_ireason(drive, len, ireason))			return ide_stopped;	/* The number of sectors we need to read from the drive. */	sectors_to_transfer = len / SECTOR_SIZE;	/* Now loop while we still have data to read from the drive. DMA	 * transfers will already have been complete	 */	while (sectors_to_transfer > 0) {		/* If we've filled the present buffer but there's another		   chained buffer after it, move on. */		if (rq->current_nr_sectors == 0 && rq->nr_sectors > 0)			cdrom_end_request(1, drive);		atapi_output_bytes(drive, rq->buffer, rq->current_nr_sectors);		rq->nr_sectors -= rq->current_nr_sectors;		rq->current_nr_sectors = 0;		rq->sector += rq->current_nr_sectors;		sectors_to_transfer -= rq->current_nr_sectors;	}	/* arm handler */	ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL);	return ide_started;}static ide_startstop_t cdrom_start_write_cont(ide_drive_t *drive){	struct packet_command pc;	/* packet_command_t pc; */	struct request *rq = HWGROUP(drive)->rq;	unsigned nframes, frame;	nframes = rq->nr_sectors >> 2;	frame = rq->sector >> 2;	memset(&pc.c, 0, sizeof(pc.c));	/*	 * we might as well use WRITE_12, but none of the device I have	 * support the streaming feature anyway, so who cares.	 */	pc.c[0] = GPCMD_WRITE_10;#if 0	/* the immediate bit */	pc.c[1] = 1 << 3;#endif	pc.c[7] = (nframes >> 8) & 0xff;	pc.c[8] = nframes & 0xff;	put_unaligned(cpu_to_be32(frame), (unsigned int *)&pc.c[2]);	pc.timeout = 2 * WAIT_CMD;	return cdrom_transfer_packet_command(drive, &pc, cdrom_write_intr);}static ide_startstop_t cdrom_start_write(ide_drive_t *drive){	struct cdrom_info *info = drive->driver_data;	info->nsectors_buffered = 0;        /* use dma, if possible. we don't need to check more, since we	 * know that the transfer is always (at least!) 2KB aligned */	info->dma = drive->using_dma ? 1 : 0;	info->cmd = WRITE;	/* Start sending the read request to the drive. */	return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont);}/**************************************************************************** * cdrom driver request routine. */static ide_startstop_tide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, unsigned long block){	ide_startstop_t action;	struct cdrom_info *info = drive->driver_data;	switch (rq->cmd) {		case WRITE:		case READ: {			if (CDROM_CONFIG_FLAGS(drive)->seeking) {				unsigned long elpased = jiffies - info->start_seek;				int stat = GET_STAT();				if ((stat & SEEK_STAT) != SEEK_STAT) {					if (elpased < IDECD_SEEK_TIMEOUT) {						ide_stall_queue(drive, IDECD_SEEK_TIMER);						return ide_stopped;

⌨️ 快捷键说明

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