📄 sr.c
字号:
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; void __user *argp = (void __user *)arg; int ret; /* * 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, argp); } ret = cdrom_ioctl(file, &cd->cdi, inode, cmd, arg); if (ret != -ENOSYS) return ret; /* * ENODEV means that we didn't recognise the ioctl, or that we * cannot execute it in the current device state. In either * case fall through to scsi_ioctl, which will return ENDOEV again * if it doesn't recognise the ioctl */ ret = scsi_nonblockable_ioctl(sdev, cmd, argp, NULL); if (ret != -ENODEV) return ret; return scsi_ioctl(sdev, cmd, argp);}static int sr_block_media_changed(struct gendisk *disk){ struct scsi_cd *cd = scsi_cd(disk); return cdrom_media_changed(&cd->cdi);}static 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, /* * No compat_ioctl for now because sr_block_ioctl never * seems to pass arbitary ioctls down to host drivers. */};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; return 0;error_out: 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 = kzalloc(sizeof(*cd), GFP_KERNEL); if (!cd) goto fail; 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->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); blk_queue_prep_rq(sdev->request_queue, sr_prep_fn); sr_vendor_init(cd); 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); sdev_printk(KERN_DEBUG, sdev, "Attached scsi CD-ROM %s\n", cd->cdi.name); 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 request_queue *queue; buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); if (!buffer) goto Enomem; do { cmd[0] = READ_CAPACITY; memset((void *) &cmd[1], 0, 9); memset(buffer, 0, 8); /* Do the command and wait.. */ the_result = scsi_execute_req(cd->device, cmd, DMA_FROM_DEVICE, buffer, 8, NULL, SR_TIMEOUT, MAX_RETRIES); retries--; } while (the_result && retries); if (the_result) { cd->capacity = 0x1fffff; sector_size = 2048; /* A guess, just in case */ } 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->device->sector_size = sector_size; /* * Add this so that we have the ability to correctly gauge * what the device is capable of. */ 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; cd->device->sector_size = 2048; /* A guess, just in case */ goto out;}static void get_capabilities(struct scsi_cd *cd){ unsigned char *buffer; struct scsi_mode_data data; unsigned char cmd[MAX_COMMAND_SIZE]; struct scsi_sense_hdr sshdr; unsigned int the_result; int retries, rc, n; static const char *loadmech[] = { "caddy", "tray", "pop-up", "", "changer", "cartridge changer", "", "" }; /* allocate transfer buffer */ buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); if (!buffer) { printk(KERN_ERR "sr: out of memory.\n"); 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; the_result = scsi_execute_req (cd->device, cmd, DMA_NONE, NULL, 0, &sshdr, SR_TIMEOUT, MAX_RETRIES); retries++; } while (retries < 5 && (!scsi_status_is_good(the_result) || (scsi_sense_valid(&sshdr) && sshdr.sense_key == UNIT_ATTENTION))); /* ask for mode page 0x2a */ rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128, SR_TIMEOUT, 3, &data, NULL); 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 | CDC_MRW | CDC_MRW_W | CDC_RAM); 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, MRW-W or CD-RW, we are randomly writable */ if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) != (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) { cd->device->writeable = 1; } 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_mutex 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); mutex_lock(&sr_ref_mutex); kref_put(&cd->kref, sr_kref_release); mutex_unlock(&sr_ref_mutex); return 0;}static int __init init_sr(void){ int rc; rc = register_blkdev(SCSI_CDROM_MAJOR, "sr"); if (rc) return rc; rc = scsi_register_driver(&sr_template.gendrv); if (rc) unregister_blkdev(SCSI_CDROM_MAJOR, "sr"); return rc;}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 + -