diff options
Diffstat (limited to 'drivers/cdrom/cdrom.c')
| -rw-r--r-- | drivers/cdrom/cdrom.c | 1283 | 
1 files changed, 644 insertions, 639 deletions
| diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 8a3aff724d98..898b84bba28a 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -312,36 +312,24 @@ static const char *mrw_format_status[] = {  static const char *mrw_address_space[] = { "DMA", "GAA" }; -#if (ERRLOGMASK!=CD_NOTHING) -#define cdinfo(type, fmt, args...)			\ +#if (ERRLOGMASK != CD_NOTHING) +#define cd_dbg(type, fmt, ...)				\  do {							\  	if ((ERRLOGMASK & type) || debug == 1)		\ -		pr_info(fmt, ##args);			\ +		pr_debug(fmt, ##__VA_ARGS__);		\  } while (0)  #else -#define cdinfo(type, fmt, args...)			\ +#define cd_dbg(type, fmt, ...)				\  do {							\  	if (0 && (ERRLOGMASK & type) || debug == 1)	\ -		pr_info(fmt, ##args);			\ +		pr_debug(fmt, ##__VA_ARGS__);		\  } while (0)  #endif -/* These are used to simplify getting data in from and back to user land */ -#define IOCTL_IN(arg, type, in)					\ -	if (copy_from_user(&(in), (type __user *) (arg), sizeof (in)))	\ -		return -EFAULT; - -#define IOCTL_OUT(arg, type, out) \ -	if (copy_to_user((type __user *) (arg), &(out), sizeof (out)))	\ -		return -EFAULT; -  /* The (cdo->capability & ~cdi->mask & CDC_XXX) construct was used in     a lot of places. This macro makes the code more clear. */  #define CDROM_CAN(type) (cdi->ops->capability & ~cdi->mask & (type)) -/* used in the audio ioctls */ -#define CHECKAUDIO if ((ret=check_for_audio_disc(cdi, cdo))) return ret -  /*   * Another popular OS uses 7 seconds as the hard timeout for default   * commands, so it is a good choice for us as well. @@ -349,21 +337,6 @@ do {							\  #define CDROM_DEF_TIMEOUT	(7 * HZ)  /* Not-exported routines. */ -static int open_for_data(struct cdrom_device_info * cdi); -static int check_for_audio_disc(struct cdrom_device_info * cdi, -			 struct cdrom_device_ops * cdo); -static void sanitize_format(union cdrom_addr *addr,  -		u_char * curr, u_char requested); -static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, -		     unsigned long arg); - -int cdrom_get_last_written(struct cdrom_device_info *, long *); -static int cdrom_get_next_writable(struct cdrom_device_info *, long *); -static void cdrom_count_tracks(struct cdrom_device_info *, tracktype*); - -static int cdrom_mrw_exit(struct cdrom_device_info *cdi); - -static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information *di);  static void cdrom_sysctl_register(void); @@ -382,113 +355,65 @@ static int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi,  	return -EIO;  } -/* This macro makes sure we don't have to check on cdrom_device_ops - * existence in the run-time routines below. Change_capability is a - * hack to have the capability flags defined const, while we can still - * change it here without gcc complaining at every line. - */ -#define ENSURE(call, bits) if (cdo->call == NULL) *change_capability &= ~(bits) - -int register_cdrom(struct cdrom_device_info *cdi) -{ -	static char banner_printed; -        struct cdrom_device_ops *cdo = cdi->ops; -        int *change_capability = (int *)&cdo->capability; /* hack */ - -	cdinfo(CD_OPEN, "entering register_cdrom\n");  - -	if (cdo->open == NULL || cdo->release == NULL) -		return -EINVAL; -	if (!banner_printed) { -		pr_info("Uniform CD-ROM driver " REVISION "\n"); -		banner_printed = 1; -		cdrom_sysctl_register(); -	} - -	ENSURE(drive_status, CDC_DRIVE_STATUS ); -	if (cdo->check_events == NULL && cdo->media_changed == NULL) -		*change_capability = ~(CDC_MEDIA_CHANGED | CDC_SELECT_DISC); -	ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY); -	ENSURE(lock_door, CDC_LOCK); -	ENSURE(select_speed, CDC_SELECT_SPEED); -	ENSURE(get_last_session, CDC_MULTI_SESSION); -	ENSURE(get_mcn, CDC_MCN); -	ENSURE(reset, CDC_RESET); -	ENSURE(generic_packet, CDC_GENERIC_PACKET); -	cdi->mc_flags = 0; -	cdo->n_minors = 0; -        cdi->options = CDO_USE_FFLAGS; -	 -	if (autoclose==1 && CDROM_CAN(CDC_CLOSE_TRAY)) -		cdi->options |= (int) CDO_AUTO_CLOSE; -	if (autoeject==1 && CDROM_CAN(CDC_OPEN_TRAY)) -		cdi->options |= (int) CDO_AUTO_EJECT; -	if (lockdoor==1) -		cdi->options |= (int) CDO_LOCK; -	if (check_media_type==1) -		cdi->options |= (int) CDO_CHECK_TYPE; - -	if (CDROM_CAN(CDC_MRW_W)) -		cdi->exit = cdrom_mrw_exit; - -	if (cdi->disk) -		cdi->cdda_method = CDDA_BPC_FULL; -	else -		cdi->cdda_method = CDDA_OLD; - -	if (!cdo->generic_packet) -		cdo->generic_packet = cdrom_dummy_generic_packet; - -	cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); -	mutex_lock(&cdrom_mutex); -	list_add(&cdi->list, &cdrom_list); -	mutex_unlock(&cdrom_mutex); -	return 0; -} -#undef ENSURE - -void unregister_cdrom(struct cdrom_device_info *cdi) +static int cdrom_flush_cache(struct cdrom_device_info *cdi)  { -	cdinfo(CD_OPEN, "entering unregister_cdrom\n");  +	struct packet_command cgc; -	mutex_lock(&cdrom_mutex); -	list_del(&cdi->list); -	mutex_unlock(&cdrom_mutex); +	init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); +	cgc.cmd[0] = GPCMD_FLUSH_CACHE; -	if (cdi->exit) -		cdi->exit(cdi); +	cgc.timeout = 5 * 60 * HZ; -	cdi->ops->n_minors--; -	cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name); +	return cdi->ops->generic_packet(cdi, &cgc);  } -int cdrom_get_media_event(struct cdrom_device_info *cdi, -			  struct media_event_desc *med) +/* requires CD R/RW */ +static int cdrom_get_disc_info(struct cdrom_device_info *cdi, +			       disc_information *di)  { +	struct cdrom_device_ops *cdo = cdi->ops;  	struct packet_command cgc; -	unsigned char buffer[8]; -	struct event_header *eh = (struct event_header *) buffer; +	int ret, buflen; -	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); +	/* set up command and get the disc info */ +	init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ); +	cgc.cmd[0] = GPCMD_READ_DISC_INFO; +	cgc.cmd[8] = cgc.buflen = 2;  	cgc.quiet = 1; -	if (cdi->ops->generic_packet(cdi, &cgc)) -		return 1; +	ret = cdo->generic_packet(cdi, &cgc); +	if (ret) +		return ret; -	if (be16_to_cpu(eh->data_len) < sizeof(*med)) -		return 1; +	/* not all drives have the same disc_info length, so requeue +	 * packet with the length the drive tells us it can supply +	 */ +	buflen = be16_to_cpu(di->disc_information_length) + +		sizeof(di->disc_information_length); -	if (eh->nea || eh->notification_class != 0x4) -		return 1; +	if (buflen > sizeof(disc_information)) +		buflen = sizeof(disc_information); -	memcpy(med, &buffer[sizeof(*eh)], sizeof(*med)); -	return 0; +	cgc.cmd[8] = cgc.buflen = buflen; +	ret = cdo->generic_packet(cdi, &cgc); +	if (ret) +		return ret; + +	/* return actual fill size */ +	return buflen;  } +/* This macro makes sure we don't have to check on cdrom_device_ops + * existence in the run-time routines below. Change_capability is a + * hack to have the capability flags defined const, while we can still + * change it here without gcc complaining at every line. + */ +#define ENSURE(call, bits)			\ +do {						\ +	if (cdo->call == NULL)			\ +		*change_capability &= ~(bits);	\ +} while (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 @@ -605,18 +530,6 @@ static int cdrom_mrw_bgformat_susp(struct cdrom_device_info *cdi, int immed)  	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; @@ -650,17 +563,19 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space)  	cgc.buffer = buffer;  	cgc.buflen = sizeof(buffer); -	if ((ret = cdrom_mode_sense(cdi, &cgc, cdi->mrw_mode_page, 0))) +	ret = cdrom_mode_sense(cdi, &cgc, cdi->mrw_mode_page, 0); +	if (ret)  		return ret; -	mph = (struct mode_page_header *) buffer; +	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))) +	ret = cdrom_mode_select(cdi, &cgc); +	if (ret)  		return ret;  	pr_info("%s: mrw address space %s selected\n", @@ -668,6 +583,106 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space)  	return 0;  } +int register_cdrom(struct cdrom_device_info *cdi) +{ +	static char banner_printed; +	struct cdrom_device_ops *cdo = cdi->ops; +	int *change_capability = (int *)&cdo->capability; /* hack */ + +	cd_dbg(CD_OPEN, "entering register_cdrom\n"); + +	if (cdo->open == NULL || cdo->release == NULL) +		return -EINVAL; +	if (!banner_printed) { +		pr_info("Uniform CD-ROM driver " REVISION "\n"); +		banner_printed = 1; +		cdrom_sysctl_register(); +	} + +	ENSURE(drive_status, CDC_DRIVE_STATUS); +	if (cdo->check_events == NULL && cdo->media_changed == NULL) +		*change_capability = ~(CDC_MEDIA_CHANGED | CDC_SELECT_DISC); +	ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY); +	ENSURE(lock_door, CDC_LOCK); +	ENSURE(select_speed, CDC_SELECT_SPEED); +	ENSURE(get_last_session, CDC_MULTI_SESSION); +	ENSURE(get_mcn, CDC_MCN); +	ENSURE(reset, CDC_RESET); +	ENSURE(generic_packet, CDC_GENERIC_PACKET); +	cdi->mc_flags = 0; +	cdo->n_minors = 0; +	cdi->options = CDO_USE_FFLAGS; + +	if (autoclose == 1 && CDROM_CAN(CDC_CLOSE_TRAY)) +		cdi->options |= (int) CDO_AUTO_CLOSE; +	if (autoeject == 1 && CDROM_CAN(CDC_OPEN_TRAY)) +		cdi->options |= (int) CDO_AUTO_EJECT; +	if (lockdoor == 1) +		cdi->options |= (int) CDO_LOCK; +	if (check_media_type == 1) +		cdi->options |= (int) CDO_CHECK_TYPE; + +	if (CDROM_CAN(CDC_MRW_W)) +		cdi->exit = cdrom_mrw_exit; + +	if (cdi->disk) +		cdi->cdda_method = CDDA_BPC_FULL; +	else +		cdi->cdda_method = CDDA_OLD; + +	if (!cdo->generic_packet) +		cdo->generic_packet = cdrom_dummy_generic_packet; + +	cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); +	mutex_lock(&cdrom_mutex); +	list_add(&cdi->list, &cdrom_list); +	mutex_unlock(&cdrom_mutex); +	return 0; +} +#undef ENSURE + +void unregister_cdrom(struct cdrom_device_info *cdi) +{ +	cd_dbg(CD_OPEN, "entering unregister_cdrom\n"); + +	mutex_lock(&cdrom_mutex); +	list_del(&cdi->list); +	mutex_unlock(&cdrom_mutex); + +	if (cdi->exit) +		cdi->exit(cdi); + +	cdi->ops->n_minors--; +	cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name); +} + +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; +} +  static int cdrom_get_random_writable(struct cdrom_device_info *cdi,  			      struct rwrt_feature_desc *rfd)  { @@ -839,7 +854,7 @@ static int cdrom_ram_open_write(struct cdrom_device_info *cdi)  	else if (CDF_RWRT == be16_to_cpu(rfd.feature_code))  		ret = !rfd.curr; -	cdinfo(CD_OPEN, "can open for random write\n"); +	cd_dbg(CD_OPEN, "can open for random write\n");  	return ret;  } @@ -928,12 +943,12 @@ 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); +		cd_dbg(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); +		cd_dbg(CD_CLOSE, "%s: DVD+RW media clean\n", cdi->name);  		return;  	} @@ -969,82 +984,74 @@ static int cdrom_close_write(struct cdrom_device_info *cdi)  #endif  } -/* We use the open-option O_NONBLOCK to indicate that the - * purpose of opening is only for subsequent ioctl() calls; no device - * integrity checks are performed. - * - * We hope that all cd-player programs will adopt this convention. It - * is in their own interest: device control becomes a lot easier - * this way. - */ -int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, fmode_t mode) +/* badly broken, I know. Is due for a fixup anytime. */ +static void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype *tracks)  { -	int ret; - -	cdinfo(CD_OPEN, "entering cdrom_open\n");  - -	/* open is event synchronization point, check events first */ -	check_disk_change(bdev); - -	/* if this was a O_NONBLOCK open and we should honor the flags, -	 * do a quick open without drive/disc integrity checks. */ -	cdi->use_count++; -	if ((mode & FMODE_NDELAY) && (cdi->options & CDO_USE_FFLAGS)) { -		ret = cdi->ops->open(cdi, 1); -	} else { -		ret = open_for_data(cdi); -		if (ret) -			goto err; -		cdrom_mmc3_profile(cdi); -		if (mode & FMODE_WRITE) { -			ret = -EROFS; -			if (cdrom_open_write(cdi)) -				goto err_release; -			if (!CDROM_CAN(CDC_RAM)) -				goto err_release; -			ret = 0; -			cdi->media_written = 0; -		} +	struct cdrom_tochdr header; +	struct cdrom_tocentry entry; +	int ret, i; +	tracks->data = 0; +	tracks->audio = 0; +	tracks->cdi = 0; +	tracks->xa = 0; +	tracks->error = 0; +	cd_dbg(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n"); +	/* Grab the TOC header so we can see how many tracks there are */ +	ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header); +	if (ret) { +		if (ret == -ENOMEDIUM) +			tracks->error = CDS_NO_DISC; +		else +			tracks->error = CDS_NO_INFO; +		return;  	} - -	if (ret) -		goto err; - -	cdinfo(CD_OPEN, "Use count for \"/dev/%s\" now %d\n", -			cdi->name, cdi->use_count); -	return 0; -err_release: -	if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { -		cdi->ops->lock_door(cdi, 0); -		cdinfo(CD_OPEN, "door unlocked.\n"); +	/* check what type of tracks are on this disc */ +	entry.cdte_format = CDROM_MSF; +	for (i = header.cdth_trk0; i <= header.cdth_trk1; i++) { +		entry.cdte_track = i; +		if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) { +			tracks->error = CDS_NO_INFO; +			return; +		} +		if (entry.cdte_ctrl & CDROM_DATA_TRACK) { +			if (entry.cdte_format == 0x10) +				tracks->cdi++; +			else if (entry.cdte_format == 0x20) +				tracks->xa++; +			else +				tracks->data++; +		} else { +			tracks->audio++; +		} +		cd_dbg(CD_COUNT_TRACKS, "track %d: format=%d, ctrl=%d\n", +		       i, entry.cdte_format, entry.cdte_ctrl);  	} -	cdi->ops->release(cdi); -err: -	cdi->use_count--; -	return ret; +	cd_dbg(CD_COUNT_TRACKS, "disc has %d tracks: %d=audio %d=data %d=Cd-I %d=XA\n", +	       header.cdth_trk1, tracks->audio, tracks->data, +	       tracks->cdi, tracks->xa);  }  static -int open_for_data(struct cdrom_device_info * cdi) +int open_for_data(struct cdrom_device_info *cdi)  {  	int ret;  	struct cdrom_device_ops *cdo = cdi->ops;  	tracktype tracks; -	cdinfo(CD_OPEN, "entering open_for_data\n"); +	cd_dbg(CD_OPEN, "entering open_for_data\n");  	/* Check if the driver can report drive status.  If it can, we  	   can do clever things.  If it can't, well, we at least tried! */  	if (cdo->drive_status != NULL) {  		ret = cdo->drive_status(cdi, CDSL_CURRENT); -		cdinfo(CD_OPEN, "drive_status=%d\n", ret);  +		cd_dbg(CD_OPEN, "drive_status=%d\n", ret);  		if (ret == CDS_TRAY_OPEN) { -			cdinfo(CD_OPEN, "the tray is open...\n");  +			cd_dbg(CD_OPEN, "the tray is open...\n");  			/* can/may i close it? */  			if (CDROM_CAN(CDC_CLOSE_TRAY) &&  			    cdi->options & CDO_AUTO_CLOSE) { -				cdinfo(CD_OPEN, "trying to close the tray.\n");  +				cd_dbg(CD_OPEN, "trying to close the tray\n");  				ret=cdo->tray_move(cdi,0);  				if (ret) { -					cdinfo(CD_OPEN, "bummer. tried to close the tray but failed.\n");  +					cd_dbg(CD_OPEN, "bummer. tried to close the tray but failed.\n");  					/* Ignore the error from the low  					level driver.  We don't care why it  					couldn't close the tray.  We only care  @@ -1054,19 +1061,19 @@ int open_for_data(struct cdrom_device_info * cdi)  					goto clean_up_and_return;  				}  			} else { -				cdinfo(CD_OPEN, "bummer. this drive can't close the tray.\n");  +				cd_dbg(CD_OPEN, "bummer. this drive can't close the tray.\n");  				ret=-ENOMEDIUM;  				goto clean_up_and_return;  			}  			/* Ok, the door should be closed now.. Check again */  			ret = cdo->drive_status(cdi, CDSL_CURRENT);  			if ((ret == CDS_NO_DISC) || (ret==CDS_TRAY_OPEN)) { -				cdinfo(CD_OPEN, "bummer. the tray is still not closed.\n");  -				cdinfo(CD_OPEN, "tray might not contain a medium.\n"); +				cd_dbg(CD_OPEN, "bummer. the tray is still not closed.\n"); +				cd_dbg(CD_OPEN, "tray might not contain a medium\n");  				ret=-ENOMEDIUM;  				goto clean_up_and_return;  			} -			cdinfo(CD_OPEN, "the tray is now closed.\n");  +			cd_dbg(CD_OPEN, "the tray is now closed\n");  		}  		/* the door should be closed now, check for the disc */  		ret = cdo->drive_status(cdi, CDSL_CURRENT); @@ -1077,7 +1084,7 @@ int open_for_data(struct cdrom_device_info * cdi)  	}  	cdrom_count_tracks(cdi, &tracks);  	if (tracks.error == CDS_NO_DISC) { -		cdinfo(CD_OPEN, "bummer. no disc.\n"); +		cd_dbg(CD_OPEN, "bummer. no disc.\n");  		ret=-ENOMEDIUM;  		goto clean_up_and_return;  	} @@ -1087,34 +1094,34 @@ int open_for_data(struct cdrom_device_info * cdi)  		if (cdi->options & CDO_CHECK_TYPE) {  		    /* give people a warning shot, now that CDO_CHECK_TYPE  		       is the default case! */ -		    cdinfo(CD_OPEN, "bummer. wrong media type.\n");  -		    cdinfo(CD_WARNING, "pid %d must open device O_NONBLOCK!\n", -					(unsigned int)task_pid_nr(current)); +		    cd_dbg(CD_OPEN, "bummer. wrong media type.\n"); +		    cd_dbg(CD_WARNING, "pid %d must open device O_NONBLOCK!\n", +			   (unsigned int)task_pid_nr(current));  		    ret=-EMEDIUMTYPE;  		    goto clean_up_and_return;  		}  		else { -		    cdinfo(CD_OPEN, "wrong media type, but CDO_CHECK_TYPE not set.\n"); +		    cd_dbg(CD_OPEN, "wrong media type, but CDO_CHECK_TYPE not set\n");  		}  	} -	cdinfo(CD_OPEN, "all seems well, opening the device.\n");  +	cd_dbg(CD_OPEN, "all seems well, opening the devicen");  	/* all seems well, we can open the device */  	ret = cdo->open(cdi, 0); /* open for data */ -	cdinfo(CD_OPEN, "opening the device gave me %d.\n", ret);  +	cd_dbg(CD_OPEN, "opening the device gave me %d\n", ret);  	/* After all this careful checking, we shouldn't have problems  	   opening the device, but we don't want the device locked if   	   this somehow fails... */  	if (ret) { -		cdinfo(CD_OPEN, "open device failed.\n");  +		cd_dbg(CD_OPEN, "open device failed\n");  		goto clean_up_and_return;  	}  	if (CDROM_CAN(CDC_LOCK) && (cdi->options & CDO_LOCK)) {  			cdo->lock_door(cdi, 1); -			cdinfo(CD_OPEN, "door locked.\n"); +			cd_dbg(CD_OPEN, "door locked\n");  	} -	cdinfo(CD_OPEN, "device opened successfully.\n");  +	cd_dbg(CD_OPEN, "device opened successfully\n");  	return ret;  	/* Something failed.  Try to unlock the drive, because some drivers @@ -1123,14 +1130,70 @@ int open_for_data(struct cdrom_device_info * cdi)  	This ensures that the drive gets unlocked after a mount fails.  This   	is a goto to avoid bloating the driver with redundant code. */   clean_up_and_return: -	cdinfo(CD_OPEN, "open failed.\n");  +	cd_dbg(CD_OPEN, "open failed\n");  	if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) {  			cdo->lock_door(cdi, 0); -			cdinfo(CD_OPEN, "door unlocked.\n"); +			cd_dbg(CD_OPEN, "door unlocked\n");  	}  	return ret;  } +/* We use the open-option O_NONBLOCK to indicate that the + * purpose of opening is only for subsequent ioctl() calls; no device + * integrity checks are performed. + * + * We hope that all cd-player programs will adopt this convention. It + * is in their own interest: device control becomes a lot easier + * this way. + */ +int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, +	       fmode_t mode) +{ +	int ret; + +	cd_dbg(CD_OPEN, "entering cdrom_open\n"); + +	/* open is event synchronization point, check events first */ +	check_disk_change(bdev); + +	/* if this was a O_NONBLOCK open and we should honor the flags, +	 * do a quick open without drive/disc integrity checks. */ +	cdi->use_count++; +	if ((mode & FMODE_NDELAY) && (cdi->options & CDO_USE_FFLAGS)) { +		ret = cdi->ops->open(cdi, 1); +	} else { +		ret = open_for_data(cdi); +		if (ret) +			goto err; +		cdrom_mmc3_profile(cdi); +		if (mode & FMODE_WRITE) { +			ret = -EROFS; +			if (cdrom_open_write(cdi)) +				goto err_release; +			if (!CDROM_CAN(CDC_RAM)) +				goto err_release; +			ret = 0; +			cdi->media_written = 0; +		} +	} + +	if (ret) +		goto err; + +	cd_dbg(CD_OPEN, "Use count for \"/dev/%s\" now %d\n", +	       cdi->name, cdi->use_count); +	return 0; +err_release: +	if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { +		cdi->ops->lock_door(cdi, 0); +		cd_dbg(CD_OPEN, "door unlocked\n"); +	} +	cdi->ops->release(cdi); +err: +	cdi->use_count--; +	return ret; +} +  /* This code is similar to that in open_for_data. The routine is called     whenever an audio play operation is requested.  */ @@ -1139,21 +1202,21 @@ static int check_for_audio_disc(struct cdrom_device_info * cdi,  {          int ret;  	tracktype tracks; -	cdinfo(CD_OPEN, "entering check_for_audio_disc\n"); +	cd_dbg(CD_OPEN, "entering check_for_audio_disc\n");  	if (!(cdi->options & CDO_CHECK_TYPE))  		return 0;  	if (cdo->drive_status != NULL) {  		ret = cdo->drive_status(cdi, CDSL_CURRENT); -		cdinfo(CD_OPEN, "drive_status=%d\n", ret);  +		cd_dbg(CD_OPEN, "drive_status=%d\n", ret);  		if (ret == CDS_TRAY_OPEN) { -			cdinfo(CD_OPEN, "the tray is open...\n");  +			cd_dbg(CD_OPEN, "the tray is open...\n");  			/* can/may i close it? */  			if (CDROM_CAN(CDC_CLOSE_TRAY) &&  			    cdi->options & CDO_AUTO_CLOSE) { -				cdinfo(CD_OPEN, "trying to close the tray.\n");  +				cd_dbg(CD_OPEN, "trying to close the tray\n");  				ret=cdo->tray_move(cdi,0);  				if (ret) { -					cdinfo(CD_OPEN, "bummer. tried to close tray but failed.\n");  +					cd_dbg(CD_OPEN, "bummer. tried to close tray but failed.\n");  					/* Ignore the error from the low  					level driver.  We don't care why it  					couldn't close the tray.  We only care  @@ -1162,20 +1225,20 @@ static int check_for_audio_disc(struct cdrom_device_info * cdi,  					return -ENOMEDIUM;  				}  			} else { -				cdinfo(CD_OPEN, "bummer. this driver can't close the tray.\n");  +				cd_dbg(CD_OPEN, "bummer. this driver can't close the tray.\n");  				return -ENOMEDIUM;  			}  			/* Ok, the door should be closed now.. Check again */  			ret = cdo->drive_status(cdi, CDSL_CURRENT);  			if ((ret == CDS_NO_DISC) || (ret==CDS_TRAY_OPEN)) { -				cdinfo(CD_OPEN, "bummer. the tray is still not closed.\n");  +				cd_dbg(CD_OPEN, "bummer. the tray is still not closed.\n");  				return -ENOMEDIUM;  			}	  			if (ret!=CDS_DISC_OK) { -				cdinfo(CD_OPEN, "bummer. disc isn't ready.\n");  +				cd_dbg(CD_OPEN, "bummer. disc isn't ready.\n");  				return -EIO;  			}	 -			cdinfo(CD_OPEN, "the tray is now closed.\n");  +			cd_dbg(CD_OPEN, "the tray is now closed\n");  		}	  	}  	cdrom_count_tracks(cdi, &tracks); @@ -1193,17 +1256,18 @@ void cdrom_release(struct cdrom_device_info *cdi, fmode_t mode)  	struct cdrom_device_ops *cdo = cdi->ops;  	int opened_for_data; -	cdinfo(CD_CLOSE, "entering cdrom_release\n"); +	cd_dbg(CD_CLOSE, "entering cdrom_release\n");  	if (cdi->use_count > 0)  		cdi->use_count--;  	if (cdi->use_count == 0) { -		cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name); +		cd_dbg(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", +		       cdi->name);  		cdrom_dvd_rw_close_write(cdi);  		if ((cdo->capability & CDC_LOCK) && !cdi->keeplocked) { -			cdinfo(CD_CLOSE, "Unlocking door!\n"); +			cd_dbg(CD_CLOSE, "Unlocking door!\n");  			cdo->lock_door(cdi, 0);  		}  	} @@ -1262,7 +1326,7 @@ static int cdrom_slot_status(struct cdrom_device_info *cdi, int slot)  	struct cdrom_changer_info *info;  	int ret; -	cdinfo(CD_CHANGER, "entering cdrom_slot_status()\n");  +	cd_dbg(CD_CHANGER, "entering cdrom_slot_status()\n");  	if (cdi->sanyo_slot)  		return CDS_NO_INFO; @@ -1292,7 +1356,7 @@ int cdrom_number_of_slots(struct cdrom_device_info *cdi)  	int nslots = 1;  	struct cdrom_changer_info *info; -	cdinfo(CD_CHANGER, "entering cdrom_number_of_slots()\n");  +	cd_dbg(CD_CHANGER, "entering cdrom_number_of_slots()\n");  	/* cdrom_read_mech_status requires a valid value for capacity: */  	cdi->capacity = 0;  @@ -1313,7 +1377,7 @@ static int cdrom_load_unload(struct cdrom_device_info *cdi, int slot)  {  	struct packet_command cgc; -	cdinfo(CD_CHANGER, "entering cdrom_load_unload()\n");  +	cd_dbg(CD_CHANGER, "entering cdrom_load_unload()\n");  	if (cdi->sanyo_slot && slot < 0)  		return 0; @@ -1342,7 +1406,7 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot)  	int curslot;  	int ret; -	cdinfo(CD_CHANGER, "entering cdrom_select_disc()\n");  +	cd_dbg(CD_CHANGER, "entering cdrom_select_disc()\n");  	if (!CDROM_CAN(CDC_SELECT_DISC))  		return -EDRIVE_CANT_DO_THIS; @@ -1476,51 +1540,6 @@ int cdrom_media_changed(struct cdrom_device_info *cdi)  	return media_changed(cdi, 0);  } -/* badly broken, I know. Is due for a fixup anytime. */ -static void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype* tracks) -{ -	struct cdrom_tochdr header; -	struct cdrom_tocentry entry; -	int ret, i; -	tracks->data=0; -	tracks->audio=0; -	tracks->cdi=0; -	tracks->xa=0; -	tracks->error=0; -	cdinfo(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n");  -	/* Grab the TOC header so we can see how many tracks there are */ -	if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header))) { -		if (ret == -ENOMEDIUM) -			tracks->error = CDS_NO_DISC; -		else -			tracks->error = CDS_NO_INFO; -		return; -	}	 -	/* check what type of tracks are on this disc */ -	entry.cdte_format = CDROM_MSF; -	for (i = header.cdth_trk0; i <= header.cdth_trk1; i++) { -		entry.cdte_track  = i; -		if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) { -			tracks->error=CDS_NO_INFO; -			return; -		}	 -		if (entry.cdte_ctrl & CDROM_DATA_TRACK) { -		    if (entry.cdte_format == 0x10) -			tracks->cdi++; -		    else if (entry.cdte_format == 0x20)  -			tracks->xa++; -		    else -			tracks->data++; -		} else -		    tracks->audio++; -		cdinfo(CD_COUNT_TRACKS, "track %d: format=%d, ctrl=%d\n", -		       i, entry.cdte_format, entry.cdte_ctrl); -	}	 -	cdinfo(CD_COUNT_TRACKS, "disc has %d tracks: %d=audio %d=data %d=Cd-I %d=XA\n",  -		header.cdth_trk1, tracks->audio, tracks->data,  -		tracks->cdi, tracks->xa); -}	 -  /* Requests to the low-level drivers will /always/ be done in the     following format convention: @@ -1632,7 +1651,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)  	switch (ai->type) {  	/* LU data send */  	case DVD_LU_SEND_AGID: -		cdinfo(CD_DVD, "entering DVD_LU_SEND_AGID\n");  +		cd_dbg(CD_DVD, "entering DVD_LU_SEND_AGID\n");  		cgc.quiet = 1;  		setup_report_key(&cgc, ai->lsa.agid, 0); @@ -1644,7 +1663,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)  		break;  	case DVD_LU_SEND_KEY1: -		cdinfo(CD_DVD, "entering DVD_LU_SEND_KEY1\n");  +		cd_dbg(CD_DVD, "entering DVD_LU_SEND_KEY1\n");  		setup_report_key(&cgc, ai->lsk.agid, 2);  		if ((ret = cdo->generic_packet(cdi, &cgc))) @@ -1655,7 +1674,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)  		break;  	case DVD_LU_SEND_CHALLENGE: -		cdinfo(CD_DVD, "entering DVD_LU_SEND_CHALLENGE\n");  +		cd_dbg(CD_DVD, "entering DVD_LU_SEND_CHALLENGE\n");  		setup_report_key(&cgc, ai->lsc.agid, 1);  		if ((ret = cdo->generic_packet(cdi, &cgc))) @@ -1667,7 +1686,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)  	/* Post-auth key */  	case DVD_LU_SEND_TITLE_KEY: -		cdinfo(CD_DVD, "entering DVD_LU_SEND_TITLE_KEY\n");  +		cd_dbg(CD_DVD, "entering DVD_LU_SEND_TITLE_KEY\n");  		cgc.quiet = 1;  		setup_report_key(&cgc, ai->lstk.agid, 4);  		cgc.cmd[5] = ai->lstk.lba; @@ -1686,7 +1705,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)  		break;  	case DVD_LU_SEND_ASF: -		cdinfo(CD_DVD, "entering DVD_LU_SEND_ASF\n");  +		cd_dbg(CD_DVD, "entering DVD_LU_SEND_ASF\n");  		setup_report_key(&cgc, ai->lsasf.agid, 5);  		if ((ret = cdo->generic_packet(cdi, &cgc))) @@ -1697,7 +1716,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)  	/* LU data receive (LU changes state) */  	case DVD_HOST_SEND_CHALLENGE: -		cdinfo(CD_DVD, "entering DVD_HOST_SEND_CHALLENGE\n");  +		cd_dbg(CD_DVD, "entering DVD_HOST_SEND_CHALLENGE\n");  		setup_send_key(&cgc, ai->hsc.agid, 1);  		buf[1] = 0xe;  		copy_chal(&buf[4], ai->hsc.chal); @@ -1709,7 +1728,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)  		break;  	case DVD_HOST_SEND_KEY2: -		cdinfo(CD_DVD, "entering DVD_HOST_SEND_KEY2\n");  +		cd_dbg(CD_DVD, "entering DVD_HOST_SEND_KEY2\n");  		setup_send_key(&cgc, ai->hsk.agid, 3);  		buf[1] = 0xa;  		copy_key(&buf[4], ai->hsk.key); @@ -1724,7 +1743,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)  	/* Misc */  	case DVD_INVALIDATE_AGID:  		cgc.quiet = 1; -		cdinfo(CD_DVD, "entering DVD_INVALIDATE_AGID\n");  +		cd_dbg(CD_DVD, "entering DVD_INVALIDATE_AGID\n");  		setup_report_key(&cgc, ai->lsa.agid, 0x3f);  		if ((ret = cdo->generic_packet(cdi, &cgc)))  			return ret; @@ -1732,7 +1751,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)  	/* Get region settings */  	case DVD_LU_SEND_RPC_STATE: -		cdinfo(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n"); +		cd_dbg(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n");  		setup_report_key(&cgc, 0, 8);  		memset(&rpc_state, 0, sizeof(rpc_state_t));  		cgc.buffer = (char *) &rpc_state; @@ -1749,7 +1768,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)  	/* Set region settings */  	case DVD_HOST_SEND_RPC_STATE: -		cdinfo(CD_DVD, "entering DVD_HOST_SEND_RPC_STATE\n"); +		cd_dbg(CD_DVD, "entering DVD_HOST_SEND_RPC_STATE\n");  		setup_send_key(&cgc, 0, 6);  		buf[1] = 6;  		buf[4] = ai->hrpcs.pdrc; @@ -1759,7 +1778,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)  		break;  	default: -		cdinfo(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type); +		cd_dbg(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type);  		return -ENOTTY;  	} @@ -1891,7 +1910,8 @@ static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s,  	s->bca.len = buf[0] << 8 | buf[1];  	if (s->bca.len < 12 || s->bca.len > 188) { -		cdinfo(CD_WARNING, "Received invalid BCA length (%d)\n", s->bca.len); +		cd_dbg(CD_WARNING, "Received invalid BCA length (%d)\n", +		       s->bca.len);  		ret = -EIO;  		goto out;  	} @@ -1927,14 +1947,13 @@ static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s,  	s->manufact.len = buf[0] << 8 | buf[1];  	if (s->manufact.len < 0) { -		cdinfo(CD_WARNING, "Received invalid manufacture info length" -				   " (%d)\n", s->manufact.len); +		cd_dbg(CD_WARNING, "Received invalid manufacture info length (%d)\n", +		       s->manufact.len);  		ret = -EIO;  	} else {  		if (s->manufact.len > 2048) { -			cdinfo(CD_WARNING, "Received invalid manufacture info " -					"length (%d): truncating to 2048\n", -					s->manufact.len); +			cd_dbg(CD_WARNING, "Received invalid manufacture info length (%d): truncating to 2048\n", +			       s->manufact.len);  			s->manufact.len = 2048;  		}  		memcpy(s->manufact.value, &buf[4], s->manufact.len); @@ -1965,8 +1984,8 @@ static int dvd_read_struct(struct cdrom_device_info *cdi, dvd_struct *s,  		return dvd_read_manufact(cdi, s, cgc);  	default: -		cdinfo(CD_WARNING, ": Invalid DVD structure read requested (%d)\n", -					s->type); +		cd_dbg(CD_WARNING, ": Invalid DVD structure read requested (%d)\n", +		       s->type);  		return -EINVAL;  	}  } @@ -2165,6 +2184,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,  			ret = -ENOMEM;  			break;  		} +		blk_rq_set_block_pc(rq);  		ret = blk_rq_map_user(q, rq, NULL, ubuf, len, GFP_KERNEL);  		if (ret) { @@ -2184,7 +2204,6 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,  		rq->cmd[9] = 0xf8;  		rq->cmd_len = 12; -		rq->cmd_type = REQ_TYPE_BLOCK_PC;  		rq->timeout = 60 * HZ;  		bio = rq->bio; @@ -2255,7 +2274,7 @@ static int cdrom_ioctl_multisession(struct cdrom_device_info *cdi,  	u8 requested_format;  	int ret; -	cdinfo(CD_DO_IOCTL, "entering CDROMMULTISESSION\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROMMULTISESSION\n");  	if (!(cdi->ops->capability & CDC_MULTI_SESSION))  		return -ENOSYS; @@ -2277,13 +2296,13 @@ static int cdrom_ioctl_multisession(struct cdrom_device_info *cdi,  	if (copy_to_user(argp, &ms_info, sizeof(ms_info)))  		return -EFAULT; -	cdinfo(CD_DO_IOCTL, "CDROMMULTISESSION successful\n"); +	cd_dbg(CD_DO_IOCTL, "CDROMMULTISESSION successful\n");  	return 0;  }  static int cdrom_ioctl_eject(struct cdrom_device_info *cdi)  { -	cdinfo(CD_DO_IOCTL, "entering CDROMEJECT\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROMEJECT\n");  	if (!CDROM_CAN(CDC_OPEN_TRAY))  		return -ENOSYS; @@ -2300,7 +2319,7 @@ static int cdrom_ioctl_eject(struct cdrom_device_info *cdi)  static int cdrom_ioctl_closetray(struct cdrom_device_info *cdi)  { -	cdinfo(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n");  	if (!CDROM_CAN(CDC_CLOSE_TRAY))  		return -ENOSYS; @@ -2310,7 +2329,7 @@ static int cdrom_ioctl_closetray(struct cdrom_device_info *cdi)  static int cdrom_ioctl_eject_sw(struct cdrom_device_info *cdi,  		unsigned long arg)  { -	cdinfo(CD_DO_IOCTL, "entering CDROMEJECT_SW\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROMEJECT_SW\n");  	if (!CDROM_CAN(CDC_OPEN_TRAY))  		return -ENOSYS; @@ -2329,7 +2348,7 @@ static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi,  	struct cdrom_changer_info *info;  	int ret; -	cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n");  	if (!CDROM_CAN(CDC_MEDIA_CHANGED))  		return -ENOSYS; @@ -2355,7 +2374,7 @@ static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi,  static int cdrom_ioctl_set_options(struct cdrom_device_info *cdi,  		unsigned long arg)  { -	cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n");  	/*  	 * Options need to be in sync with capability. @@ -2383,7 +2402,7 @@ static int cdrom_ioctl_set_options(struct cdrom_device_info *cdi,  static int cdrom_ioctl_clear_options(struct cdrom_device_info *cdi,  		unsigned long arg)  { -	cdinfo(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n");  	cdi->options &= ~(int) arg;  	return cdi->options; @@ -2392,7 +2411,7 @@ static int cdrom_ioctl_clear_options(struct cdrom_device_info *cdi,  static int cdrom_ioctl_select_speed(struct cdrom_device_info *cdi,  		unsigned long arg)  { -	cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n");  	if (!CDROM_CAN(CDC_SELECT_SPEED))  		return -ENOSYS; @@ -2402,7 +2421,7 @@ static int cdrom_ioctl_select_speed(struct cdrom_device_info *cdi,  static int cdrom_ioctl_select_disc(struct cdrom_device_info *cdi,  		unsigned long arg)  { -	cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n");  	if (!CDROM_CAN(CDC_SELECT_DISC))  		return -ENOSYS; @@ -2420,14 +2439,14 @@ static int cdrom_ioctl_select_disc(struct cdrom_device_info *cdi,  	if (cdi->ops->select_disc)  		return cdi->ops->select_disc(cdi, arg); -	cdinfo(CD_CHANGER, "Using generic cdrom_select_disc()\n"); +	cd_dbg(CD_CHANGER, "Using generic cdrom_select_disc()\n");  	return cdrom_select_disc(cdi, arg);  }  static int cdrom_ioctl_reset(struct cdrom_device_info *cdi,  		struct block_device *bdev)  { -	cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROM_RESET\n");  	if (!capable(CAP_SYS_ADMIN))  		return -EACCES; @@ -2440,7 +2459,7 @@ static int cdrom_ioctl_reset(struct cdrom_device_info *cdi,  static int cdrom_ioctl_lock_door(struct cdrom_device_info *cdi,  		unsigned long arg)  { -	cdinfo(CD_DO_IOCTL, "%socking door.\n", arg ? "L" : "Unl"); +	cd_dbg(CD_DO_IOCTL, "%socking door\n", arg ? "L" : "Unl");  	if (!CDROM_CAN(CDC_LOCK))  		return -EDRIVE_CANT_DO_THIS; @@ -2459,7 +2478,7 @@ static int cdrom_ioctl_lock_door(struct cdrom_device_info *cdi,  static int cdrom_ioctl_debug(struct cdrom_device_info *cdi,  		unsigned long arg)  { -	cdinfo(CD_DO_IOCTL, "%sabling debug.\n", arg ? "En" : "Dis"); +	cd_dbg(CD_DO_IOCTL, "%sabling debug\n", arg ? "En" : "Dis");  	if (!capable(CAP_SYS_ADMIN))  		return -EACCES; @@ -2469,7 +2488,7 @@ static int cdrom_ioctl_debug(struct cdrom_device_info *cdi,  static int cdrom_ioctl_get_capability(struct cdrom_device_info *cdi)  { -	cdinfo(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n");  	return (cdi->ops->capability & ~cdi->mask);  } @@ -2485,7 +2504,7 @@ static int cdrom_ioctl_get_mcn(struct cdrom_device_info *cdi,  	struct cdrom_mcn mcn;  	int ret; -	cdinfo(CD_DO_IOCTL, "entering CDROM_GET_MCN\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROM_GET_MCN\n");  	if (!(cdi->ops->capability & CDC_MCN))  		return -ENOSYS; @@ -2495,14 +2514,14 @@ static int cdrom_ioctl_get_mcn(struct cdrom_device_info *cdi,  	if (copy_to_user(argp, &mcn, sizeof(mcn)))  		return -EFAULT; -	cdinfo(CD_DO_IOCTL, "CDROM_GET_MCN successful\n"); +	cd_dbg(CD_DO_IOCTL, "CDROM_GET_MCN successful\n");  	return 0;  }  static int cdrom_ioctl_drive_status(struct cdrom_device_info *cdi,  		unsigned long arg)  { -	cdinfo(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n");  	if (!(cdi->ops->capability & CDC_DRIVE_STATUS))  		return -ENOSYS; @@ -2535,7 +2554,7 @@ static int cdrom_ioctl_disc_status(struct cdrom_device_info *cdi)  {  	tracktype tracks; -	cdinfo(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n");  	cdrom_count_tracks(cdi, &tracks);  	if (tracks.error) @@ -2557,13 +2576,13 @@ static int cdrom_ioctl_disc_status(struct cdrom_device_info *cdi)  		return CDS_DATA_1;  	/* Policy mode off */ -	cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognize!\n"); +	cd_dbg(CD_WARNING, "This disc doesn't have any tracks I recognize!\n");  	return CDS_NO_INFO;  }  static int cdrom_ioctl_changer_nslots(struct cdrom_device_info *cdi)  { -	cdinfo(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n");  	return cdi->capacity;  } @@ -2574,7 +2593,7 @@ static int cdrom_ioctl_get_subchnl(struct cdrom_device_info *cdi,  	u8 requested, back;  	int ret; -	/* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/ +	/* cd_dbg(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/  	if (copy_from_user(&q, argp, sizeof(q)))  		return -EFAULT; @@ -2594,7 +2613,7 @@ static int cdrom_ioctl_get_subchnl(struct cdrom_device_info *cdi,  	if (copy_to_user(argp, &q, sizeof(q)))  		return -EFAULT; -	/* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ +	/* cd_dbg(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */  	return 0;  } @@ -2604,7 +2623,7 @@ static int cdrom_ioctl_read_tochdr(struct cdrom_device_info *cdi,  	struct cdrom_tochdr header;  	int ret; -	/* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */ +	/* cd_dbg(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */  	if (copy_from_user(&header, argp, sizeof(header)))  		return -EFAULT; @@ -2615,7 +2634,7 @@ static int cdrom_ioctl_read_tochdr(struct cdrom_device_info *cdi,  	if (copy_to_user(argp, &header, sizeof(header)))  		return -EFAULT; -	/* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */ +	/* cd_dbg(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */  	return 0;  } @@ -2626,7 +2645,7 @@ static int cdrom_ioctl_read_tocentry(struct cdrom_device_info *cdi,  	u8 requested_format;  	int ret; -	/* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */ +	/* cd_dbg(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */  	if (copy_from_user(&entry, argp, sizeof(entry)))  		return -EFAULT; @@ -2643,7 +2662,7 @@ static int cdrom_ioctl_read_tocentry(struct cdrom_device_info *cdi,  	if (copy_to_user(argp, &entry, sizeof(entry)))  		return -EFAULT; -	/* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */ +	/* cd_dbg(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */  	return 0;  } @@ -2652,7 +2671,7 @@ static int cdrom_ioctl_play_msf(struct cdrom_device_info *cdi,  {  	struct cdrom_msf msf; -	cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");  	if (!CDROM_CAN(CDC_PLAY_AUDIO))  		return -ENOSYS; @@ -2667,7 +2686,7 @@ static int cdrom_ioctl_play_trkind(struct cdrom_device_info *cdi,  	struct cdrom_ti ti;  	int ret; -	cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n");  	if (!CDROM_CAN(CDC_PLAY_AUDIO))  		return -ENOSYS; @@ -2684,7 +2703,7 @@ static int cdrom_ioctl_volctrl(struct cdrom_device_info *cdi,  {  	struct cdrom_volctrl volume; -	cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROMVOLCTRL\n");  	if (!CDROM_CAN(CDC_PLAY_AUDIO))  		return -ENOSYS; @@ -2699,7 +2718,7 @@ static int cdrom_ioctl_volread(struct cdrom_device_info *cdi,  	struct cdrom_volctrl volume;  	int ret; -	cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROMVOLREAD\n");  	if (!CDROM_CAN(CDC_PLAY_AUDIO))  		return -ENOSYS; @@ -2718,7 +2737,7 @@ static int cdrom_ioctl_audioctl(struct cdrom_device_info *cdi,  {  	int ret; -	cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n"); +	cd_dbg(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n");  	if (!CDROM_CAN(CDC_PLAY_AUDIO))  		return -ENOSYS; @@ -2729,103 +2748,6 @@ static int cdrom_ioctl_audioctl(struct cdrom_device_info *cdi,  }  /* - * Just about every imaginable ioctl is supported in the Uniform layer - * these days. - * ATAPI / SCSI specific code now mainly resides in mmc_ioctl(). - */ -int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, -		fmode_t mode, unsigned int cmd, unsigned long arg) -{ -	void __user *argp = (void __user *)arg; -	int ret; - -	/* -	 * Try the generic SCSI command ioctl's first. -	 */ -	ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp); -	if (ret != -ENOTTY) -		return ret; - -	switch (cmd) { -	case CDROMMULTISESSION: -		return cdrom_ioctl_multisession(cdi, argp); -	case CDROMEJECT: -		return cdrom_ioctl_eject(cdi); -	case CDROMCLOSETRAY: -		return cdrom_ioctl_closetray(cdi); -	case CDROMEJECT_SW: -		return cdrom_ioctl_eject_sw(cdi, arg); -	case CDROM_MEDIA_CHANGED: -		return cdrom_ioctl_media_changed(cdi, arg); -	case CDROM_SET_OPTIONS: -		return cdrom_ioctl_set_options(cdi, arg); -	case CDROM_CLEAR_OPTIONS: -		return cdrom_ioctl_clear_options(cdi, arg); -	case CDROM_SELECT_SPEED: -		return cdrom_ioctl_select_speed(cdi, arg); -	case CDROM_SELECT_DISC: -		return cdrom_ioctl_select_disc(cdi, arg); -	case CDROMRESET: -		return cdrom_ioctl_reset(cdi, bdev); -	case CDROM_LOCKDOOR: -		return cdrom_ioctl_lock_door(cdi, arg); -	case CDROM_DEBUG: -		return cdrom_ioctl_debug(cdi, arg); -	case CDROM_GET_CAPABILITY: -		return cdrom_ioctl_get_capability(cdi); -	case CDROM_GET_MCN: -		return cdrom_ioctl_get_mcn(cdi, argp); -	case CDROM_DRIVE_STATUS: -		return cdrom_ioctl_drive_status(cdi, arg); -	case CDROM_DISC_STATUS: -		return cdrom_ioctl_disc_status(cdi); -	case CDROM_CHANGER_NSLOTS: -		return cdrom_ioctl_changer_nslots(cdi); -	} - -	/* -	 * 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. -	 */ -	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: -		return cdrom_ioctl_get_subchnl(cdi, argp); -	case CDROMREADTOCHDR: -		return cdrom_ioctl_read_tochdr(cdi, argp); -	case CDROMREADTOCENTRY: -		return cdrom_ioctl_read_tocentry(cdi, argp); -	case CDROMPLAYMSF: -		return cdrom_ioctl_play_msf(cdi, argp); -	case CDROMPLAYTRKIND: -		return cdrom_ioctl_play_trkind(cdi, argp); -	case CDROMVOLCTRL: -		return cdrom_ioctl_volctrl(cdi, argp); -	case CDROMVOLREAD: -		return cdrom_ioctl_volread(cdi, argp); -	case CDROMSTART: -	case CDROMSTOP: -	case CDROMPAUSE: -	case CDROMRESUME: -		return cdrom_ioctl_audioctl(cdi, cmd); -	} - -	return -ENOSYS; -} - -/*   * Required when we need to use READ_10 to issue other than 2048 block   * reads   */ @@ -2854,10 +2776,158 @@ static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size)  	return cdo->generic_packet(cdi, &cgc);  } +static int cdrom_get_track_info(struct cdrom_device_info *cdi, +				__u16 track, __u8 type, track_information *ti) +{ +	struct cdrom_device_ops *cdo = cdi->ops; +	struct packet_command cgc; +	int ret, buflen; + +	init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ); +	cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO; +	cgc.cmd[1] = type & 3; +	cgc.cmd[4] = (track & 0xff00) >> 8; +	cgc.cmd[5] = track & 0xff; +	cgc.cmd[8] = 8; +	cgc.quiet = 1; + +	ret = cdo->generic_packet(cdi, &cgc); +	if (ret) +		return ret; + +	buflen = be16_to_cpu(ti->track_information_length) + +		sizeof(ti->track_information_length); + +	if (buflen > sizeof(track_information)) +		buflen = sizeof(track_information); + +	cgc.cmd[8] = cgc.buflen = buflen; +	ret = cdo->generic_packet(cdi, &cgc); +	if (ret) +		return ret; + +	/* return actual fill size */ +	return buflen; +} + +/* return the last written block on the CD-R media. this is for the udf +   file system. */ +int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written) +{ +	struct cdrom_tocentry toc; +	disc_information di; +	track_information ti; +	__u32 last_track; +	int ret = -1, ti_size; + +	if (!CDROM_CAN(CDC_GENERIC_PACKET)) +		goto use_toc; + +	ret = cdrom_get_disc_info(cdi, &di); +	if (ret < (int)(offsetof(typeof(di), last_track_lsb) +			+ sizeof(di.last_track_lsb))) +		goto use_toc; + +	/* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */ +	last_track = (di.last_track_msb << 8) | di.last_track_lsb; +	ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); +	if (ti_size < (int)offsetof(typeof(ti), track_start)) +		goto use_toc; + +	/* if this track is blank, try the previous. */ +	if (ti.blank) { +		if (last_track == 1) +			goto use_toc; +		last_track--; +		ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); +	} + +	if (ti_size < (int)(offsetof(typeof(ti), track_size) +				+ sizeof(ti.track_size))) +		goto use_toc; + +	/* if last recorded field is valid, return it. */ +	if (ti.lra_v && ti_size >= (int)(offsetof(typeof(ti), last_rec_address) +				+ sizeof(ti.last_rec_address))) { +		*last_written = be32_to_cpu(ti.last_rec_address); +	} else { +		/* make it up instead */ +		*last_written = be32_to_cpu(ti.track_start) + +				be32_to_cpu(ti.track_size); +		if (ti.free_blocks) +			*last_written -= (be32_to_cpu(ti.free_blocks) + 7); +	} +	return 0; + +	/* this is where we end up if the drive either can't do a +	   GPCMD_READ_DISC_INFO or GPCMD_READ_TRACK_RZONE_INFO or if +	   it doesn't give enough information or fails. then we return +	   the toc contents. */ +use_toc: +	toc.cdte_format = CDROM_MSF; +	toc.cdte_track = CDROM_LEADOUT; +	if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &toc))) +		return ret; +	sanitize_format(&toc.cdte_addr, &toc.cdte_format, CDROM_LBA); +	*last_written = toc.cdte_addr.lba; +	return 0; +} + +/* return the next writable block. also for udf file system. */ +static int cdrom_get_next_writable(struct cdrom_device_info *cdi, +				   long *next_writable) +{ +	disc_information di; +	track_information ti; +	__u16 last_track; +	int ret, ti_size; + +	if (!CDROM_CAN(CDC_GENERIC_PACKET)) +		goto use_last_written; + +	ret = cdrom_get_disc_info(cdi, &di); +	if (ret < 0 || ret < offsetof(typeof(di), last_track_lsb) +				+ sizeof(di.last_track_lsb)) +		goto use_last_written; + +	/* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */ +	last_track = (di.last_track_msb << 8) | di.last_track_lsb; +	ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); +	if (ti_size < 0 || ti_size < offsetof(typeof(ti), track_start)) +		goto use_last_written; + +	/* if this track is blank, try the previous. */ +	if (ti.blank) { +		if (last_track == 1) +			goto use_last_written; +		last_track--; +		ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); +		if (ti_size < 0) +			goto use_last_written; +	} + +	/* if next recordable address field is valid, use it. */ +	if (ti.nwa_v && ti_size >= offsetof(typeof(ti), next_writable) +				+ sizeof(ti.next_writable)) { +		*next_writable = be32_to_cpu(ti.next_writable); +		return 0; +	} + +use_last_written: +	ret = cdrom_get_last_written(cdi, next_writable); +	if (ret) { +		*next_writable = 0; +		return ret; +	} else { +		*next_writable += 7; +		return 0; +	} +} +  static noinline int mmc_ioctl_cdrom_read_data(struct cdrom_device_info *cdi, -					void __user *arg, -					struct packet_command *cgc, -					int cmd) +					      void __user *arg, +					      struct packet_command *cgc, +					      int cmd)  {  	struct request_sense sense;  	struct cdrom_msf msf; @@ -2876,7 +2946,8 @@ static noinline int mmc_ioctl_cdrom_read_data(struct cdrom_device_info *cdi,  		blocksize = CD_FRAMESIZE_RAW0;  		break;  	} -	IOCTL_IN(arg, struct cdrom_msf, msf); +	if (copy_from_user(&msf, (struct cdrom_msf __user *)arg, sizeof(msf))) +		return -EFAULT;  	lba = msf_to_lba(msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0);  	/* FIXME: we need upper bound checking, too!! */  	if (lba < 0) @@ -2891,8 +2962,8 @@ static noinline int mmc_ioctl_cdrom_read_data(struct cdrom_device_info *cdi,  	cgc->data_direction = CGC_DATA_READ;  	ret = cdrom_read_block(cdi, cgc, lba, 1, format, blocksize);  	if (ret && sense.sense_key == 0x05 && -		   sense.asc == 0x20 && -		   sense.ascq == 0x00) { +	    sense.asc == 0x20 && +	    sense.ascq == 0x00) {  		/*  		 * SCSI-II devices are not required to support  		 * READ_CD, so let's try switching block size @@ -2913,12 +2984,14 @@ out:  }  static noinline int mmc_ioctl_cdrom_read_audio(struct cdrom_device_info *cdi, -					void __user *arg) +					       void __user *arg)  {  	struct cdrom_read_audio ra;  	int lba; -	IOCTL_IN(arg, struct cdrom_read_audio, ra); +	if (copy_from_user(&ra, (struct cdrom_read_audio __user *)arg, +			   sizeof(ra))) +		return -EFAULT;  	if (ra.addr_format == CDROM_MSF)  		lba = msf_to_lba(ra.addr.msf.minute, @@ -2937,12 +3010,13 @@ static noinline int mmc_ioctl_cdrom_read_audio(struct cdrom_device_info *cdi,  }  static noinline int mmc_ioctl_cdrom_subchannel(struct cdrom_device_info *cdi, -					void __user *arg) +					       void __user *arg)  {  	int ret;  	struct cdrom_subchnl q;  	u_char requested, back; -	IOCTL_IN(arg, struct cdrom_subchnl, q); +	if (copy_from_user(&q, (struct cdrom_subchnl __user *)arg, sizeof(q))) +		return -EFAULT;  	requested = q.cdsc_format;  	if (!((requested == CDROM_MSF) ||  	      (requested == CDROM_LBA))) @@ -2954,19 +3028,21 @@ static noinline int mmc_ioctl_cdrom_subchannel(struct cdrom_device_info *cdi,  	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"); */ +	if (copy_to_user((struct cdrom_subchnl __user *)arg, &q, sizeof(q))) +		return -EFAULT; +	/* cd_dbg(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */  	return 0;  }  static noinline int mmc_ioctl_cdrom_play_msf(struct cdrom_device_info *cdi, -					void __user *arg, -					struct packet_command *cgc) +					     void __user *arg, +					     struct packet_command *cgc)  {  	struct cdrom_device_ops *cdo = cdi->ops;  	struct cdrom_msf msf; -	cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); -	IOCTL_IN(arg, struct cdrom_msf, msf); +	cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); +	if (copy_from_user(&msf, (struct cdrom_msf __user *)arg, sizeof(msf))) +		return -EFAULT;  	cgc->cmd[0] = GPCMD_PLAY_AUDIO_MSF;  	cgc->cmd[3] = msf.cdmsf_min0;  	cgc->cmd[4] = msf.cdmsf_sec0; @@ -2979,13 +3055,14 @@ static noinline int mmc_ioctl_cdrom_play_msf(struct cdrom_device_info *cdi,  }  static noinline int mmc_ioctl_cdrom_play_blk(struct cdrom_device_info *cdi, -					void __user *arg, -					struct packet_command *cgc) +					     void __user *arg, +					     struct packet_command *cgc)  {  	struct cdrom_device_ops *cdo = cdi->ops;  	struct cdrom_blk blk; -	cdinfo(CD_DO_IOCTL, "entering CDROMPLAYBLK\n"); -	IOCTL_IN(arg, struct cdrom_blk, blk); +	cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYBLK\n"); +	if (copy_from_user(&blk, (struct cdrom_blk __user *)arg, sizeof(blk))) +		return -EFAULT;  	cgc->cmd[0] = GPCMD_PLAY_AUDIO_10;  	cgc->cmd[2] = (blk.from >> 24) & 0xff;  	cgc->cmd[3] = (blk.from >> 16) & 0xff; @@ -2998,9 +3075,9 @@ static noinline int mmc_ioctl_cdrom_play_blk(struct cdrom_device_info *cdi,  }  static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi, -					void __user *arg, -					struct packet_command *cgc, -					unsigned int cmd) +					   void __user *arg, +					   struct packet_command *cgc, +					   unsigned int cmd)  {  	struct cdrom_volctrl volctrl;  	unsigned char buffer[32]; @@ -3008,9 +3085,11 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,  	unsigned short offset;  	int ret; -	cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROMVOLUME\n"); -	IOCTL_IN(arg, struct cdrom_volctrl, volctrl); +	if (copy_from_user(&volctrl, (struct cdrom_volctrl __user *)arg, +			   sizeof(volctrl))) +		return -EFAULT;  	cgc->buffer = buffer;  	cgc->buflen = 24; @@ -3030,14 +3109,14 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,  	if (offset + 16 > cgc->buflen) {  		cgc->buflen = offset + 16;  		ret = cdrom_mode_sense(cdi, cgc, -					GPMODE_AUDIO_CTL_PAGE, 0); +				       GPMODE_AUDIO_CTL_PAGE, 0);  		if (ret)  			return ret;  	}  	/* sanity check */  	if ((buffer[offset] & 0x3f) != GPMODE_AUDIO_CTL_PAGE || -			buffer[offset + 1] < 14) +	    buffer[offset + 1] < 14)  		return -EINVAL;  	/* now we have the current volume settings. if it was only @@ -3047,7 +3126,9 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,  		volctrl.channel1 = buffer[offset+11];  		volctrl.channel2 = buffer[offset+13];  		volctrl.channel3 = buffer[offset+15]; -		IOCTL_OUT(arg, struct cdrom_volctrl, volctrl); +		if (copy_to_user((struct cdrom_volctrl __user *)arg, &volctrl, +				 sizeof(volctrl))) +			return -EFAULT;  		return 0;  	} @@ -3069,11 +3150,11 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,  }  static noinline int mmc_ioctl_cdrom_start_stop(struct cdrom_device_info *cdi, -					struct packet_command *cgc, -					int cmd) +					       struct packet_command *cgc, +					       int cmd)  {  	struct cdrom_device_ops *cdo = cdi->ops; -	cdinfo(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n"); +	cd_dbg(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; @@ -3082,11 +3163,11 @@ static noinline int mmc_ioctl_cdrom_start_stop(struct cdrom_device_info *cdi,  }  static noinline int mmc_ioctl_cdrom_pause_resume(struct cdrom_device_info *cdi, -					struct packet_command *cgc, -					int cmd) +						 struct packet_command *cgc, +						 int cmd)  {  	struct cdrom_device_ops *cdo = cdi->ops; -	cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); +	cd_dbg(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; @@ -3094,8 +3175,8 @@ static noinline int mmc_ioctl_cdrom_pause_resume(struct cdrom_device_info *cdi,  }  static noinline int mmc_ioctl_dvd_read_struct(struct cdrom_device_info *cdi, -						void __user *arg, -						struct packet_command *cgc) +					      void __user *arg, +					      struct packet_command *cgc)  {  	int ret;  	dvd_struct *s; @@ -3108,7 +3189,7 @@ static noinline int mmc_ioctl_dvd_read_struct(struct cdrom_device_info *cdi,  	if (!s)  		return -ENOMEM; -	cdinfo(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n"); +	cd_dbg(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n");  	if (copy_from_user(s, arg, size)) {  		kfree(s);  		return -EFAULT; @@ -3126,44 +3207,48 @@ out:  }  static noinline int mmc_ioctl_dvd_auth(struct cdrom_device_info *cdi, -					void __user *arg) +				       void __user *arg)  {  	int ret;  	dvd_authinfo ai;  	if (!CDROM_CAN(CDC_DVD))  		return -ENOSYS; -	cdinfo(CD_DO_IOCTL, "entering DVD_AUTH\n"); -	IOCTL_IN(arg, dvd_authinfo, ai); +	cd_dbg(CD_DO_IOCTL, "entering DVD_AUTH\n"); +	if (copy_from_user(&ai, (dvd_authinfo __user *)arg, sizeof(ai))) +		return -EFAULT;  	ret = dvd_do_auth(cdi, &ai);  	if (ret)  		return ret; -	IOCTL_OUT(arg, dvd_authinfo, ai); +	if (copy_to_user((dvd_authinfo __user *)arg, &ai, sizeof(ai))) +		return -EFAULT;  	return 0;  }  static noinline int mmc_ioctl_cdrom_next_writable(struct cdrom_device_info *cdi, -						void __user *arg) +						  void __user *arg)  {  	int ret;  	long next = 0; -	cdinfo(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n");  	ret = cdrom_get_next_writable(cdi, &next);  	if (ret)  		return ret; -	IOCTL_OUT(arg, long, next); +	if (copy_to_user((long __user *)arg, &next, sizeof(next))) +		return -EFAULT;  	return 0;  }  static noinline int mmc_ioctl_cdrom_last_written(struct cdrom_device_info *cdi, -						void __user *arg) +						 void __user *arg)  {  	int ret;  	long last = 0; -	cdinfo(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n"); +	cd_dbg(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n");  	ret = cdrom_get_last_written(cdi, &last);  	if (ret)  		return ret; -	IOCTL_OUT(arg, long, last); +	if (copy_to_user((long __user *)arg, &last, sizeof(last))) +		return -EFAULT;  	return 0;  } @@ -3212,181 +3297,101 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,  	return -ENOTTY;  } -static int cdrom_get_track_info(struct cdrom_device_info *cdi, __u16 track, __u8 type, -			 track_information *ti) -{ -	struct cdrom_device_ops *cdo = cdi->ops; -	struct packet_command cgc; -	int ret, buflen; - -	init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ); -	cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO; -	cgc.cmd[1] = type & 3; -	cgc.cmd[4] = (track & 0xff00) >> 8; -	cgc.cmd[5] = track & 0xff; -	cgc.cmd[8] = 8; -	cgc.quiet = 1; - -	if ((ret = cdo->generic_packet(cdi, &cgc))) -		return ret; -	 -	buflen = be16_to_cpu(ti->track_information_length) + -		     sizeof(ti->track_information_length); - -	if (buflen > sizeof(track_information)) -		buflen = sizeof(track_information); - -	cgc.cmd[8] = cgc.buflen = buflen; -	if ((ret = cdo->generic_packet(cdi, &cgc))) -		return ret; - -	/* return actual fill size */ -	return buflen; -} - -/* requires CD R/RW */ -static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information *di) +/* + * Just about every imaginable ioctl is supported in the Uniform layer + * these days. + * ATAPI / SCSI specific code now mainly resides in mmc_ioctl(). + */ +int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, +		fmode_t mode, unsigned int cmd, unsigned long arg)  { -	struct cdrom_device_ops *cdo = cdi->ops; -	struct packet_command cgc; -	int ret, buflen; - -	/* set up command and get the disc info */ -	init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ); -	cgc.cmd[0] = GPCMD_READ_DISC_INFO; -	cgc.cmd[8] = cgc.buflen = 2; -	cgc.quiet = 1; - -	if ((ret = cdo->generic_packet(cdi, &cgc))) -		return ret; +	void __user *argp = (void __user *)arg; +	int ret; -	/* not all drives have the same disc_info length, so requeue -	 * packet with the length the drive tells us it can supply +	/* +	 * Try the generic SCSI command ioctl's first.  	 */ -	buflen = be16_to_cpu(di->disc_information_length) + -		     sizeof(di->disc_information_length); - -	if (buflen > sizeof(disc_information)) -		buflen = sizeof(disc_information); - -	cgc.cmd[8] = cgc.buflen = buflen; -	if ((ret = cdo->generic_packet(cdi, &cgc))) +	ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp); +	if (ret != -ENOTTY)  		return ret; -	/* return actual fill size */ -	return buflen; -} - -/* return the last written block on the CD-R media. this is for the udf -   file system. */ -int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written) -{ -	struct cdrom_tocentry toc; -	disc_information di; -	track_information ti; -	__u32 last_track; -	int ret = -1, ti_size; - -	if (!CDROM_CAN(CDC_GENERIC_PACKET)) -		goto use_toc; - -	ret = cdrom_get_disc_info(cdi, &di); -	if (ret < (int)(offsetof(typeof(di), last_track_lsb) -			+ sizeof(di.last_track_lsb))) -		goto use_toc; - -	/* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */ -	last_track = (di.last_track_msb << 8) | di.last_track_lsb; -	ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); -	if (ti_size < (int)offsetof(typeof(ti), track_start)) -		goto use_toc; - -	/* if this track is blank, try the previous. */ -	if (ti.blank) { -		if (last_track==1) -			goto use_toc; -		last_track--; -		ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); -	} - -	if (ti_size < (int)(offsetof(typeof(ti), track_size) -				+ sizeof(ti.track_size))) -		goto use_toc; - -	/* if last recorded field is valid, return it. */ -	if (ti.lra_v && ti_size >= (int)(offsetof(typeof(ti), last_rec_address) -				+ sizeof(ti.last_rec_address))) { -		*last_written = be32_to_cpu(ti.last_rec_address); -	} else { -		/* make it up instead */ -		*last_written = be32_to_cpu(ti.track_start) + -				be32_to_cpu(ti.track_size); -		if (ti.free_blocks) -			*last_written -= (be32_to_cpu(ti.free_blocks) + 7); +	switch (cmd) { +	case CDROMMULTISESSION: +		return cdrom_ioctl_multisession(cdi, argp); +	case CDROMEJECT: +		return cdrom_ioctl_eject(cdi); +	case CDROMCLOSETRAY: +		return cdrom_ioctl_closetray(cdi); +	case CDROMEJECT_SW: +		return cdrom_ioctl_eject_sw(cdi, arg); +	case CDROM_MEDIA_CHANGED: +		return cdrom_ioctl_media_changed(cdi, arg); +	case CDROM_SET_OPTIONS: +		return cdrom_ioctl_set_options(cdi, arg); +	case CDROM_CLEAR_OPTIONS: +		return cdrom_ioctl_clear_options(cdi, arg); +	case CDROM_SELECT_SPEED: +		return cdrom_ioctl_select_speed(cdi, arg); +	case CDROM_SELECT_DISC: +		return cdrom_ioctl_select_disc(cdi, arg); +	case CDROMRESET: +		return cdrom_ioctl_reset(cdi, bdev); +	case CDROM_LOCKDOOR: +		return cdrom_ioctl_lock_door(cdi, arg); +	case CDROM_DEBUG: +		return cdrom_ioctl_debug(cdi, arg); +	case CDROM_GET_CAPABILITY: +		return cdrom_ioctl_get_capability(cdi); +	case CDROM_GET_MCN: +		return cdrom_ioctl_get_mcn(cdi, argp); +	case CDROM_DRIVE_STATUS: +		return cdrom_ioctl_drive_status(cdi, arg); +	case CDROM_DISC_STATUS: +		return cdrom_ioctl_disc_status(cdi); +	case CDROM_CHANGER_NSLOTS: +		return cdrom_ioctl_changer_nslots(cdi);  	} -	return 0; -	/* this is where we end up if the drive either can't do a -	   GPCMD_READ_DISC_INFO or GPCMD_READ_TRACK_RZONE_INFO or if -	   it doesn't give enough information or fails. then we return -	   the toc contents. */ -use_toc: -	toc.cdte_format = CDROM_MSF; -	toc.cdte_track = CDROM_LEADOUT; -	if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &toc))) -		return ret; -	sanitize_format(&toc.cdte_addr, &toc.cdte_format, CDROM_LBA); -	*last_written = toc.cdte_addr.lba; -	return 0; -} - -/* return the next writable block. also for udf file system. */ -static int cdrom_get_next_writable(struct cdrom_device_info *cdi, long *next_writable) -{ -	disc_information di; -	track_information ti; -	__u16 last_track; -	int ret, ti_size; - -	if (!CDROM_CAN(CDC_GENERIC_PACKET)) -		goto use_last_written; - -	ret = cdrom_get_disc_info(cdi, &di); -	if (ret < 0 || ret < offsetof(typeof(di), last_track_lsb) -				+ sizeof(di.last_track_lsb)) -		goto use_last_written; - -	/* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */ -	last_track = (di.last_track_msb << 8) | di.last_track_lsb; -	ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); -	if (ti_size < 0 || ti_size < offsetof(typeof(ti), track_start)) -		goto use_last_written; - -        /* if this track is blank, try the previous. */ -	if (ti.blank) { -		if (last_track == 1) -			goto use_last_written; -		last_track--; -		ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti); -		if (ti_size < 0) -			goto use_last_written; +	/* +	 * 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. +	 */ +	if (CDROM_CAN(CDC_GENERIC_PACKET)) { +		ret = mmc_ioctl(cdi, cmd, arg); +		if (ret != -ENOTTY) +			return ret;  	} -	/* if next recordable address field is valid, use it. */ -	if (ti.nwa_v && ti_size >= offsetof(typeof(ti), next_writable) -				+ sizeof(ti.next_writable)) { -		*next_writable = be32_to_cpu(ti.next_writable); -		return 0; +	/* +	 * Note: most of the cd_dbg() calls are commented out here, +	 * because they fill up the sys log when CD players poll +	 * the drive. +	 */ +	switch (cmd) { +	case CDROMSUBCHNL: +		return cdrom_ioctl_get_subchnl(cdi, argp); +	case CDROMREADTOCHDR: +		return cdrom_ioctl_read_tochdr(cdi, argp); +	case CDROMREADTOCENTRY: +		return cdrom_ioctl_read_tocentry(cdi, argp); +	case CDROMPLAYMSF: +		return cdrom_ioctl_play_msf(cdi, argp); +	case CDROMPLAYTRKIND: +		return cdrom_ioctl_play_trkind(cdi, argp); +	case CDROMVOLCTRL: +		return cdrom_ioctl_volctrl(cdi, argp); +	case CDROMVOLREAD: +		return cdrom_ioctl_volread(cdi, argp); +	case CDROMSTART: +	case CDROMSTOP: +	case CDROMPAUSE: +	case CDROMRESUME: +		return cdrom_ioctl_audioctl(cdi, cmd);  	} -use_last_written: -	if ((ret = cdrom_get_last_written(cdi, next_writable))) { -		*next_writable = 0; -		return ret; -	} else { -		*next_writable += 7; -		return 0; -	} +	return -ENOSYS;  }  EXPORT_SYMBOL(cdrom_get_last_written); @@ -3465,7 +3470,7 @@ static int cdrom_print_info(const char *header, int val, char *info,  	return 0;  } -static int cdrom_sysctl_info(ctl_table *ctl, int write, +static int cdrom_sysctl_info(struct ctl_table *ctl, int write,                             void __user *buffer, size_t *lenp, loff_t *ppos)  {  	int pos; @@ -3578,7 +3583,7 @@ static void cdrom_update_settings(void)  	mutex_unlock(&cdrom_mutex);  } -static int cdrom_sysctl_handler(ctl_table *ctl, int write, +static int cdrom_sysctl_handler(struct ctl_table *ctl, int write,  				void __user *buffer, size_t *lenp, loff_t *ppos)  {  	int ret; @@ -3604,7 +3609,7 @@ static int cdrom_sysctl_handler(ctl_table *ctl, int write,  }  /* Place files in /proc/sys/dev/cdrom */ -static ctl_table cdrom_table[] = { +static struct ctl_table cdrom_table[] = {  	{  		.procname	= "info",  		.data		= &cdrom_sysctl_settings.info,  @@ -3650,7 +3655,7 @@ static ctl_table cdrom_table[] = {  	{ }  }; -static ctl_table cdrom_cdrom_table[] = { +static struct ctl_table cdrom_cdrom_table[] = {  	{  		.procname	= "cdrom",  		.maxlen		= 0, @@ -3661,7 +3666,7 @@ static ctl_table cdrom_cdrom_table[] = {  };  /* Make sure that /proc/sys/dev is there */ -static ctl_table cdrom_root_table[] = { +static struct ctl_table cdrom_root_table[] = {  	{  		.procname	= "dev",  		.maxlen		= 0, | 
