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

📄 ide-cd.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		reqbuf->error_code, reqbuf->sense_key,		reqbuf->asc, reqbuf->ascq);#endif /* not VERBOSE_IDE_CD_ERRORS */}/* 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;}static void cdrom_queue_request_sense (ide_drive_t *drive, 				       struct semaphore *sem,				       struct atapi_request_sense *reqbuf,				       struct packet_command *failed_command){	struct cdrom_info *info = drive->driver_data;	struct request *rq;	struct packet_command *pc;	int len;	/* If the request didn't explicitly specify where	   to put the sense data, use the statically allocated structure. */	if (reqbuf == NULL)		reqbuf = &info->sense_data;	/* Make up a new request to retrieve sense information. */	pc = &info->request_sense_pc;	memset (pc, 0, sizeof (*pc));	/* The request_sense structure has an odd number of (16-bit) words,	   which won't work well with 32-bit transfers.  However, we don't care	   about the last two bytes, so just truncate the structure down	   to an even length. */	len = sizeof (*reqbuf) / 4;	len *= 4;	pc->c[0] = REQUEST_SENSE;	pc->c[4] = (unsigned char) len;	pc->buffer = (char *)reqbuf;	pc->buflen = len;	pc->sense_data = (struct atapi_request_sense *)failed_command;	/* stuff the sense request in front of our current request */	rq = &info->request_sense_request;	ide_init_drive_cmd (rq);	rq->cmd = REQUEST_SENSE_COMMAND;	rq->buffer = (char *)pc;	rq->sem = sem;	(void) ide_do_drive_cmd (drive, rq, ide_preempt);}static void cdrom_end_request (int uptodate, ide_drive_t *drive){	struct request *rq = HWGROUP(drive)->rq;	if (rq->cmd == REQUEST_SENSE_COMMAND && uptodate) {		struct packet_command *pc = (struct packet_command *)			                      rq->buffer;		cdrom_analyze_sense_data (drive,					  (struct atapi_request_sense *)					  	(pc->buffer - pc->c[4]), 					  (struct packet_command *)					  	pc->sense_data);	}	if (rq->cmd == READ && !rq->current_nr_sectors)		uptodate = 1;	ide_end_request (uptodate, HWGROUP(drive));}/* Returns 0 if the request should be continued.   Returns 1 if the request was ended. */static int cdrom_decode_status (ide_drive_t *drive, int good_stat,				int *stat_ret){	struct request *rq = HWGROUP(drive)->rq;	int stat, err, sense_key, cmd;	/* Check for errors. */	stat = GET_STAT();	*stat_ret = stat;	if (OK_STAT (stat, good_stat, BAD_R_STAT))		return 0;	/* Got an error. */	err = IN_BYTE (IDE_ERROR_REG);	sense_key = err >> 4;	if (rq == NULL)		printk ("%s: missing request in cdrom_decode_status\n",			drive->name);	else {		cmd = rq->cmd;		if (cmd == REQUEST_SENSE_COMMAND) {			/* We got an error trying to get sense info			   from the drive (probably while trying			   to recover from a former error).  Just give up. */			struct packet_command *pc = (struct packet_command *)				                      rq->buffer;			pc->stat = 1;			cdrom_end_request (1, drive);			ide_error (drive, "request sense failure", stat);			return 1;		} else if (cmd == PACKET_COMMAND) {			/* All other functions, except for READ. */			struct packet_command *pc = (struct packet_command *)				                      rq->buffer;			struct semaphore *sem = NULL;			/* Check for tray open. */			if (sense_key == NOT_READY) {				cdrom_saw_media_change (drive);#if 0	/* let the upper layers do the complaining */				/* Print an error message to the syslog.				   Exception: don't print anything if this				   is a read subchannel command.  This is				   because workman constantly polls the drive				   with this command, and we don't want				   to uselessly fill up the syslog. */				if (pc->c[0] != SCMD_READ_SUBCHANNEL)					printk ("%s: tray open or drive not ready\n", drive->name);#endif			} else if (sense_key == UNIT_ATTENTION) {				/* Check for media change. */				cdrom_saw_media_change (drive);				/*printk("%s: media changed\n",drive->name);*/				return 0;			} else {				/* Otherwise, print an error. */				ide_dump_status (drive, "packet command error",						 stat);			}						/* Set the error flag and complete the request.			   Then, if we have a CHECK CONDITION status,			   queue a request sense command.  We must be careful,			   though: we don't want the thread in			   cdrom_queue_packet_command to wake up until			   the request sense has completed.  We do this			   by transferring the semaphore from the packet			   command request to the request sense request. */			if ((stat & ERR_STAT) != 0) {				sem = rq->sem;				rq->sem = NULL;			}			pc->stat = 1;			cdrom_end_request (1, drive);			if ((stat & ERR_STAT) != 0)				cdrom_queue_request_sense (drive, sem,							   pc->sense_data, pc);		} else {			/* Handle errors from READ requests. */			if (sense_key == NOT_READY) {				/* Tray open. */				cdrom_saw_media_change (drive);				/* Fail the request. */				printk ("%s: tray open\n", drive->name);				cdrom_end_request (0, drive);			} else if (sense_key == UNIT_ATTENTION) {				/* Media change. */				cdrom_saw_media_change (drive);				/* Arrange to retry the request.				   But be sure to give up if we've retried				   too many times. */				if (++rq->errors > ERROR_MAX)					cdrom_end_request (0, drive);			} else if (sense_key == ILLEGAL_REQUEST ||				   sense_key == DATA_PROTECT) {				/* No point in retrying after an illegal				   request or data protect error.*/				ide_dump_status (drive, "command error", stat);				cdrom_end_request (0, drive);			} else if ((err & ~ABRT_ERR) != 0) {				/* Go to the default handler				   for other errors. */				ide_error (drive, "cdrom_decode_status", stat);				return 1;			} else if ((++rq->errors > ERROR_MAX)) {				/* We've racked up too many retries.  Abort. */				cdrom_end_request (0, drive);			}			/* If we got a CHECK_CONDITION status,			   queue a request sense command. */			if ((stat & ERR_STAT) != 0)				cdrom_queue_request_sense (drive,							   NULL, NULL, NULL);		}	}	/* Retry, or handle the next request. */	return 1;}/* Set up the device registers for transferring a packet command on DEV,   expecting to later transfer XFERLEN bytes.  HANDLER is the routine   which actually transfers the command to the drive.  If this is a   drq_interrupt device, this routine will arrange for HANDLER to be   called when the interrupt from the drive arrives.  Otherwise, HANDLER   will be called immediately after the drive is prepared for the transfer. */static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen,				       ide_handler_t *handler){	struct cdrom_info *info = drive->driver_data;	/* Wait for the controller to be idle. */	if (ide_wait_stat (drive, 0, BUSY_STAT, WAIT_READY)) return 1;	if (info->dma)		info->dma = !HWIF(drive)->dmaproc(ide_dma_read, drive);	/* Set up the controller registers. */	OUT_BYTE (info->dma, IDE_FEATURE_REG);	OUT_BYTE (0, IDE_NSECTOR_REG);	OUT_BYTE (0, IDE_SECTOR_REG);	OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);	OUT_BYTE (xferlen >> 8  , IDE_HCYL_REG);	OUT_BYTE (drive->ctl, IDE_CONTROL_REG); 	if (info->dma)		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {		ide_set_handler (drive, handler, WAIT_CMD);		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */	} else {		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */		(*handler) (drive);	}	return 0;}/* Send a packet command to DRIVE described by CMD_BUF and CMD_LEN.   The device registers must have already been prepared   by cdrom_start_packet_command.   HANDLER is the interrupt handler to call when the command completes   or there's data ready. */static int cdrom_transfer_packet_command (ide_drive_t *drive,                                          char *cmd_buf, int cmd_len,					  ide_handler_t *handler){	if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {		/* Here we should have been called after receiving an interrupt		   from the device.  DRQ should how be set. */		int stat_dum;		/* Check for errors. */		if (cdrom_decode_status (drive, DRQ_STAT, &stat_dum))			return 1;	} else {		/* Otherwise, we must wait for DRQ to get set. */		if (ide_wait_stat (drive, DRQ_STAT, BUSY_STAT, WAIT_READY))			return 1;	}	/* Arm the interrupt handler. */	ide_set_handler (drive, handler, WAIT_CMD);	/* Send the command to the device. */	atapi_output_bytes (drive, cmd_buf, cmd_len);	return 0;}/**************************************************************************** * Block read functions. *//* * Buffer up to SECTORS_TO_TRANSFER sectors from the drive in our sector * buffer.  Once the first sector is added, any subsequent sectors are * assumed to be continuous (until the buffer is cleared).  For the first * sector added, SECTOR is its sector number.  (SECTOR is then ignored until * the buffer is cleared.) */static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector,                                  int sectors_to_transfer){	struct cdrom_info *info = drive->driver_data;	/* Number of sectors to read into the buffer. */	int sectors_to_buffer = MIN (sectors_to_transfer,				     (SECTOR_BUFFER_SIZE >> SECTOR_BITS) -				       info->nsectors_buffered);	char *dest;	/* If we don't yet have a sector buffer, try to allocate one.	   If we can't get one atomically, it's not fatal -- we'll just throw	   the data away rather than caching it. */	if (info->sector_buffer == NULL) {		info->sector_buffer = (char *) kmalloc (SECTOR_BUFFER_SIZE,							GFP_ATOMIC);		/* If we couldn't get a buffer,		   don't try to buffer anything... */		if (info->sector_buffer == NULL)			sectors_to_buffer = 0;	}	/* If this is the first sector in the buffer, remember its number. */	if (info->nsectors_buffered == 0)		info->sector_buffered = sector;	/* Read the data into the buffer. */	dest = info->sector_buffer + info->nsectors_buffered * SECTOR_SIZE;	while (sectors_to_buffer > 0) {		atapi_input_bytes (drive, dest, SECTOR_SIZE);		--sectors_to_buffer;		--sectors_to_transfer;		++info->nsectors_buffered;		dest += SECTOR_SIZE;	}	/* Throw away any remaining data. */	while (sectors_to_transfer > 0) {		char dum[SECTOR_SIZE];		atapi_input_bytes (drive, dum, sizeof (dum));		--sectors_to_transfer;	}}/* * Check the contents of the interrupt reason register from the cdrom * and attempt to recover if there are problems.  Returns  0 if everything's * ok; nonzero if the request has been terminated. */static inlineint cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason){	ireason &= 3;	if (ireason == 2) return 0;	if (ireason == 0) {		/* Whoops... The drive is expecting to receive data from us! */		printk ("%s: cdrom_read_intr: "			"Drive wants to transfer data the wrong way!\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_read_intr: bad interrupt reason %d\n",			drive->name, ireason);	}	cdrom_end_request (0, drive);	return -1;}/* * Interrupt routine.  Called when a read request has completed. */static void cdrom_read_intr (ide_drive_t *drive){	int stat;	int ireason, len, sectors_to_transfer, nskip;	struct cdrom_info *info = drive->driver_data;	int i, dma = info->dma, dma_error = 0;	struct request *rq = HWGROUP(drive)->rq;	/* Check for errors. */	if (dma) {		info->dma = 0;		if ((dma_error = HWIF(drive)->dmaproc(ide_dma_end, drive)))			HWIF(drive)->dmaproc(ide_dma_off, drive);	}	if (cdrom_decode_status (drive, 0, &stat))		return; 	if (dma) {		if (!dma_error) {			for (i = rq->nr_sectors; i > 0;) {				i -= rq->current_nr_sectors;				ide_end_request(1, HWGROUP(drive));			}		} else			ide_error (drive, "dma error", stat);		return;	}	/* 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) {

⌨️ 快捷键说明

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