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

📄 sr.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 2 页
字号:
		return ret;		scsi_cd_put(cd);	return 0;}static int sr_block_ioctl(struct inode *inode, struct file *file, unsigned cmd,			  unsigned long arg){	struct scsi_cd *cd = scsi_cd(inode->i_bdev->bd_disk);	struct scsi_device *sdev = cd->device;        /*         * Send SCSI addressing ioctls directly to mid level, send other         * ioctls to cdrom/block level.         */        switch (cmd) {                case SCSI_IOCTL_GET_IDLUN:                case SCSI_IOCTL_GET_BUS_NUMBER:                        return scsi_ioctl(sdev, cmd, (void __user *)arg);	}	return cdrom_ioctl(file, &cd->cdi, inode, cmd, arg);}static int sr_block_media_changed(struct gendisk *disk){	struct scsi_cd *cd = scsi_cd(disk);	return cdrom_media_changed(&cd->cdi);}struct block_device_operations sr_bdops ={	.owner		= THIS_MODULE,	.open		= sr_block_open,	.release	= sr_block_release,	.ioctl		= sr_block_ioctl,	.media_changed	= sr_block_media_changed,};static int sr_open(struct cdrom_device_info *cdi, int purpose){	struct scsi_cd *cd = cdi->handle;	struct scsi_device *sdev = cd->device;	int retval;	/*	 * If the device is in error recovery, wait until it is done.	 * If the device is offline, then disallow any access to it.	 */	retval = -ENXIO;	if (!scsi_block_when_processing_errors(sdev))		goto error_out;	/*	 * 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 (cd->needs_sector_size)		get_sectorsize(cd);	return 0;error_out:	scsi_cd_put(cd);	return retval;	}static void sr_release(struct cdrom_device_info *cdi){	struct scsi_cd *cd = cdi->handle;	if (cd->device->sector_size > 2048)		sr_set_blocklength(cd, 2048);}static int sr_probe(struct device *dev){	struct scsi_device *sdev = to_scsi_device(dev);	struct gendisk *disk;	struct scsi_cd *cd;	int minor, error;	error = -ENODEV;	if (sdev->type != TYPE_ROM && sdev->type != TYPE_WORM)		goto fail;	error = -ENOMEM;	cd = kmalloc(sizeof(*cd), GFP_KERNEL);	if (!cd)		goto fail;	memset(cd, 0, sizeof(*cd));	kref_init(&cd->kref);	disk = alloc_disk(1);	if (!disk)		goto fail_free;	spin_lock(&sr_index_lock);	minor = find_first_zero_bit(sr_index_bits, SR_DISKS);	if (minor == SR_DISKS) {		spin_unlock(&sr_index_lock);		error = -EBUSY;		goto fail_put;	}	__set_bit(minor, sr_index_bits);	spin_unlock(&sr_index_lock);	disk->major = SCSI_CDROM_MAJOR;	disk->first_minor = minor;	sprintf(disk->disk_name, "sr%d", minor);	disk->fops = &sr_bdops;	disk->flags = GENHD_FL_CD;	cd->device = sdev;	cd->disk = disk;	cd->driver = &sr_template;	cd->disk = disk;	cd->capacity = 0x1fffff;	cd->needs_sector_size = 1;	cd->device->changed = 1;	/* force recheck CD type */	cd->use = 1;	cd->readcd_known = 0;	cd->readcd_cdda = 0;	cd->cdi.ops = &sr_dops;	cd->cdi.handle = cd;	cd->cdi.mask = 0;	cd->cdi.capacity = 1;	sprintf(cd->cdi.name, "sr%d", minor);	sdev->sector_size = 2048;	/* A guess, just in case */	/* FIXME: need to handle a get_capabilities failure properly ?? */	get_capabilities(cd);	sr_vendor_init(cd);	snprintf(disk->devfs_name, sizeof(disk->devfs_name),			"%s/cd", sdev->devfs_name);	disk->driverfs_dev = &sdev->sdev_gendev;	set_capacity(disk, cd->capacity);	disk->private_data = &cd->driver;	disk->queue = sdev->request_queue;	cd->cdi.disk = disk;	if (register_cdrom(&cd->cdi))		goto fail_put;	dev_set_drvdata(dev, cd);	disk->flags |= GENHD_FL_REMOVABLE;	add_disk(disk);	printk(KERN_DEBUG	    "Attached scsi CD-ROM %s at scsi%d, channel %d, id %d, lun %d\n",	    cd->cdi.name, sdev->host->host_no, sdev->channel,	    sdev->id, sdev->lun);	return 0;fail_put:	put_disk(disk);fail_free:	kfree(cd);fail:	return error;}static void get_sectorsize(struct scsi_cd *cd){	unsigned char cmd[10];	unsigned char *buffer;	int the_result, retries = 3;	int sector_size;	struct scsi_request *SRpnt = NULL;	request_queue_t *queue;	buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);	if (!buffer)		goto Enomem;	SRpnt = scsi_allocate_request(cd->device, GFP_KERNEL);	if (!SRpnt)		goto Enomem;	do {		cmd[0] = READ_CAPACITY;		memset((void *) &cmd[1], 0, 9);		/* Mark as really busy */		SRpnt->sr_request->rq_status = RQ_SCSI_BUSY;		SRpnt->sr_cmd_len = 0;		memset(buffer, 0, 8);		/* Do the command and wait.. */		SRpnt->sr_data_direction = DMA_FROM_DEVICE;		scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,			      8, SR_TIMEOUT, MAX_RETRIES);		the_result = SRpnt->sr_result;		retries--;	} while (the_result && retries);	scsi_release_request(SRpnt);	SRpnt = NULL;	if (the_result) {		cd->capacity = 0x1fffff;		sector_size = 2048;	/* A guess, just in case */		cd->needs_sector_size = 1;	} else {#if 0		if (cdrom_get_last_written(&cd->cdi,					   &cd->capacity))#endif			cd->capacity = 1 + ((buffer[0] << 24) |						    (buffer[1] << 16) |						    (buffer[2] << 8) |						    buffer[3]);		sector_size = (buffer[4] << 24) |		    (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];		switch (sector_size) {			/*			 * HP 4020i CD-Recorder reports 2340 byte sectors			 * Philips CD-Writers report 2352 byte sectors			 *			 * Use 2k sectors for them..			 */		case 0:		case 2340:		case 2352:			sector_size = 2048;			/* fall through */		case 2048:			cd->capacity *= 4;			/* fall through */		case 512:			break;		default:			printk("%s: unsupported sector size %d.\n",			       cd->cdi.name, sector_size);			cd->capacity = 0;			cd->needs_sector_size = 1;		}		cd->device->sector_size = sector_size;		/*		 * Add this so that we have the ability to correctly gauge		 * what the device is capable of.		 */		cd->needs_sector_size = 0;		set_capacity(cd->disk, cd->capacity);	}	queue = cd->device->request_queue;	blk_queue_hardsect_size(queue, sector_size);out:	kfree(buffer);	return;Enomem:	cd->capacity = 0x1fffff;	sector_size = 2048;	/* A guess, just in case */	cd->needs_sector_size = 1;	if (SRpnt)		scsi_release_request(SRpnt);	goto out;}static void get_capabilities(struct scsi_cd *cd){	unsigned char *buffer;	struct scsi_mode_data data;	struct scsi_request *SRpnt;	unsigned char cmd[MAX_COMMAND_SIZE];	unsigned int the_result;	int retries, rc, n;	static char *loadmech[] =	{		"caddy",		"tray",		"pop-up",		"",		"changer",		"cartridge changer",		"",		""	};	/* allocate a request for the TEST_UNIT_READY */	SRpnt = scsi_allocate_request(cd->device, GFP_KERNEL);	if (!SRpnt) {		printk(KERN_WARNING "(get_capabilities:) Request allocation "		       "failure.\n");		return;	}	/* allocate transfer buffer */	buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);	if (!buffer) {		printk(KERN_ERR "sr: out of memory.\n");		scsi_release_request(SRpnt);		return;	}	/* issue TEST_UNIT_READY until the initial startup UNIT_ATTENTION	 * conditions are gone, or a timeout happens	 */	retries = 0;	do {		memset((void *)cmd, 0, MAX_COMMAND_SIZE);		cmd[0] = TEST_UNIT_READY;		SRpnt->sr_cmd_len = 0;		SRpnt->sr_sense_buffer[0] = 0;		SRpnt->sr_sense_buffer[2] = 0;		SRpnt->sr_data_direction = DMA_NONE;		scsi_wait_req (SRpnt, (void *) cmd, buffer,			       0, SR_TIMEOUT, MAX_RETRIES);		the_result = SRpnt->sr_result;		retries++;	} while (retries < 5 && 		 (!scsi_status_is_good(the_result) ||		  ((driver_byte(the_result) & DRIVER_SENSE) &&		   SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION)));	/* ask for mode page 0x2a */	rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128,			     SR_TIMEOUT, 3, &data);	if (!scsi_status_is_good(rc)) {		/* failed, drive doesn't have capabilities mode page */		cd->cdi.speed = 1;		cd->cdi.mask |= (CDC_CD_R | CDC_CD_RW | CDC_DVD_R |					 CDC_DVD | CDC_DVD_RAM |					 CDC_SELECT_DISC | CDC_SELECT_SPEED);		scsi_release_request(SRpnt);		kfree(buffer);		printk("%s: scsi-1 drive\n", cd->cdi.name);		return;	}	n = data.header_length + data.block_descriptor_length;	cd->cdi.speed = ((buffer[n + 8] << 8) + buffer[n + 9]) / 176;	cd->readcd_known = 1;	cd->readcd_cdda = buffer[n + 5] & 0x01;	/* print some capability bits */	printk("%s: scsi3-mmc drive: %dx/%dx %s%s%s%s%s%s\n", cd->cdi.name,	       ((buffer[n + 14] << 8) + buffer[n + 15]) / 176,	       cd->cdi.speed,	       buffer[n + 3] & 0x01 ? "writer " : "", /* CD Writer */	       buffer[n + 3] & 0x20 ? "dvd-ram " : "",	       buffer[n + 2] & 0x02 ? "cd/rw " : "", /* can read rewriteable */	       buffer[n + 4] & 0x20 ? "xa/form2 " : "",	/* can read xa/from2 */	       buffer[n + 5] & 0x01 ? "cdda " : "", /* can read audio data */	       loadmech[buffer[n + 6] >> 5]);	if ((buffer[n + 6] >> 5) == 0)		/* caddy drives can't close tray... */		cd->cdi.mask |= CDC_CLOSE_TRAY;	if ((buffer[n + 2] & 0x8) == 0)		/* not a DVD drive */		cd->cdi.mask |= CDC_DVD;	if ((buffer[n + 3] & 0x20) == 0) 		/* can't write DVD-RAM media */		cd->cdi.mask |= CDC_DVD_RAM;	if ((buffer[n + 3] & 0x10) == 0)		/* can't write DVD-R media */		cd->cdi.mask |= CDC_DVD_R;	if ((buffer[n + 3] & 0x2) == 0)		/* can't write CD-RW media */		cd->cdi.mask |= CDC_CD_RW;	if ((buffer[n + 3] & 0x1) == 0)		/* can't write CD-R media */		cd->cdi.mask |= CDC_CD_R;	if ((buffer[n + 6] & 0x8) == 0)		/* can't eject */		cd->cdi.mask |= CDC_OPEN_TRAY;	if ((buffer[n + 6] >> 5) == mechtype_individual_changer ||	    (buffer[n + 6] >> 5) == mechtype_cartridge_changer)		cd->cdi.capacity =		    cdrom_number_of_slots(&cd->cdi);	if (cd->cdi.capacity <= 1)		/* not a changer */		cd->cdi.mask |= CDC_SELECT_DISC;	/*else    I don't think it can close its tray		cd->cdi.mask |= CDC_CLOSE_TRAY; */	/*	 * if DVD-RAM of MRW-W, we are randomly writeable	 */	if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM)) !=			(CDC_DVD_RAM | CDC_MRW_W | CDC_RAM)) {		cd->device->writeable = 1;	}	scsi_release_request(SRpnt);	kfree(buffer);}/* * sr_packet() is the entry point for the generic commands generated * by the Uniform CD-ROM layer.  */static int sr_packet(struct cdrom_device_info *cdi,		struct packet_command *cgc){	if (cgc->timeout <= 0)		cgc->timeout = IOCTL_TIMEOUT;	sr_do_ioctl(cdi->handle, cgc);	return cgc->stat;}/** *	sr_kref_release - Called to free the scsi_cd structure *	@kref: pointer to embedded kref * *	sr_ref_sem must be held entering this routine.  Because it is *	called on last put, you should always use the scsi_cd_get() *	scsi_cd_put() helpers which manipulate the semaphore directly *	and never do a direct kref_put(). **/static void sr_kref_release(struct kref *kref){	struct scsi_cd *cd = container_of(kref, struct scsi_cd, kref);	struct gendisk *disk = cd->disk;	spin_lock(&sr_index_lock);	clear_bit(disk->first_minor, sr_index_bits);	spin_unlock(&sr_index_lock);	unregister_cdrom(&cd->cdi);	disk->private_data = NULL;	put_disk(disk);	kfree(cd);}static int sr_remove(struct device *dev){	struct scsi_cd *cd = dev_get_drvdata(dev);	del_gendisk(cd->disk);	down(&sr_ref_sem);	kref_put(&cd->kref, sr_kref_release);	up(&sr_ref_sem);	return 0;}static int __init init_sr(void){	int rc;	rc = register_blkdev(SCSI_CDROM_MAJOR, "sr");	if (rc)		return rc;	return scsi_register_driver(&sr_template.gendrv);}static void __exit exit_sr(void){	scsi_unregister_driver(&sr_template.gendrv);	unregister_blkdev(SCSI_CDROM_MAJOR, "sr");}module_init(init_sr);module_exit(exit_sr);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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