cdrom.c

来自「linux 内核源代码」· C语言 代码 · 共 2,396 行 · 第 1/5 页

C
2,396
字号
int cdrom_get_media_event(struct cdrom_device_info *cdi,			  struct media_event_desc *med){	struct packet_command cgc;	unsigned char buffer[8];	struct event_header *eh = (struct event_header *) buffer;	init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);	cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION;	cgc.cmd[1] = 1;		/* IMMED */	cgc.cmd[4] = 1 << 4;	/* media event */	cgc.cmd[8] = sizeof(buffer);	cgc.quiet = 1;	if (cdi->ops->generic_packet(cdi, &cgc))		return 1;	if (be16_to_cpu(eh->data_len) < sizeof(*med))		return 1;	if (eh->nea || eh->notification_class != 0x4)		return 1;	memcpy(med, &buffer[sizeof(*eh)], sizeof(*med));	return 0;}/* * the first prototypes used 0x2c as the page code for the mrw mode page, * subsequently this was changed to 0x03. probe the one used by this drive */static int cdrom_mrw_probe_pc(struct cdrom_device_info *cdi){	struct packet_command cgc;	char buffer[16];	init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);	cgc.timeout = HZ;	cgc.quiet = 1;	if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC, 0)) {		cdi->mrw_mode_page = MRW_MODE_PC;		return 0;	} else if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC_PRE1, 0)) {		cdi->mrw_mode_page = MRW_MODE_PC_PRE1;		return 0;	}	return 1;}static int cdrom_is_mrw(struct cdrom_device_info *cdi, int *write){	struct packet_command cgc;	struct mrw_feature_desc *mfd;	unsigned char buffer[16];	int ret;	*write = 0;	init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);	cgc.cmd[0] = GPCMD_GET_CONFIGURATION;	cgc.cmd[3] = CDF_MRW;	cgc.cmd[8] = sizeof(buffer);	cgc.quiet = 1;	if ((ret = cdi->ops->generic_packet(cdi, &cgc)))		return ret;	mfd = (struct mrw_feature_desc *)&buffer[sizeof(struct feature_header)];	if (be16_to_cpu(mfd->feature_code) != CDF_MRW)		return 1;	*write = mfd->write;	if ((ret = cdrom_mrw_probe_pc(cdi))) {		*write = 0;		return ret;	}	return 0;}static int cdrom_mrw_bgformat(struct cdrom_device_info *cdi, int cont){	struct packet_command cgc;	unsigned char buffer[12];	int ret;	printk(KERN_INFO "cdrom: %sstarting format\n", cont ? "Re" : "");	/*	 * FmtData bit set (bit 4), format type is 1	 */	init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_WRITE);	cgc.cmd[0] = GPCMD_FORMAT_UNIT;	cgc.cmd[1] = (1 << 4) | 1;	cgc.timeout = 5 * 60 * HZ;	/*	 * 4 byte format list header, 8 byte format list descriptor	 */	buffer[1] = 1 << 1;	buffer[3] = 8;	/*	 * nr_blocks field	 */	buffer[4] = 0xff;	buffer[5] = 0xff;	buffer[6] = 0xff;	buffer[7] = 0xff;	buffer[8] = 0x24 << 2;	buffer[11] = cont;	ret = cdi->ops->generic_packet(cdi, &cgc);	if (ret)		printk(KERN_INFO "cdrom: bgformat failed\n");	return ret;}static int cdrom_mrw_bgformat_susp(struct cdrom_device_info *cdi, int immed){	struct packet_command cgc;	init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);	cgc.cmd[0] = GPCMD_CLOSE_TRACK;	/*	 * Session = 1, Track = 0	 */	cgc.cmd[1] = !!immed;	cgc.cmd[2] = 1 << 1;	cgc.timeout = 5 * 60 * HZ;	return cdi->ops->generic_packet(cdi, &cgc);}static int cdrom_flush_cache(struct cdrom_device_info *cdi){	struct packet_command cgc;	init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);	cgc.cmd[0] = GPCMD_FLUSH_CACHE;	cgc.timeout = 5 * 60 * HZ;	return cdi->ops->generic_packet(cdi, &cgc);}static int cdrom_mrw_exit(struct cdrom_device_info *cdi){	disc_information di;	int ret;	ret = cdrom_get_disc_info(cdi, &di);	if (ret < 0 || ret < (int)offsetof(typeof(di),disc_type))		return 1;	ret = 0;	if (di.mrw_status == CDM_MRW_BGFORMAT_ACTIVE) {		printk(KERN_INFO "cdrom: issuing MRW back ground "				"format suspend\n");		ret = cdrom_mrw_bgformat_susp(cdi, 0);	}	if (!ret && cdi->media_written)		ret = cdrom_flush_cache(cdi);	return ret;}static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space){	struct packet_command cgc;	struct mode_page_header *mph;	char buffer[16];	int ret, offset, size;	init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);	cgc.buffer = buffer;	cgc.buflen = sizeof(buffer);	if ((ret = cdrom_mode_sense(cdi, &cgc, cdi->mrw_mode_page, 0)))		return ret;	mph = (struct mode_page_header *) buffer;	offset = be16_to_cpu(mph->desc_length);	size = be16_to_cpu(mph->mode_data_length) + 2;	buffer[offset + 3] = space;	cgc.buflen = size;	if ((ret = cdrom_mode_select(cdi, &cgc)))		return ret;	printk(KERN_INFO "cdrom: %s: mrw address space %s selected\n", cdi->name, mrw_address_space[space]);	return 0;}static int cdrom_get_random_writable(struct cdrom_device_info *cdi,			      struct rwrt_feature_desc *rfd){	struct packet_command cgc;	char buffer[24];	int ret;	init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);	cgc.cmd[0] = GPCMD_GET_CONFIGURATION;	/* often 0x46 */	cgc.cmd[3] = CDF_RWRT;			/* often 0x0020 */	cgc.cmd[8] = sizeof(buffer);		/* often 0x18 */	cgc.quiet = 1;	if ((ret = cdi->ops->generic_packet(cdi, &cgc)))		return ret;	memcpy(rfd, &buffer[sizeof(struct feature_header)], sizeof (*rfd));	return 0;}static int cdrom_has_defect_mgt(struct cdrom_device_info *cdi){	struct packet_command cgc;	char buffer[16];	__be16 *feature_code;	int ret;	init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);	cgc.cmd[0] = GPCMD_GET_CONFIGURATION;	cgc.cmd[3] = CDF_HWDM;	cgc.cmd[8] = sizeof(buffer);	cgc.quiet = 1;	if ((ret = cdi->ops->generic_packet(cdi, &cgc)))		return ret;	feature_code = (__be16 *) &buffer[sizeof(struct feature_header)];	if (be16_to_cpu(*feature_code) == CDF_HWDM)		return 0;	return 1;}static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write){	struct rwrt_feature_desc rfd;	int ret;	*write = 0;	if ((ret = cdrom_get_random_writable(cdi, &rfd)))		return ret;	if (CDF_RWRT == be16_to_cpu(rfd.feature_code))		*write = 1;	return 0;}static int cdrom_media_erasable(struct cdrom_device_info *cdi){	disc_information di;	int ret;	ret = cdrom_get_disc_info(cdi, &di);	if (ret < 0 || ret < offsetof(typeof(di), n_first_track))		return -1;	return di.erasable;}/* * FIXME: check RO bit */static int cdrom_dvdram_open_write(struct cdrom_device_info *cdi){	int ret = cdrom_media_erasable(cdi);	/*	 * allow writable open if media info read worked and media is	 * erasable, _or_ if it fails since not all drives support it	 */	if (!ret)		return 1;	return 0;}static int cdrom_mrw_open_write(struct cdrom_device_info *cdi){	disc_information di;	int ret;	/*	 * always reset to DMA lba space on open	 */	if (cdrom_mrw_set_lba_space(cdi, MRW_LBA_DMA)) {		printk(KERN_ERR "cdrom: failed setting lba address space\n");		return 1;	}	ret = cdrom_get_disc_info(cdi, &di);	if (ret < 0 || ret < offsetof(typeof(di),disc_type))		return 1;	if (!di.erasable)		return 1;	/*	 * mrw_status	 * 0	-	not MRW formatted	 * 1	-	MRW bgformat started, but not running or complete	 * 2	-	MRW bgformat in progress	 * 3	-	MRW formatting complete	 */	ret = 0;	printk(KERN_INFO "cdrom open: mrw_status '%s'\n",			mrw_format_status[di.mrw_status]);	if (!di.mrw_status)		ret = 1;	else if (di.mrw_status == CDM_MRW_BGFORMAT_INACTIVE &&			mrw_format_restart)		ret = cdrom_mrw_bgformat(cdi, 1);	return ret;}static int mo_open_write(struct cdrom_device_info *cdi){	struct packet_command cgc;	char buffer[255];	int ret;	init_cdrom_command(&cgc, &buffer, 4, CGC_DATA_READ);	cgc.quiet = 1;	/*	 * obtain write protect information as per	 * drivers/scsi/sd.c:sd_read_write_protect_flag	 */	ret = cdrom_mode_sense(cdi, &cgc, GPMODE_ALL_PAGES, 0);	if (ret)		ret = cdrom_mode_sense(cdi, &cgc, GPMODE_VENDOR_PAGE, 0);	if (ret) {		cgc.buflen = 255;		ret = cdrom_mode_sense(cdi, &cgc, GPMODE_ALL_PAGES, 0);	}	/* drive gave us no info, let the user go ahead */	if (ret)		return 0;	return buffer[3] & 0x80;}static int cdrom_ram_open_write(struct cdrom_device_info *cdi){	struct rwrt_feature_desc rfd;	int ret;	if ((ret = cdrom_has_defect_mgt(cdi)))		return ret;	if ((ret = cdrom_get_random_writable(cdi, &rfd)))		return ret;	else if (CDF_RWRT == be16_to_cpu(rfd.feature_code))		ret = !rfd.curr;	cdinfo(CD_OPEN, "can open for random write\n");	return ret;}static void cdrom_mmc3_profile(struct cdrom_device_info *cdi){	struct packet_command cgc;	char buffer[32];	int ret, mmc3_profile;	init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);	cgc.cmd[0] = GPCMD_GET_CONFIGURATION;	cgc.cmd[1] = 0;	cgc.cmd[2] = cgc.cmd[3] = 0;		/* Starting Feature Number */	cgc.cmd[8] = sizeof(buffer);		/* Allocation Length */	cgc.quiet = 1;	if ((ret = cdi->ops->generic_packet(cdi, &cgc)))		mmc3_profile = 0xffff;	else		mmc3_profile = (buffer[6] << 8) | buffer[7];	cdi->mmc3_profile = mmc3_profile;}static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi){	switch (cdi->mmc3_profile) {	case 0x12:	/* DVD-RAM	*/	case 0x1A:	/* DVD+RW	*/		return 0;	default:		return 1;	}}/* * returns 0 for ok to open write, non-0 to disallow */static int cdrom_open_write(struct cdrom_device_info *cdi){	int mrw, mrw_write, ram_write;	int ret = 1;	mrw = 0;	if (!cdrom_is_mrw(cdi, &mrw_write))		mrw = 1;	if (CDROM_CAN(CDC_MO_DRIVE))		ram_write = 1;	else		(void) cdrom_is_random_writable(cdi, &ram_write);		if (mrw)		cdi->mask &= ~CDC_MRW;	else		cdi->mask |= CDC_MRW;	if (mrw_write)		cdi->mask &= ~CDC_MRW_W;	else		cdi->mask |= CDC_MRW_W;	if (ram_write)		cdi->mask &= ~CDC_RAM;	else		cdi->mask |= CDC_RAM;	if (CDROM_CAN(CDC_MRW_W))		ret = cdrom_mrw_open_write(cdi);	else if (CDROM_CAN(CDC_DVD_RAM))		ret = cdrom_dvdram_open_write(cdi); 	else if (CDROM_CAN(CDC_RAM) && 		 !CDROM_CAN(CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_MRW|CDC_MO_DRIVE)) 		ret = cdrom_ram_open_write(cdi);	else if (CDROM_CAN(CDC_MO_DRIVE))		ret = mo_open_write(cdi);	else if (!cdrom_is_dvd_rw(cdi))		ret = 0;	return ret;}static void cdrom_dvd_rw_close_write(struct cdrom_device_info *cdi){	struct packet_command cgc;	if (cdi->mmc3_profile != 0x1a) {		cdinfo(CD_CLOSE, "%s: No DVD+RW\n", cdi->name);		return;	}	if (!cdi->media_written) {		cdinfo(CD_CLOSE, "%s: DVD+RW media clean\n", cdi->name);		return;	}	printk(KERN_INFO "cdrom: %s: dirty DVD+RW media, \"finalizing\"\n",	       cdi->name);	init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);

⌨️ 快捷键说明

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