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

📄 cdrom.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	if ((buf = (u_char *) kmalloc(size, GFP_KERNEL)) == NULL)		return -ENOMEM;	init_cdrom_command(&cgc, buf, size, CGC_DATA_READ);	cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;	cgc.cmd[7] = s->type;	cgc.cmd[8] = size >> 8;	cgc.cmd[9] = size & 0xff;	if ((ret = cdo->generic_packet(cdi, &cgc))) {		kfree(buf);		return ret;	}	s->manufact.len = buf[0] << 8 | buf[1];	if (s->manufact.len < 0 || s->manufact.len > 2048) {		cdinfo(CD_WARNING, "Received invalid manufacture info length"				   " (%d)\n", s->bca.len);		ret = -EIO;	} else {		memcpy(s->manufact.value, &buf[4], s->manufact.len);	}	kfree(buf);	return ret;}static int dvd_read_struct(struct cdrom_device_info *cdi, dvd_struct *s){	switch (s->type) {	case DVD_STRUCT_PHYSICAL:		return dvd_read_physical(cdi, s);	case DVD_STRUCT_COPYRIGHT:		return dvd_read_copyright(cdi, s);	case DVD_STRUCT_DISCKEY:		return dvd_read_disckey(cdi, s);	case DVD_STRUCT_BCA:		return dvd_read_bca(cdi, s);	case DVD_STRUCT_MANUFACT:		return dvd_read_manufact(cdi, s);			default:		cdinfo(CD_WARNING, ": Invalid DVD structure read requested (%d)\n",					s->type);		return -EINVAL;	}}int cdrom_mode_sense(struct cdrom_device_info *cdi,		     struct cdrom_generic_command *cgc,		     int page_code, int page_control){	struct cdrom_device_ops *cdo = cdi->ops;	memset(cgc->cmd, 0, sizeof(cgc->cmd));	cgc->cmd[0] = GPCMD_MODE_SENSE_10;	cgc->cmd[2] = page_code | (page_control << 6);	cgc->cmd[7] = cgc->buflen >> 8;	cgc->cmd[8] = cgc->buflen & 0xff;	cgc->data_direction = CGC_DATA_READ;	return cdo->generic_packet(cdi, cgc);}int cdrom_mode_select(struct cdrom_device_info *cdi,		      struct cdrom_generic_command *cgc){	struct cdrom_device_ops *cdo = cdi->ops;	memset(cgc->cmd, 0, sizeof(cgc->cmd));	memset(cgc->buffer, 0, 2);	cgc->cmd[0] = GPCMD_MODE_SELECT_10;	cgc->cmd[1] = 0x10;		/* PF */	cgc->cmd[7] = cgc->buflen >> 8;	cgc->cmd[8] = cgc->buflen & 0xff;	cgc->data_direction = CGC_DATA_WRITE;	return cdo->generic_packet(cdi, cgc);}static int cdrom_read_subchannel(struct cdrom_device_info *cdi,				 struct cdrom_subchnl *subchnl, int mcn){	struct cdrom_device_ops *cdo = cdi->ops;	struct cdrom_generic_command cgc;	char buffer[32];	int ret;	init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ);	cgc.cmd[0] = GPCMD_READ_SUBCHANNEL;	cgc.cmd[1] = 2;     /* MSF addressing */	cgc.cmd[2] = 0x40;  /* request subQ data */	cgc.cmd[3] = mcn ? 2 : 1;	cgc.cmd[8] = 16;	if ((ret = cdo->generic_packet(cdi, &cgc)))		return ret;	subchnl->cdsc_audiostatus = cgc.buffer[1];	subchnl->cdsc_format = CDROM_MSF;	subchnl->cdsc_ctrl = cgc.buffer[5] & 0xf;	subchnl->cdsc_trk = cgc.buffer[6];	subchnl->cdsc_ind = cgc.buffer[7];	subchnl->cdsc_reladdr.msf.minute = cgc.buffer[13];	subchnl->cdsc_reladdr.msf.second = cgc.buffer[14];	subchnl->cdsc_reladdr.msf.frame = cgc.buffer[15];	subchnl->cdsc_absaddr.msf.minute = cgc.buffer[9];	subchnl->cdsc_absaddr.msf.second = cgc.buffer[10];	subchnl->cdsc_absaddr.msf.frame = cgc.buffer[11];	return 0;}/* * Specific READ_10 interface */static int cdrom_read_cd(struct cdrom_device_info *cdi,			 struct cdrom_generic_command *cgc, int lba,			 int blocksize, int nblocks){	struct cdrom_device_ops *cdo = cdi->ops;	memset(&cgc->cmd, 0, sizeof(cgc->cmd));	cgc->cmd[0] = GPCMD_READ_10;	cgc->cmd[2] = (lba >> 24) & 0xff;	cgc->cmd[3] = (lba >> 16) & 0xff;	cgc->cmd[4] = (lba >>  8) & 0xff;	cgc->cmd[5] = lba & 0xff;	cgc->cmd[6] = (nblocks >> 16) & 0xff;	cgc->cmd[7] = (nblocks >>  8) & 0xff;	cgc->cmd[8] = nblocks & 0xff;	cgc->buflen = blocksize * nblocks;	return cdo->generic_packet(cdi, cgc);}/* very generic interface for reading the various types of blocks */static int cdrom_read_block(struct cdrom_device_info *cdi,			    struct cdrom_generic_command *cgc,			    int lba, int nblocks, int format, int blksize){	struct cdrom_device_ops *cdo = cdi->ops;	memset(&cgc->cmd, 0, sizeof(cgc->cmd));	cgc->cmd[0] = GPCMD_READ_CD;	/* expected sector size - cdda,mode1,etc. */	cgc->cmd[1] = format << 2;	/* starting address */	cgc->cmd[2] = (lba >> 24) & 0xff;	cgc->cmd[3] = (lba >> 16) & 0xff;	cgc->cmd[4] = (lba >>  8) & 0xff;	cgc->cmd[5] = lba & 0xff;	/* number of blocks */	cgc->cmd[6] = (nblocks >> 16) & 0xff;	cgc->cmd[7] = (nblocks >>  8) & 0xff;	cgc->cmd[8] = nblocks & 0xff;	cgc->buflen = blksize * nblocks;		/* set the header info returned */	switch (blksize) {	case CD_FRAMESIZE_RAW0	: cgc->cmd[9] = 0x58; break;	case CD_FRAMESIZE_RAW1	: cgc->cmd[9] = 0x78; break;	case CD_FRAMESIZE_RAW	: cgc->cmd[9] = 0xf8; break;	default			: cgc->cmd[9] = 0x10;	}		return cdo->generic_packet(cdi, cgc);}/* Just about every imaginable ioctl is supported in the Uniform layer * these days. ATAPI / SCSI specific code now mainly resides in * mmc_ioct(). */static int cdrom_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,		       unsigned long arg){	kdev_t dev = ip->i_rdev;	struct cdrom_device_info *cdi = cdrom_find_device(dev);	struct cdrom_device_ops *cdo = cdi->ops;	int ret;	/* the first few commands do not deal with audio drive_info, but	   only with routines in cdrom device operations. */	switch (cmd) {	case CDROMMULTISESSION: {		struct cdrom_multisession ms_info;		u_char requested_format;		cdinfo(CD_DO_IOCTL, "entering CDROMMULTISESSION\n");                 if (!(cdo->capability & CDC_MULTI_SESSION))                        return -ENOSYS;		IOCTL_IN(arg, struct cdrom_multisession, ms_info);		requested_format = ms_info.addr_format;		if (!((requested_format == CDROM_MSF) ||			(requested_format == CDROM_LBA)))				return -EINVAL;		ms_info.addr_format = CDROM_LBA;		if ((ret=cdo->get_last_session(cdi, &ms_info)))			return ret;		sanitize_format(&ms_info.addr, &ms_info.addr_format,				requested_format);		IOCTL_OUT(arg, struct cdrom_multisession, ms_info);		cdinfo(CD_DO_IOCTL, "CDROMMULTISESSION successful\n"); 		return 0;		}	case CDROMEJECT: {		cdinfo(CD_DO_IOCTL, "entering CDROMEJECT\n"); 		if (!CDROM_CAN(CDC_OPEN_TRAY))			return -ENOSYS;		if (cdi->use_count != 1 || keeplocked)			return -EBUSY;		if (CDROM_CAN(CDC_LOCK))			if ((ret=cdo->lock_door(cdi, 0)))				return ret;		return cdo->tray_move(cdi, 1);		}	case CDROMCLOSETRAY: {		cdinfo(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n"); 		if (!CDROM_CAN(CDC_CLOSE_TRAY))			return -ENOSYS;		return cdo->tray_move(cdi, 0);		}	case CDROMEJECT_SW: {		cdinfo(CD_DO_IOCTL, "entering CDROMEJECT_SW\n"); 		if (!CDROM_CAN(CDC_OPEN_TRAY))			return -ENOSYS;		if (keeplocked)			return -EBUSY;		cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT);		if (arg)			cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT;		return 0;		}	case CDROM_MEDIA_CHANGED: {		struct cdrom_changer_info info;		cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n"); 		if (!CDROM_CAN(CDC_MEDIA_CHANGED))			return -ENOSYS;		/* cannot select disc or select current disc */		if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT)			return media_changed(cdi, 1);		if ((unsigned int)arg >= cdi->capacity)			return -EINVAL;		if ((ret = cdrom_read_mech_status(cdi, &info)))			return ret;		return info.slots[arg].change;		}	case CDROM_SET_OPTIONS: {		cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n"); 		/* options need to be in sync with capability. too late for		   that, so we have to check each one separately... */		switch (arg) {		case CDO_USE_FFLAGS:		case CDO_CHECK_TYPE:			break;		case CDO_LOCK:			if (!CDROM_CAN(CDC_LOCK))				return -ENOSYS;			break;		case 0:			return cdi->options;		/* default is basically CDO_[AUTO_CLOSE|AUTO_EJECT] */		default:			if (!CDROM_CAN(arg))				return -ENOSYS;		}		cdi->options |= (int) arg;		return cdi->options;		}	case CDROM_CLEAR_OPTIONS: {		cdinfo(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n"); 		cdi->options &= ~(int) arg;		return cdi->options;		}	case CDROM_SELECT_SPEED: {		cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n"); 		if (!CDROM_CAN(CDC_SELECT_SPEED))			return -ENOSYS;		return cdo->select_speed(cdi, arg);		}	case CDROM_SELECT_DISC: {		cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n"); 		if (!CDROM_CAN(CDC_SELECT_DISC))			return -ENOSYS;                if ((arg != CDSL_CURRENT) && (arg != CDSL_NONE))			if ((int)arg >= cdi->capacity)				return -EINVAL;		/* cdo->select_disc is a hook to allow a driver-specific		 * way of seleting disc.  However, since there is no		 * equiv hook for cdrom_slot_status this may not 		 * actually be useful...		 */		if (cdo->select_disc != NULL)			return cdo->select_disc(cdi, arg);		/* no driver specific select_disc(), call our own */		cdinfo(CD_CHANGER, "Using generic cdrom_select_disc()\n"); 		return cdrom_select_disc(cdi, arg);		}	case CDROMRESET: {		if (!capable(CAP_SYS_ADMIN))			return -EACCES;		cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n");		if (!CDROM_CAN(CDC_RESET))			return -ENOSYS;		return cdo->reset(cdi);		}	case CDROM_LOCKDOOR: {		cdinfo(CD_DO_IOCTL, "%socking door.\n", arg ? "L" : "Unl");		if (!CDROM_CAN(CDC_LOCK))			return -EDRIVE_CANT_DO_THIS;		keeplocked = arg ? 1 : 0;		/* don't unlock the door on multiple opens,but allow root		 * to do so */		if ((cdi->use_count != 1) && !arg && !capable(CAP_SYS_ADMIN))			return -EBUSY;		return cdo->lock_door(cdi, arg);		}	case CDROM_DEBUG: {		if (!capable(CAP_SYS_ADMIN))			return -EACCES;		cdinfo(CD_DO_IOCTL, "%sabling debug.\n", arg ? "En" : "Dis");		debug = arg ? 1 : 0;		return debug;		}	case CDROM_GET_CAPABILITY: {		cdinfo(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n");		return (cdo->capability & ~cdi->mask);		}/* The following function is implemented, although very few audio * discs give Universal Product Code information, which should just be * the Medium Catalog Number on the box.  Note, that the way the code * is written on the CD is /not/ uniform across all discs! */	case CDROM_GET_MCN: {		struct cdrom_mcn mcn;		cdinfo(CD_DO_IOCTL, "entering CDROM_GET_MCN\n"); 		if (!(cdo->capability & CDC_MCN))			return -ENOSYS;		if ((ret=cdo->get_mcn(cdi, &mcn)))			return ret;		IOCTL_OUT(arg, struct cdrom_mcn, mcn);		cdinfo(CD_DO_IOCTL, "CDROM_GET_MCN successful\n"); 		return 0;		}	case CDROM_DRIVE_STATUS: {		cdinfo(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n"); 		if (!(cdo->capability & CDC_DRIVE_STATUS))			return -ENOSYS;		if (!CDROM_CAN(CDC_SELECT_DISC))			return cdo->drive_status(cdi, CDSL_CURRENT);                if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE)) 			return cdo->drive_status(cdi, CDSL_CURRENT);		if (((int)arg >= cdi->capacity))			return -EINVAL;		return cdrom_slot_status(cdi, arg);		}	/* Ok, this is where problems start.  The current interface for the	   CDROM_DISC_STATUS ioctl is flawed.  It makes the false assumption	   that CDs are all CDS_DATA_1 or all CDS_AUDIO, etc.  Unfortunatly,	   while this is often the case, it is also very common for CDs to	   have some tracks with data, and some tracks with audio.  Just 	   because I feel like it, I declare the following to be the best	   way to cope.  If the CD has ANY data tracks on it, it will be	   returned as a data CD.  If it has any XA tracks, I will return	   it as that.  Now I could simplify this interface by combining these 	   returns with the above, but this more clearly demonstrates	   the problem with the current interface.  Too bad this wasn't 	   designed to use bitmasks...         -Erik 	   Well, now we have the option CDS_MIXED: a mixed-type CD. 	   User level programmers might feel the ioctl is not very useful.	   					---david	*/	case CDROM_DISC_STATUS: {		tracktype tracks;		cdinfo(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n"); 		cdrom_count_tracks(cdi, &tracks);		if (tracks.error) 			return(tracks.error);		/* Policy mode on */		if (tracks.audio > 0) {			if (tracks.data==0 && tracks.cdi==0 && tracks.xa==0) 				return CDS_AUDIO;			else				return CDS_MIXED;		}		if (tracks.cdi > 0) return CDS_XA_2_2;		if (tracks.xa > 0) return CDS_XA_2_1;		if (tracks.data > 0) return CDS_DATA_1;		/* Policy mode off */		cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognize!\n");		return CDS_NO_INFO;		}	case CDROM_CHANGER_NSLOTS: {		cdinfo(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n"); 		return cdi->capacity;		}	}	/* use the ioctls that are implemented through the generic_packet()	   interface. this may look at bit funny, but if -ENOTTY is	   returned that particular ioctl is not implemented and we	   let it go through the device specific ones. */

⌨️ 快捷键说明

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