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

📄 sr.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 3 页
字号:
	*((unsigned int*)buf+1) = 0x16;  /* and receive 0x16 bytes */	cmd[0] = 0xde;	cmd[1] = 0x03;	cmd[2] = 0xb0;	rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,			   SCSI_IOCTL_SEND_COMMAND, buf);	if (rc != 0) {            if (rc != 0x28000002) /* drop "not ready" */                printk(KERN_WARNING"sr_photocd: ioctl error (NEC): 0x%x\n",rc);	    break;	}	if (rec[14] != 0 && rec[14] != 0xb0) {	    printk(KERN_INFO"sr_photocd: (NEC) Hmm, seems the CDROM doesn't support multisession CD's\n");	    no_multi = 1;	    break;	}	min   = (unsigned long) rec[15]/16*10 + (unsigned long) rec[15]%16;	sec   = (unsigned long) rec[16]/16*10 + (unsigned long) rec[16]%16;	frame = (unsigned long) rec[17]/16*10 + (unsigned long) rec[17]%16;	sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;	is_xa  = (rec[14] == 0xb0);#ifdef DEBUG	if (sector) {	    printk(KERN_DEBUG "sr_photocd: multisession CD detected. start: %lu\n",sector);	}#endif	break;	    case SCSI_MAN_TOSHIBA:#ifdef DEBUG	printk(KERN_DEBUG "sr_photocd: use TOSHIBA code\n");#endif		/* we request some disc information (is it a XA-CD ?,	 * where starts the last session ?) */	memset(buf,0,40);	*((unsigned int*)buf)   = (unsigned int) 0;	*((unsigned int*)buf+1) = (unsigned int) 4;  /* receive 4 bytes */	cmd[0]                  = (unsigned char) 0x00c7;	cmd[1]                  = (unsigned char) 3;	rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,			       SCSI_IOCTL_SEND_COMMAND, buf);	if (rc != 0) {	    if (rc == 0x28000002) {		/* Got a "not ready" - error. No chance to find out if this is		 * because there is no CD in the drive or because the drive		 * don't knows multisession CD's. So I need to do an extra                 * check... */		if (!kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,				       SCSI_IOCTL_TEST_UNIT_READY, NULL)) {		    printk(KERN_INFO "sr_photocd: (TOSHIBA) Hmm, seems the CDROM doesn't support multisession CD's\n");		    no_multi = 1;		}	    } else		printk(KERN_INFO"sr_photocd: ioctl error (TOSHIBA #1): 0x%x\n",rc);	    break; /* if the first ioctl fails, we don't call the second one */	}	is_xa  = (rec[0] == 0x20);	min    = (unsigned long) rec[1]/16*10 + (unsigned long) rec[1]%16;	sec    = (unsigned long) rec[2]/16*10 + (unsigned long) rec[2]%16;	frame  = (unsigned long) rec[3]/16*10 + (unsigned long) rec[3]%16;	sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;	if (sector) {	    sector -= CD_BLOCK_OFFSET;#ifdef DEBUG	    printk(KERN_DEBUG "sr_photocd: multisession CD detected: start: %lu\n",sector);#endif	}		/* now we do a get_density... */	memset(buf,0,40);	*((unsigned int*)buf)   = (unsigned int) 0;	*((unsigned int*)buf+1) = (unsigned int) 12;	cmd[0]                  = (unsigned char) MODE_SENSE;	cmd[2]                  = (unsigned char) 1;	cmd[4]                  = (unsigned char) 12;	rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,			       SCSI_IOCTL_SEND_COMMAND, buf);	if (rc != 0) {	    printk(KERN_WARNING "sr_photocd: ioctl error (TOSHIBA #2): 0x%x\n",rc);	    break;	}#ifdef DEBUG	printk(KERN_DEBUG "sr_photocd: get_density: 0x%x\n",rec[4]);#endif		/* ...and only if necessary a set_density */	if ((rec[4] != 0x81 && is_xa) || (rec[4] != 0 && !is_xa)) {#ifdef DEBUG	    printk(KERN_DEBUG "sr_photocd: doing set_density\n");#endif	    memset(buf,0,40);	    *((unsigned int*)buf)   = (unsigned int) 12;  /* send 12 bytes */	    *((unsigned int*)buf+1) = (unsigned int) 0;	    cmd[0]                  = (unsigned char) MODE_SELECT;	    cmd[1]                  = (unsigned char) (1 << 4);	    cmd[4]                  = (unsigned char) 12;            send = &cmd[6]; 		/* this is a 6-Byte command    */            send[ 3]                = (unsigned char) 0x08; /* data for cmd */            /* density 0x81 for XA, 0 else */            send[ 4]                = (is_xa) ?                                     (unsigned char) 0x81 : (unsigned char) 0;              send[10]                = (unsigned char) 0x08;	    rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,				   SCSI_IOCTL_SEND_COMMAND, buf);	    if (rc != 0) {		printk(KERN_WARNING "sr_photocd: ioctl error (TOSHIBA #3): 0x%x\n",rc);	    }	    /* The set_density command may have changed the             * sector size or capacity. */	    scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size = 1;	}	break;    case SCSI_MAN_SONY: /* Thomas QUINOT <thomas@melchior.cuivre.fdn.fr> */    case SCSI_MAN_PIONEER:    case SCSI_MAN_UNKNOWN:#ifdef DEBUG	printk(KERN_DEBUG "sr_photocd: use SONY/PIONEER code\n");#endif	get_sectorsize(MINOR(inode->i_rdev));	/* spinup (avoid timeout) */	memset(buf,0,40);	*((unsigned int*)buf)   = 0x0;   /* we send nothing...     */	*((unsigned int*)buf+1) = 0x0c;  /* and receive 0x0c bytes */	cmd[0] = READ_TOC;	cmd[8] = 0x0c;	cmd[9] = 0x40;	rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,			       SCSI_IOCTL_SEND_COMMAND, buf);		if (rc != 0) {            if (rc != 0x28000002) /* drop "not ready" */                printk(KERN_WARNING "sr_photocd: ioctl error (SONY/PIONEER): 0x%x\n",rc);	    break;	}	if ((rec[0] << 8) + rec[1] < 0x0a) {	    printk(KERN_INFO "sr_photocd: (SONY/PIONEER) Hmm, seems the CDROM doesn't support multisession CD's\n");	    no_multi = 1;	    break;	}	sector = rec[11] + (rec[10] << 8) + (rec[9] << 16) + (rec[8] << 24);	is_xa = !!sector;#ifdef DEBUG	if (sector)	    printk (KERN_DEBUG "sr_photocd: multisession CD detected. start: %lu\n",sector);#endif	break;		    case SCSI_MAN_NEC_OLDCDR:    default:	sector = 0;	no_multi = 1;	break; }        scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = sector;    if (is_xa)	scsi_CDs[MINOR(inode->i_rdev)].xa_flags |= 0x01;    else	scsi_CDs[MINOR(inode->i_rdev)].xa_flags &= ~0x01;    if (no_multi)	scsi_CDs[MINOR(inode->i_rdev)].xa_flags |= 0x02;    return;}static int sr_open(struct inode * inode, struct file * filp){    if(MINOR(inode->i_rdev) >= sr_template.nr_dev ||        !scsi_CDs[MINOR(inode->i_rdev)].device) return -ENXIO;   /* No such device */    if (filp->f_mode & 2)  	return -EROFS;    if(sr_template.usage_count) (*sr_template.usage_count)++;    sr_ioctl(inode,filp,CDROMCLOSETRAY,0);    check_disk_change(inode->i_rdev);        if(!scsi_CDs[MINOR(inode->i_rdev)].device->access_count++)	sr_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);    if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)	(*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)++;        sr_photocd(inode);        /* If this device did not have media in the drive at boot time, then     * we would have been unable to get the sector size.  Check to see if     * this is the case, and try again.     */    if(scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size)	get_sectorsize(MINOR(inode->i_rdev));    return 0;}/* * do_sr_request() is the request handler function for the sr driver. * Its function in life is to take block device requests, and * translate them to SCSI commands.   */static void do_sr_request (void){    Scsi_Cmnd * SCpnt = NULL;    struct request * req = NULL;    Scsi_Device * SDev;    unsigned long flags;    int flag = 0;        while (1==1){	save_flags(flags);	cli();	if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) {	    restore_flags(flags);	    return;	};		INIT_SCSI_REQUEST; 	SDev = scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device;		/*	 * I am not sure where the best place to do this is.  We need	 * to hook in a place where we are likely to come if in user	 * space.	 */	if( SDev->was_reset )	{ 	    /* 	     * We need to relock the door, but we might 	     * be in an interrupt handler.  Only do this 	     * from user space, since we do not want to 	     * sleep from an interrupt. 	     */ 	    if( SDev->removable && !intr_count ) 	    {		scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0); 	    } 	    SDev->was_reset = 0;	}		if (flag++ == 0)	    SCpnt = allocate_device(&CURRENT,				    scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0); 	else SCpnt = NULL;	restore_flags(flags);		/* This is a performance enhancement.  We dig down into the request list and	 * try to find a queueable request (i.e. device not busy, and host able to	 * accept another command.  If we find one, then we queue it. This can	 * make a big difference on systems with more than one disk drive.  We want	 * to have the interrupts off when monkeying with the request list, because	 * otherwise the kernel might try to slip in a request in between somewhere. */		if (!SCpnt && sr_template.nr_dev > 1){	    struct request *req1;	    req1 = NULL;	    save_flags(flags);	    cli();	    req = CURRENT;	    while(req){		SCpnt = request_queueable(req,					  scsi_CDs[DEVICE_NR(req->rq_dev)].device);		if(SCpnt) break;		req1 = req;		req = req->next;	    };	    if (SCpnt && req->rq_status == RQ_INACTIVE) {		if (req == CURRENT) 		    CURRENT = CURRENT->next;		else		    req1->next = req->next;	    };	    restore_flags(flags);	};		if (!SCpnt)	    return; /* Could not find anything to do */		wake_up(&wait_for_request);	/* Queue command */	requeue_sr_request(SCpnt);    };  /* While */}    void requeue_sr_request (Scsi_Cmnd * SCpnt){	unsigned int dev, block, realcount;	unsigned char cmd[10], *buffer, tries;	int this_count, start, end_rec;    	tries = 2;     repeat:	if(!SCpnt || SCpnt->request.rq_status == RQ_INACTIVE) {		do_sr_request();		return;	}    	dev =  MINOR(SCpnt->request.rq_dev);	block = SCpnt->request.sector;		buffer = NULL;	this_count = 0;    	if (dev >= sr_template.nr_dev) {		/* printk("CD-ROM request error: invalid device.\n");			*/		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);		tries = 2;		goto repeat;	}    	if (!scsi_CDs[dev].use) {		/* printk("CD-ROM request error: device marked not in use.\n");		*/		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);		tries = 2;		goto repeat;	}    	if (scsi_CDs[dev].device->changed) {	/* 	 * quietly refuse to do anything to a changed disc 	 * until the changed bit has been reset	 */		/* printk("CD-ROM has been changed.  Prohibiting further I/O.\n");	*/		SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);		tries = 2;		goto repeat;	}		switch (SCpnt->request.cmd)    {    case WRITE: 			SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);	goto repeat;	break;    case READ : 	cmd[0] = READ_6;	break;    default : 	panic ("Unknown sr command %d\n", SCpnt->request.cmd);    }		cmd[1] = (SCpnt->lun << 5) & 0xe0;        /*     * Now do the grungy work of figuring out which sectors we need, and     * where in memory we are going to put them.     *      * The variables we need are:     *      * this_count= number of 512 byte sectors being read      * block     = starting cdrom sector to read.     * realcount = # of cdrom sectors to read     *      * The major difference between a scsi disk and a scsi cdrom     * is that we will always use scatter-gather if we can, because we can     * work around the fact that the buffer cache has a block size of 1024,     * and we have 2048 byte sectors.  This code should work for buffers that     * are any multiple of 512 bytes long.     */    	SCpnt->use_sg = 0;    	if (SCpnt->host->sg_tablesize > 0 &&	    (!need_isa_buffer ||	 dma_free_sectors >= 10)) {	struct buffer_head * bh;	struct scatterlist * sgpnt;	int count, this_count_max;	bh = SCpnt->request.bh;	this_count = 0;	count = 0;	this_count_max = (scsi_CDs[dev].ten ? 0xffff : 0xff) << 4;	/* Calculate how many links we can use.  First see if we need	 * a padding record at the start */	this_count = SCpnt->request.sector % 4;	if(this_count) count++;	while(bh && count < SCpnt->host->sg_tablesize) {	    if ((this_count + (bh->b_size >> 9)) > this_count_max) break;	    this_count += (bh->b_size >> 9);	    count++;	    bh = bh->b_reqnext;	};	/* Fix up in case of an odd record at the end */	end_rec = 0;	if(this_count % 4) {	    if (count < SCpnt->host->sg_tablesize) {		count++;		end_rec = (4 - (this_count % 4)) << 9;		this_count += 4 - (this_count % 4);	    } else {		count--;		this_count -= (this_count % 4);	    };	};	SCpnt->use_sg = count;  /* Number of chains */	/* scsi_malloc can only allocate in chunks of 512 bytes */	count  = (SCpnt->use_sg * sizeof(struct scatterlist) + 511) & ~511;	SCpnt->sglist_len = count;	sgpnt = (struct scatterlist * ) scsi_malloc(count);	if (!sgpnt) {	    printk("Warning - running *really* short on DMA buffers\n");	    SCpnt->use_sg = 0;  /* No memory left - bail out */	} else {	    buffer = (unsigned char *) sgpnt;	    count = 0;	    bh = SCpnt->request.bh;	    if(SCpnt->request.sector % 4) {		sgpnt[count].length = (SCpnt->request.sector % 4) << 9;		sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);		if(!sgpnt[count].address) panic("SCSI DMA pool exhausted.");		sgpnt[count].alt_address = sgpnt[count].address; /* Flag to delete								    if needed */		count++;	    };	    for(bh = SCpnt->request.bh; count < SCpnt->use_sg; 		count++, bh = bh->b_reqnext) {		if (bh) { /* Need a placeholder at the end of the record? */		    sgpnt[count].address = bh->b_data;		    sgpnt[count].length = bh->b_size;		    sgpnt[count].alt_address = NULL;		} else {		    sgpnt[count].address = (char *) scsi_malloc(end_rec);		    if(!sgpnt[count].address) panic("SCSI DMA pool exhausted.");		    sgpnt[count].length = end_rec;		    sgpnt[count].alt_address = sgpnt[count].address;		    if (count+1 != SCpnt->use_sg) panic("Bad sr request list");		    break;

⌨️ 快捷键说明

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