📄 sr.c
字号:
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 + -