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

📄 cdrom.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (CDROM_CAN(CDC_GENERIC_PACKET)) {		ret = mmc_ioctl(cdi, cmd, arg);		if (ret != -ENOTTY) {			return ret;		}	}	/* note: most of the cdinfo() calls are commented out here,	   because they fill up the sys log when CD players poll	   the drive. */	switch (cmd) {	case CDROMSUBCHNL: {		struct cdrom_subchnl q;		u_char requested, back;		if (!CDROM_CAN(CDC_PLAY_AUDIO))			return -ENOSYS;		/* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/ 		IOCTL_IN(arg, struct cdrom_subchnl, q);		requested = q.cdsc_format;		if (!((requested == CDROM_MSF) ||		      (requested == CDROM_LBA)))			return -EINVAL;		q.cdsc_format = CDROM_MSF;		if ((ret=cdo->audio_ioctl(cdi, cmd, &q)))			return ret;		back = q.cdsc_format; /* local copy */		sanitize_format(&q.cdsc_absaddr, &back, requested);		sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested);		IOCTL_OUT(arg, struct cdrom_subchnl, q);		/* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ 		return 0;		}	case CDROMREADTOCHDR: {		struct cdrom_tochdr header;		if (!CDROM_CAN(CDC_PLAY_AUDIO))			return -ENOSYS;		/* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */ 		IOCTL_IN(arg, struct cdrom_tochdr, header);		if ((ret=cdo->audio_ioctl(cdi, cmd, &header)))			return ret;		IOCTL_OUT(arg, struct cdrom_tochdr, header);		/* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */ 		return 0;		}	case CDROMREADTOCENTRY: {		struct cdrom_tocentry entry;		u_char requested_format;		if (!CDROM_CAN(CDC_PLAY_AUDIO))			return -ENOSYS;		/* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */ 		IOCTL_IN(arg, struct cdrom_tocentry, entry);		requested_format = entry.cdte_format;		if (!((requested_format == CDROM_MSF) || 			(requested_format == CDROM_LBA)))				return -EINVAL;		/* make interface to low-level uniform */		entry.cdte_format = CDROM_MSF;		if ((ret=cdo->audio_ioctl(cdi, cmd, &entry)))			return ret;		sanitize_format(&entry.cdte_addr,		&entry.cdte_format, requested_format);		IOCTL_OUT(arg, struct cdrom_tocentry, entry);		/* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */ 		return 0;		}	case CDROMPLAYMSF: {		struct cdrom_msf msf;		if (!CDROM_CAN(CDC_PLAY_AUDIO))			return -ENOSYS;		cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); 		IOCTL_IN(arg, struct cdrom_msf, msf);		return cdo->audio_ioctl(cdi, cmd, &msf);		}	case CDROMPLAYTRKIND: {		struct cdrom_ti ti;		if (!CDROM_CAN(CDC_PLAY_AUDIO))			return -ENOSYS;		cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); 		IOCTL_IN(arg, struct cdrom_ti, ti);		CHECKAUDIO;		return cdo->audio_ioctl(cdi, cmd, &ti);		}	case CDROMVOLCTRL: {		struct cdrom_volctrl volume;		if (!CDROM_CAN(CDC_PLAY_AUDIO))			return -ENOSYS;		cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n"); 		IOCTL_IN(arg, struct cdrom_volctrl, volume);		return cdo->audio_ioctl(cdi, cmd, &volume);		}	case CDROMVOLREAD: {		struct cdrom_volctrl volume;		if (!CDROM_CAN(CDC_PLAY_AUDIO))			return -ENOSYS;		cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n"); 		if ((ret=cdo->audio_ioctl(cdi, cmd, &volume)))			return ret;		IOCTL_OUT(arg, struct cdrom_volctrl, volume);		return 0;		}	case CDROMSTART:	case CDROMSTOP:	case CDROMPAUSE:	case CDROMRESUME: {		if (!CDROM_CAN(CDC_PLAY_AUDIO))			return -ENOSYS;		cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n"); 		CHECKAUDIO;		return cdo->audio_ioctl(cdi, cmd, NULL);		}	} /* switch */	/* do the device specific ioctls */	if (CDROM_CAN(CDC_IOCTLS))		return cdo->dev_ioctl(cdi, cmd, arg);		return -ENOSYS;}static inlineint msf_to_lba(char m, char s, char f){	return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET;}/* * Required when we need to use READ_10 to issue other than 2048 block * reads */static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size){	struct cdrom_device_ops *cdo = cdi->ops;	struct cdrom_generic_command cgc;	struct modesel_head mh;	memset(&mh, 0, sizeof(mh));	mh.block_desc_length = 0x08;	mh.block_length_med = (size >> 8) & 0xff;	mh.block_length_lo = size & 0xff;	memset(&cgc, 0, sizeof(cgc));	cgc.cmd[0] = 0x15;	cgc.cmd[1] = 1 << 4;	cgc.cmd[4] = 12;	cgc.buflen = sizeof(mh);	cgc.buffer = (char *) &mh;	cgc.data_direction = CGC_DATA_WRITE;	mh.block_desc_length = 0x08;	mh.block_length_med = (size >> 8) & 0xff;	mh.block_length_lo = size & 0xff;	return cdo->generic_packet(cdi, &cgc);}static int cdrom_do_cmd(struct cdrom_device_info *cdi,			struct cdrom_generic_command *cgc){	struct request_sense *usense, sense;	unsigned char *ubuf;	int ret;	if (cgc->data_direction == CGC_DATA_UNKNOWN)		return -EINVAL;	if (cgc->buflen < 0 || cgc->buflen >= 131072)		return -EINVAL;	if ((ubuf = cgc->buffer)) {		cgc->buffer = kmalloc(cgc->buflen, GFP_KERNEL);		if (cgc->buffer == NULL)			return -ENOMEM;	}	usense = cgc->sense;	cgc->sense = &sense;	if (usense && !access_ok(VERIFY_WRITE, usense, sizeof(*usense)))		return -EFAULT;	if (cgc->data_direction == CGC_DATA_READ) {		if (!access_ok(VERIFY_READ, ubuf, cgc->buflen))			return -EFAULT;	} else if (cgc->data_direction == CGC_DATA_WRITE) {		if (copy_from_user(cgc->buffer, ubuf, cgc->buflen)) {			kfree(cgc->buffer);			return -EFAULT;		}	}	ret = cdi->ops->generic_packet(cdi, cgc);	__copy_to_user(usense, cgc->sense, sizeof(*usense));	if (!ret && cgc->data_direction == CGC_DATA_READ)		__copy_to_user(ubuf, cgc->buffer, cgc->buflen);	kfree(cgc->buffer);	return ret;}static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,		     unsigned long arg){			struct cdrom_device_ops *cdo = cdi->ops;	struct cdrom_generic_command cgc;	kdev_t dev = cdi->dev;	char buffer[32];	int ret = 0;	memset(&cgc, 0, sizeof(cgc));	/* build a unified command and queue it through	   cdo->generic_packet() */	switch (cmd) {	case CDROMREADRAW:	case CDROMREADMODE1:	case CDROMREADMODE2: {		struct cdrom_msf msf;		int blocksize = 0, format = 0, lba;				switch (cmd) {		case CDROMREADRAW:			blocksize = CD_FRAMESIZE_RAW;			break;		case CDROMREADMODE1:			blocksize = CD_FRAMESIZE;			format = 2;			break;		case CDROMREADMODE2:			blocksize = CD_FRAMESIZE_RAW0;			break;		}		IOCTL_IN(arg, struct cdrom_msf, msf);		lba = msf_to_lba(msf.cdmsf_min0,msf.cdmsf_sec0,msf.cdmsf_frame0);		/* FIXME: we need upper bound checking, too!! */		if (lba < 0)			return -EINVAL;		cgc.buffer = (char *) kmalloc(blocksize, GFP_KERNEL);		if (cgc.buffer == NULL)			return -ENOMEM;		cgc.data_direction = CGC_DATA_READ;		ret = cdrom_read_block(cdi, &cgc, lba, 1, format, blocksize);		if (ret) {			/*			 * SCSI-II devices are not required to support			 * READ_CD, so let's try switching block size			 */			/* FIXME: switch back again... */			if ((ret = cdrom_switch_blocksize(cdi, blocksize))) {				kfree(cgc.buffer);				return ret;			}			cgc.sense = NULL;			ret = cdrom_read_cd(cdi, &cgc, lba, blocksize, 1);			ret |= cdrom_switch_blocksize(cdi, blocksize);		}		if (!ret && copy_to_user((char *)arg, cgc.buffer, blocksize))			ret = -EFAULT;		kfree(cgc.buffer);		return ret;		}	case CDROMREADAUDIO: {		struct cdrom_read_audio ra;		int lba;		IOCTL_IN(arg, struct cdrom_read_audio, ra);		if (ra.addr_format == CDROM_MSF)			lba = msf_to_lba(ra.addr.msf.minute,					 ra.addr.msf.second,					 ra.addr.msf.frame);		else if (ra.addr_format == CDROM_LBA)			lba = ra.addr.lba;		else			return -EINVAL;		/* FIXME: we need upper bound checking, too!! */		if (lba < 0 || ra.nframes <= 0)			return -EINVAL;		if ((cgc.buffer = (char *) kmalloc(CD_FRAMESIZE_RAW, GFP_KERNEL)) == NULL)			return -ENOMEM;		if (!access_ok(VERIFY_WRITE, ra.buf, ra.nframes*CD_FRAMESIZE_RAW)) {			kfree(cgc.buffer);			return -EFAULT;		}		cgc.data_direction = CGC_DATA_READ;		while (ra.nframes > 0) {			ret = cdrom_read_block(cdi, &cgc, lba, 1, 1, CD_FRAMESIZE_RAW);			if (ret) break;			__copy_to_user(ra.buf, cgc.buffer, CD_FRAMESIZE_RAW);			ra.buf += CD_FRAMESIZE_RAW;			ra.nframes--;			lba++;		}		kfree(cgc.buffer);		return ret;		}	case CDROMSUBCHNL: {		struct cdrom_subchnl q;		u_char requested, back;		IOCTL_IN(arg, struct cdrom_subchnl, q);		requested = q.cdsc_format;		if (!((requested == CDROM_MSF) ||		      (requested == CDROM_LBA)))			return -EINVAL;		q.cdsc_format = CDROM_MSF;		if ((ret = cdrom_read_subchannel(cdi, &q, 0)))			return ret;		back = q.cdsc_format; /* local copy */		sanitize_format(&q.cdsc_absaddr, &back, requested);		sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested);		IOCTL_OUT(arg, struct cdrom_subchnl, q);		/* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ 		return 0;		}	case CDROMPLAYMSF: {		struct cdrom_msf msf;		cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");		IOCTL_IN(arg, struct cdrom_msf, msf);		cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF;		cgc.cmd[3] = msf.cdmsf_min0;		cgc.cmd[4] = msf.cdmsf_sec0;		cgc.cmd[5] = msf.cdmsf_frame0;		cgc.cmd[6] = msf.cdmsf_min1;		cgc.cmd[7] = msf.cdmsf_sec1;		cgc.cmd[8] = msf.cdmsf_frame1;		cgc.data_direction = CGC_DATA_NONE;		return cdo->generic_packet(cdi, &cgc);		}	case CDROMPLAYBLK: {		struct cdrom_blk blk;		cdinfo(CD_DO_IOCTL, "entering CDROMPLAYBLK\n");		IOCTL_IN(arg, struct cdrom_blk, blk);		cgc.cmd[0] = GPCMD_PLAY_AUDIO_10;		cgc.cmd[2] = (blk.from >> 24) & 0xff;		cgc.cmd[3] = (blk.from >> 16) & 0xff;		cgc.cmd[4] = (blk.from >>  8) & 0xff;		cgc.cmd[5] = blk.from & 0xff;		cgc.cmd[7] = (blk.len >> 8) & 0xff;		cgc.cmd[8] = blk.len & 0xff;		cgc.data_direction = CGC_DATA_NONE;		return cdo->generic_packet(cdi, &cgc);		}	case CDROMVOLCTRL:	case CDROMVOLREAD: {		struct cdrom_volctrl volctrl;		char mask[32];		unsigned short offset;		cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n");		IOCTL_IN(arg, struct cdrom_volctrl, volctrl);		cgc.buffer = buffer;		cgc.buflen = 24;		if ((ret = cdrom_mode_sense(cdi, &cgc, GPMODE_AUDIO_CTL_PAGE, 0)))		    return ret;				/* some drives have longer pages, adjust and reread. */		if (buffer[1] > cgc.buflen) {			cgc.buflen = buffer[1] + 2;			if ((ret = cdrom_mode_sense(cdi, &cgc, 					GPMODE_AUDIO_CTL_PAGE, 0))) 			    return ret;		}				/* get the offset from the length of the page. length		   is measure from byte 2 an on, thus the 14. */		offset = buffer[1] - 14;		/* now we have the current volume settings. if it was only		   a CDROMVOLREAD, return these values */		if (cmd == CDROMVOLREAD) {			volctrl.channel0 = buffer[offset+9];			volctrl.channel1 = buffer[offset+11];			volctrl.channel2 = buffer[offset+13];			volctrl.channel3 = buffer[offset+15];			IOCTL_OUT(arg, struct cdrom_volctrl, volctrl);			return 0;		}				/* get the volume mask */		cgc.buffer = mask;		if ((ret = cdrom_mode_sense(cdi, &cgc, 				GPMODE_AUDIO_CTL_PAGE, 1)))			return ret;		buffer[offset+9] = volctrl.channel0 & mask[offset+9];		buffer[offset+11] = volctrl.channel1 & mask[offset+11];		buffer[offset+13] = volctrl.channel2 & mask[offset+13];		buffer[offset+15] = volctrl.channel3 & mask[offset+15];		/* set volume */		cgc.buffer = buffer;		return cdrom_mode_select(cdi, &cgc);		}	case CDROMSTART:	case CDROMSTOP: {		cdinfo(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n"); 		cgc.cmd[0] = GPCMD_START_STOP_UNIT;		cgc.cmd[1] = 1;		cgc.cmd[4] = (cmd == CDROMSTART) ? 1 : 0;		cgc.data_direction = CGC_DATA_NONE;		return cdo->generic_packet(cdi, &cgc);		}	case CDROMPAUSE:	case CDROMRESUME: {		cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); 		cgc.cmd[0] = GPCMD_PAUSE_RESUME;		cgc.cmd[8] = (cmd == CDROMRESUME) ? 1 : 0;		cgc.data_direction = CGC_DATA_NONE;		return cdo->generic_packet(cdi, &cgc);		}	case DVD_READ_STRUCT: {		dvd_struct *s;		int size = sizeof(dvd_struct);		if (!CDROM_CAN(CDC_DVD))			return -ENOSYS;		if ((s = (dvd_struct *) kmalloc(size, GFP_KERNEL)) == NULL)			return -ENOMEM;		cdinfo(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n"); 		if (copy_from_user(s, (dvd_struct *)arg, size)) {			kfree(s);			return -EFAULT;		}		if ((ret = dvd_read_struct(cdi, s))) {			kfree(s);			return ret;		}		if (copy_to_user((dvd_struct *)arg, s, size))			ret =

⌨️ 快捷键说明

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