diff options
Diffstat (limited to 'drivers/cdrom')
| -rw-r--r-- | drivers/cdrom/Makefile | 1 | ||||
| -rw-r--r-- | drivers/cdrom/cdrom.c | 1380 | ||||
| -rw-r--r-- | drivers/cdrom/gdrom.c | 46 | ||||
| -rw-r--r-- | drivers/cdrom/viocd.c | 736 | 
4 files changed, 740 insertions, 1423 deletions
diff --git a/drivers/cdrom/Makefile b/drivers/cdrom/Makefile index ecf85fda0fc..8ffde4f8ab9 100644 --- a/drivers/cdrom/Makefile +++ b/drivers/cdrom/Makefile @@ -10,5 +10,4 @@ obj-$(CONFIG_BLK_DEV_SR)	+=              cdrom.o  obj-$(CONFIG_PARIDE_PCD)	+=		cdrom.o  obj-$(CONFIG_CDROM_PKTCDVD)	+=		cdrom.o -obj-$(CONFIG_VIOCD)		+= viocd.o      cdrom.o  obj-$(CONFIG_GDROM)		+= gdrom.o      cdrom.o diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index af13c62dc47..898b84bba28 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -30,7 +30,7 @@    changelog for the 1.x series, David?  2.00  Dec  2, 1997 -- Erik Andersen <andersee@debian.org> -  -- New maintainer! As David A. van Leeuwen has been too busy to activly +  -- New maintainer! As David A. van Leeuwen has been too busy to actively    maintain and improve this driver, I am now carrying on the torch. If    you have a problem with this driver, please feel free to contact me. @@ -267,7 +267,6 @@  #include <linux/module.h>  #include <linux/fs.h> -#include <linux/buffer_head.h>  #include <linux/major.h>  #include <linux/types.h>  #include <linux/errno.h> @@ -286,17 +285,15 @@  #include <asm/uaccess.h>  /* used to tell the module to turn on full debugging messages */ -static int debug; -/* used to keep tray locked at all times */ -static int keeplocked; +static bool debug;  /* default compatibility mode */ -static int autoclose=1; -static int autoeject; -static int lockdoor = 1; +static bool autoclose=1; +static bool autoeject; +static bool lockdoor = 1;  /* will we ever get to use this... sigh. */ -static int check_media_type; +static bool check_media_type;  /* automatically restart mrw format */ -static int mrw_format_restart = 1; +static bool mrw_format_restart = 1;  module_param(debug, bool, 0);  module_param(autoclose, bool, 0);  module_param(autoeject, bool, 0); @@ -315,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. @@ -352,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); @@ -385,112 +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 ); -	ENSURE(media_changed, CDC_MEDIA_CHANGED); -	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 @@ -607,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; @@ -652,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", @@ -670,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)  { @@ -841,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;  } @@ -930,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;  	} @@ -971,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");  - -	/* 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); -	/* Do this on open.  Don't wait for mount, because they might -	    not be mounting, but opening with O_NONBLOCK */ -	check_disk_change(bdev); -	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  @@ -1056,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); @@ -1079,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;  	} @@ -1089,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 @@ -1125,11 +1130,67 @@ 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;  } @@ -1141,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  @@ -1164,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); @@ -1195,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) && !keeplocked) { -			cdinfo(CD_CLOSE, "Unlocking door!\n"); +		if ((cdo->capability & CDC_LOCK) && !cdi->keeplocked) { +			cd_dbg(CD_CLOSE, "Unlocking door!\n");  			cdo->lock_door(cdi, 0);  		}  	} @@ -1264,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; @@ -1294,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;  @@ -1315,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; @@ -1344,11 +1406,14 @@ 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; -	(void) cdi->ops->media_changed(cdi, slot); +	if (cdi->ops->check_events) +		cdi->ops->check_events(cdi, 0, slot); +	else +		cdi->ops->media_changed(cdi, slot);  	if (slot == CDSL_NONE) {  		/* set media changed bits, on both queues */ @@ -1368,7 +1433,7 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot)  	curslot = info->hdr.curslot;  	kfree(info); -	if (cdi->use_count > 1 || keeplocked) { +	if (cdi->use_count > 1 || cdi->keeplocked) {  		if (slot == CDSL_CURRENT) {  	    		return curslot;  		} else { @@ -1392,6 +1457,42 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot)  	return slot;  } +/* + * As cdrom implements an extra ioctl consumer for media changed + * event, it needs to buffer ->check_events() output, such that event + * is not lost for both the usual VFS and ioctl paths. + * cdi->{vfs|ioctl}_events are used to buffer pending events for each + * path. + * + * XXX: Locking is non-existent.  cdi->ops->check_events() can be + * called in parallel and buffering fields are accessed without any + * exclusion.  The original media_changed code had the same problem. + * It might be better to simply deprecate CDROM_MEDIA_CHANGED ioctl + * and remove this cruft altogether.  It doesn't have much usefulness + * at this point. + */ +static void cdrom_update_events(struct cdrom_device_info *cdi, +				unsigned int clearing) +{ +	unsigned int events; + +	events = cdi->ops->check_events(cdi, clearing, CDSL_CURRENT); +	cdi->vfs_events |= events; +	cdi->ioctl_events |= events; +} + +unsigned int cdrom_check_events(struct cdrom_device_info *cdi, +				unsigned int clearing) +{ +	unsigned int events; + +	cdrom_update_events(cdi, clearing); +	events = cdi->vfs_events; +	cdi->vfs_events = 0; +	return events; +} +EXPORT_SYMBOL(cdrom_check_events); +  /* We want to make media_changed accessible to the user through an   * ioctl. The main problem now is that we must double-buffer the   * low-level implementation, to assure that the VFS and the user both @@ -1403,15 +1504,26 @@ int media_changed(struct cdrom_device_info *cdi, int queue)  {  	unsigned int mask = (1 << (queue & 1));  	int ret = !!(cdi->mc_flags & mask); +	bool changed;  	if (!CDROM_CAN(CDC_MEDIA_CHANGED)) -	    return ret; +		return ret; +  	/* changed since last call? */ -	if (cdi->ops->media_changed(cdi, CDSL_CURRENT)) { +	if (cdi->ops->check_events) { +		BUG_ON(!queue);	/* shouldn't be called from VFS path */ +		cdrom_update_events(cdi, DISK_EVENT_MEDIA_CHANGE); +		changed = cdi->ioctl_events & DISK_EVENT_MEDIA_CHANGE; +		cdi->ioctl_events = 0; +	} else +		changed = cdi->ops->media_changed(cdi, CDSL_CURRENT); + +	if (changed) {  		cdi->mc_flags = 0x3;    /* set bit on both queues */  		ret |= 1;  		cdi->media_written = 0;  	} +  	cdi->mc_flags &= ~mask;         /* clear bit */  	return ret;  } @@ -1428,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: @@ -1584,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); @@ -1596,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))) @@ -1607,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))) @@ -1619,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; @@ -1638,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))) @@ -1649,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); @@ -1661,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); @@ -1676,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; @@ -1684,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; @@ -1701,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; @@ -1711,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;  	} @@ -1843,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;  	} @@ -1878,11 +1946,16 @@ static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s,  		goto out;  	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->manufact.len); +	if (s->manufact.len < 0) { +		cd_dbg(CD_WARNING, "Received invalid manufacture info length (%d)\n", +		       s->manufact.len);  		ret = -EIO;  	} else { +		if (s->manufact.len > 2048) { +			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);  	} @@ -1911,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;  	}  } @@ -2063,11 +2136,6 @@ static int cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf,  	if (!nr)  		return -ENOMEM; -	if (!access_ok(VERIFY_WRITE, ubuf, nframes * CD_FRAMESIZE_RAW)) { -		ret = -EFAULT; -		goto out; -	} -  	cgc.data_direction = CGC_DATA_READ;  	while (nframes > 0) {  		if (nr > nframes) @@ -2076,7 +2144,7 @@ static int cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf,  		ret = cdrom_read_block(cdi, &cgc, lba, nr, 1, CD_FRAMESIZE_RAW);  		if (ret)  			break; -		if (__copy_to_user(ubuf, cgc.buffer, CD_FRAMESIZE_RAW * nr)) { +		if (copy_to_user(ubuf, cgc.buffer, CD_FRAMESIZE_RAW * nr)) {  			ret = -EFAULT;  			break;  		} @@ -2084,7 +2152,6 @@ static int cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf,  		nframes -= nr;  		lba += nr;  	} -out:  	kfree(cgc.buffer);  	return ret;  } @@ -2117,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) { @@ -2136,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; @@ -2207,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; @@ -2229,17 +2296,17 @@ 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; -	if (cdi->use_count != 1 || keeplocked) +	if (cdi->use_count != 1 || cdi->keeplocked)  		return -EBUSY;  	if (CDROM_CAN(CDC_LOCK)) {  		int ret = cdi->ops->lock_door(cdi, 0); @@ -2252,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; @@ -2262,11 +2329,11 @@ 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; -	if (keeplocked) +	if (cdi->keeplocked)  		return -EBUSY;  	cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT); @@ -2281,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; @@ -2307,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. @@ -2335,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; @@ -2344,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; @@ -2354,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; @@ -2372,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; @@ -2392,12 +2459,12 @@ 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; -	keeplocked = arg ? 1 : 0; +	cdi->keeplocked = arg ? 1 : 0;  	/*  	 * Don't unlock the door on multiple opens by default, but allow @@ -2411,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; @@ -2421,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);  } @@ -2437,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; @@ -2447,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; @@ -2469,7 +2536,7 @@ static int cdrom_ioctl_drive_status(struct cdrom_device_info *cdi,  /*   * 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 + * CDs are all CDS_DATA_1 or all CDS_AUDIO, etc.  Unfortunately, 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 @@ -2487,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) @@ -2509,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;  } @@ -2526,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; @@ -2546,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;  } @@ -2556,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; @@ -2567,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;  } @@ -2578,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; @@ -2595,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;  } @@ -2604,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; @@ -2619,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; @@ -2636,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; @@ -2651,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; @@ -2670,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; @@ -2681,104 +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; -	struct gendisk *disk = bdev->bd_disk; - -	/* -	 * Try the generic SCSI command ioctl's first. -	 */ -	ret = scsi_cmd_ioctl(disk->queue, disk, 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   */ @@ -2807,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; @@ -2829,13 +2946,14 @@ 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)  		return -EINVAL; -	cgc->buffer = kmalloc(blocksize, GFP_KERNEL); +	cgc->buffer = kzalloc(blocksize, GFP_KERNEL);  	if (cgc->buffer == NULL)  		return -ENOMEM; @@ -2844,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 @@ -2866,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, @@ -2890,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))) @@ -2907,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; @@ -2932,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; @@ -2951,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]; @@ -2961,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; @@ -2983,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 @@ -3000,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;  	} @@ -3022,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; @@ -3035,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; @@ -3047,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; @@ -3061,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; @@ -3079,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;  } @@ -3165,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); @@ -3418,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; @@ -3531,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; @@ -3557,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,  @@ -3603,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, @@ -3614,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, diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index de65915308f..584bc312640 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -395,10 +395,12 @@ static int gdrom_drivestatus(struct cdrom_device_info *cd_info, int ignore)  	return CDS_NO_INFO;  } -static int gdrom_mediachanged(struct cdrom_device_info *cd_info, int ignore) +static unsigned int gdrom_check_events(struct cdrom_device_info *cd_info, +				       unsigned int clearing, int ignore)  {  	/* check the sense key */ -	return (__raw_readb(GDROM_ERROR_REG) & 0xF0) == 0x60; +	return (__raw_readb(GDROM_ERROR_REG) & 0xF0) == 0x60 ? +		DISK_EVENT_MEDIA_CHANGE : 0;  }  /* reset the G1 bus */ @@ -483,7 +485,7 @@ static struct cdrom_device_ops gdrom_ops = {  	.open			= gdrom_open,  	.release		= gdrom_release,  	.drive_status		= gdrom_drivestatus, -	.media_changed		= gdrom_mediachanged, +	.check_events		= gdrom_check_events,  	.get_last_session	= gdrom_get_last_session,  	.reset			= gdrom_hardreset,  	.audio_ioctl		= gdrom_audio_ioctl, @@ -501,17 +503,17 @@ static int gdrom_bdops_open(struct block_device *bdev, fmode_t mode)  	return ret;  } -static int gdrom_bdops_release(struct gendisk *disk, fmode_t mode) +static void gdrom_bdops_release(struct gendisk *disk, fmode_t mode)  {  	mutex_lock(&gdrom_mutex);  	cdrom_release(gd.cd_info, mode);  	mutex_unlock(&gdrom_mutex); -	return 0;  } -static int gdrom_bdops_mediachanged(struct gendisk *disk) +static unsigned int gdrom_bdops_check_events(struct gendisk *disk, +					     unsigned int clearing)  { -	return cdrom_media_changed(gd.cd_info); +	return cdrom_check_events(gd.cd_info, clearing);  }  static int gdrom_bdops_ioctl(struct block_device *bdev, fmode_t mode, @@ -530,7 +532,7 @@ static const struct block_device_operations gdrom_bdops = {  	.owner			= THIS_MODULE,  	.open			= gdrom_bdops_open,  	.release		= gdrom_bdops_release, -	.media_changed		= gdrom_bdops_mediachanged, +	.check_events		= gdrom_bdops_check_events,  	.ioctl			= gdrom_bdops_ioctl,  }; @@ -554,16 +556,16 @@ static irqreturn_t gdrom_dma_interrupt(int irq, void *dev_id)  	return IRQ_HANDLED;  } -static int __devinit gdrom_set_interrupt_handlers(void) +static int gdrom_set_interrupt_handlers(void)  {  	int err;  	err = request_irq(HW_EVENT_GDROM_CMD, gdrom_command_interrupt, -		IRQF_DISABLED, "gdrom_command", &gd); +		0, "gdrom_command", &gd);  	if (err)  		return err;  	err = request_irq(HW_EVENT_GDROM_DMA, gdrom_dma_interrupt, -		IRQF_DISABLED, "gdrom_dma", &gd); +		0, "gdrom_dma", &gd);  	if (err)  		free_irq(HW_EVENT_GDROM_CMD, &gd);  	return err; @@ -600,7 +602,7 @@ static void gdrom_readdisk_dma(struct work_struct *work)  		spin_unlock(&gdrom_lock);  		block = blk_rq_pos(req)/GD_TO_BLK + GD_SESSION_OFFSET;  		block_cnt = blk_rq_sectors(req)/GD_TO_BLK; -		__raw_writel(virt_to_phys(req->buffer), GDROM_DMA_STARTADDR_REG); +		__raw_writel(virt_to_phys(bio_data(req->bio)), GDROM_DMA_STARTADDR_REG);  		__raw_writel(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG);  		__raw_writel(1, GDROM_DMA_DIRECTION_REG);  		__raw_writel(1, GDROM_DMA_ENABLE_REG); @@ -678,7 +680,7 @@ static void gdrom_request(struct request_queue *rq)  }  /* Print string identifying GD ROM device */ -static int __devinit gdrom_outputversion(void) +static int gdrom_outputversion(void)  {  	struct gdrom_id *id;  	char *model_name, *manuf_name, *firmw_ver; @@ -712,7 +714,7 @@ free_id:  }  /* set the default mode for DMA transfer */ -static int __devinit gdrom_init_dma_mode(void) +static int gdrom_init_dma_mode(void)  {  	__raw_writeb(0x13, GDROM_ERROR_REG);  	__raw_writeb(0x22, GDROM_INTSEC_REG); @@ -733,7 +735,7 @@ static int __devinit gdrom_init_dma_mode(void)  	return 0;  } -static void __devinit probe_gdrom_setupcd(void) +static void probe_gdrom_setupcd(void)  {  	gd.cd_info->ops = &gdrom_ops;  	gd.cd_info->capacity = 1; @@ -742,7 +744,7 @@ static void __devinit probe_gdrom_setupcd(void)  		CDC_SELECT_DISC;  } -static void __devinit probe_gdrom_setupdisk(void) +static void probe_gdrom_setupdisk(void)  {  	gd.disk->major = gdrom_major;  	gd.disk->first_minor = 1; @@ -750,7 +752,7 @@ static void __devinit probe_gdrom_setupdisk(void)  	strcpy(gd.disk->disk_name, GDROM_DEV_NAME);  } -static int __devinit probe_gdrom_setupqueue(void) +static int probe_gdrom_setupqueue(void)  {  	blk_queue_logical_block_size(gd.gdrom_rq, GDROM_HARD_SECTOR);  	/* using DMA so memory will need to be contiguous */ @@ -765,7 +767,7 @@ static int __devinit probe_gdrom_setupqueue(void)   * register this as a block device and as compliant with the   * universal CD Rom driver interface   */ -static int __devinit probe_gdrom(struct platform_device *devptr) +static int probe_gdrom(struct platform_device *devptr)  {  	int err;  	/* Start the device */ @@ -828,16 +830,16 @@ probe_fail_cdrom_register:  	del_gendisk(gd.disk);  probe_fail_no_disk:  	kfree(gd.cd_info); +probe_fail_no_mem:  	unregister_blkdev(gdrom_major, GDROM_DEV_NAME);  	gdrom_major = 0; -probe_fail_no_mem:  	pr_warning("Probe failed - error is 0x%X\n", err);  	return err;  } -static int __devexit remove_gdrom(struct platform_device *devptr) +static int remove_gdrom(struct platform_device *devptr)  { -	flush_scheduled_work(); +	flush_work(&work);  	blk_cleanup_queue(gd.gdrom_rq);  	free_irq(HW_EVENT_GDROM_CMD, &gd);  	free_irq(HW_EVENT_GDROM_DMA, &gd); @@ -851,7 +853,7 @@ static int __devexit remove_gdrom(struct platform_device *devptr)  static struct platform_driver gdrom_driver = {  	.probe = probe_gdrom, -	.remove = __devexit_p(remove_gdrom), +	.remove = remove_gdrom,  	.driver = {  			.name = GDROM_DEV_NAME,  	}, diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c deleted file mode 100644 index be73a9b493a..00000000000 --- a/drivers/cdrom/viocd.c +++ /dev/null @@ -1,736 +0,0 @@ -/* -*- linux-c -*- - *  drivers/cdrom/viocd.c - * - *  iSeries Virtual CD Rom - * - *  Authors: Dave Boutcher <boutcher@us.ibm.com> - *           Ryan Arnold <ryanarn@us.ibm.com> - *           Colin Devilbiss <devilbis@us.ibm.com> - *           Stephen Rothwell - * - * (C) Copyright 2000-2004 IBM Corporation - * - * This program is free software;  you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) anyu later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * This routine provides access to CD ROM drives owned and managed by an - * OS/400 partition running on the same box as this Linux partition. - * - * All operations are performed by sending messages back and forth to - * the OS/400 partition. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/major.h> -#include <linux/blkdev.h> -#include <linux/cdrom.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/dma-mapping.h> -#include <linux/module.h> -#include <linux/completion.h> -#include <linux/proc_fs.h> -#include <linux/mutex.h> -#include <linux/seq_file.h> -#include <linux/scatterlist.h> - -#include <asm/vio.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/vio.h> -#include <asm/firmware.h> - -#define VIOCD_DEVICE			"iseries/vcd" - -#define VIOCD_VERS "1.06" - -/* - * Should probably make this a module parameter....sigh - */ -#define VIOCD_MAX_CD	HVMAXARCHITECTEDVIRTUALCDROMS - -static DEFINE_MUTEX(viocd_mutex); -static const struct vio_error_entry viocd_err_table[] = { -	{0x0201, EINVAL, "Invalid Range"}, -	{0x0202, EINVAL, "Invalid Token"}, -	{0x0203, EIO, "DMA Error"}, -	{0x0204, EIO, "Use Error"}, -	{0x0205, EIO, "Release Error"}, -	{0x0206, EINVAL, "Invalid CD"}, -	{0x020C, EROFS, "Read Only Device"}, -	{0x020D, ENOMEDIUM, "Changed or Missing Volume (or Varied Off?)"}, -	{0x020E, EIO, "Optical System Error (Varied Off?)"}, -	{0x02FF, EIO, "Internal Error"}, -	{0x3010, EIO, "Changed Volume"}, -	{0xC100, EIO, "Optical System Error"}, -	{0x0000, 0, NULL}, -}; - -/* - * This is the structure we use to exchange info between driver and interrupt - * handler - */ -struct viocd_waitevent { -	struct completion	com; -	int			rc; -	u16			sub_result; -	int			changed; -}; - -/* this is a lookup table for the true capabilities of a device */ -struct capability_entry { -	char	*type; -	int	capability; -}; - -static struct capability_entry capability_table[] __initdata = { -	{ "6330", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, -	{ "6331", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, -	{ "6333", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, -	{ "632A", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, -	{ "6321", CDC_LOCK }, -	{ "632B", 0 }, -	{ NULL  , CDC_LOCK }, -}; - -/* These are our internal structures for keeping track of devices */ -static int viocd_numdev; - -struct disk_info { -	struct gendisk			*viocd_disk; -	struct cdrom_device_info	viocd_info; -	struct device			*dev; -	const char			*rsrcname; -	const char			*type; -	const char			*model; -}; -static struct disk_info viocd_diskinfo[VIOCD_MAX_CD]; - -#define DEVICE_NR(di)	((di) - &viocd_diskinfo[0]) - -static spinlock_t viocd_reqlock; - -#define MAX_CD_REQ	1 - -/* procfs support */ -static int proc_viocd_show(struct seq_file *m, void *v) -{ -	int i; - -	for (i = 0; i < viocd_numdev; i++) { -		seq_printf(m, "viocd device %d is iSeries resource %10.10s" -				"type %4.4s, model %3.3s\n", -				i, viocd_diskinfo[i].rsrcname, -				viocd_diskinfo[i].type, -				viocd_diskinfo[i].model); -	} -	return 0; -} - -static int proc_viocd_open(struct inode *inode, struct file *file) -{ -	return single_open(file, proc_viocd_show, NULL); -} - -static const struct file_operations proc_viocd_operations = { -	.owner		= THIS_MODULE, -	.open		= proc_viocd_open, -	.read		= seq_read, -	.llseek		= seq_lseek, -	.release	= single_release, -}; - -static int viocd_blk_open(struct block_device *bdev, fmode_t mode) -{ -	struct disk_info *di = bdev->bd_disk->private_data; -	int ret; - -	mutex_lock(&viocd_mutex); -	ret = cdrom_open(&di->viocd_info, bdev, mode); -	mutex_unlock(&viocd_mutex); - -	return ret; -} - -static int viocd_blk_release(struct gendisk *disk, fmode_t mode) -{ -	struct disk_info *di = disk->private_data; -	mutex_lock(&viocd_mutex); -	cdrom_release(&di->viocd_info, mode); -	mutex_unlock(&viocd_mutex); -	return 0; -} - -static int viocd_blk_ioctl(struct block_device *bdev, fmode_t mode, -		unsigned cmd, unsigned long arg) -{ -	struct disk_info *di = bdev->bd_disk->private_data; -	int ret; - -	mutex_lock(&viocd_mutex); -	ret = cdrom_ioctl(&di->viocd_info, bdev, mode, cmd, arg); -	mutex_unlock(&viocd_mutex); - -	return ret; -} - -static int viocd_blk_media_changed(struct gendisk *disk) -{ -	struct disk_info *di = disk->private_data; -	return cdrom_media_changed(&di->viocd_info); -} - -static const struct block_device_operations viocd_fops = { -	.owner =		THIS_MODULE, -	.open =			viocd_blk_open, -	.release =		viocd_blk_release, -	.ioctl =		viocd_blk_ioctl, -	.media_changed =	viocd_blk_media_changed, -}; - -static int viocd_open(struct cdrom_device_info *cdi, int purpose) -{ -        struct disk_info *diskinfo = cdi->handle; -	int device_no = DEVICE_NR(diskinfo); -	HvLpEvent_Rc hvrc; -	struct viocd_waitevent we; - -	init_completion(&we.com); -	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, -			HvLpEvent_Type_VirtualIo, -			viomajorsubtype_cdio | viocdopen, -			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, -			viopath_sourceinst(viopath_hostLp), -			viopath_targetinst(viopath_hostLp), -			(u64)&we, VIOVERSION << 16, ((u64)device_no << 48), -			0, 0, 0); -	if (hvrc != 0) { -		pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n", -			   (int)hvrc); -		return -EIO; -	} - -	wait_for_completion(&we.com); - -	if (we.rc) { -		const struct vio_error_entry *err = -			vio_lookup_rc(viocd_err_table, we.sub_result); -		pr_warning("bad rc %d:0x%04X on open: %s\n", -			   we.rc, we.sub_result, err->msg); -		return -err->errno; -	} - -	return 0; -} - -static void viocd_release(struct cdrom_device_info *cdi) -{ -	int device_no = DEVICE_NR((struct disk_info *)cdi->handle); -	HvLpEvent_Rc hvrc; - -	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, -			HvLpEvent_Type_VirtualIo, -			viomajorsubtype_cdio | viocdclose, -			HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck, -			viopath_sourceinst(viopath_hostLp), -			viopath_targetinst(viopath_hostLp), 0, -			VIOVERSION << 16, ((u64)device_no << 48), 0, 0, 0); -	if (hvrc != 0) -		pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n", -			   (int)hvrc); -} - -/* Send a read or write request to OS/400 */ -static int send_request(struct request *req) -{ -	HvLpEvent_Rc hvrc; -	struct disk_info *diskinfo = req->rq_disk->private_data; -	u64 len; -	dma_addr_t dmaaddr; -	int direction; -	u16 cmd; -	struct scatterlist sg; - -	BUG_ON(req->nr_phys_segments > 1); - -	if (rq_data_dir(req) == READ) { -		direction = DMA_FROM_DEVICE; -		cmd = viomajorsubtype_cdio | viocdread; -	} else { -		direction = DMA_TO_DEVICE; -		cmd = viomajorsubtype_cdio | viocdwrite; -	} - -	sg_init_table(&sg, 1); -        if (blk_rq_map_sg(req->q, req, &sg) == 0) { -		pr_warning("error setting up scatter/gather list\n"); -		return -1; -	} - -	if (dma_map_sg(diskinfo->dev, &sg, 1, direction) == 0) { -		pr_warning("error allocating sg tce\n"); -		return -1; -	} -	dmaaddr = sg_dma_address(&sg); -	len = sg_dma_len(&sg); - -	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, -			HvLpEvent_Type_VirtualIo, cmd, -			HvLpEvent_AckInd_DoAck, -			HvLpEvent_AckType_ImmediateAck, -			viopath_sourceinst(viopath_hostLp), -			viopath_targetinst(viopath_hostLp), -			(u64)req, VIOVERSION << 16, -			((u64)DEVICE_NR(diskinfo) << 48) | dmaaddr, -			(u64)blk_rq_pos(req) * 512, len, 0); -	if (hvrc != HvLpEvent_Rc_Good) { -		pr_warning("hv error on op %d\n", (int)hvrc); -		return -1; -	} - -	return 0; -} - -static int rwreq; - -static void do_viocd_request(struct request_queue *q) -{ -	struct request *req; - -	while ((rwreq == 0) && ((req = blk_fetch_request(q)) != NULL)) { -		if (req->cmd_type != REQ_TYPE_FS) -			__blk_end_request_all(req, -EIO); -		else if (send_request(req) < 0) { -			pr_warning("unable to send message to OS/400!\n"); -			__blk_end_request_all(req, -EIO); -		} else -			rwreq++; -	} -} - -static int viocd_media_changed(struct cdrom_device_info *cdi, int disc_nr) -{ -	struct viocd_waitevent we; -	HvLpEvent_Rc hvrc; -	int device_no = DEVICE_NR((struct disk_info *)cdi->handle); - -	init_completion(&we.com); - -	/* Send the open event to OS/400 */ -	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, -			HvLpEvent_Type_VirtualIo, -			viomajorsubtype_cdio | viocdcheck, -			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, -			viopath_sourceinst(viopath_hostLp), -			viopath_targetinst(viopath_hostLp), -			(u64)&we, VIOVERSION << 16, ((u64)device_no << 48), -			0, 0, 0); -	if (hvrc != 0) { -		pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n", -			   (int)hvrc); -		return -EIO; -	} - -	wait_for_completion(&we.com); - -	/* Check the return code.  If bad, assume no change */ -	if (we.rc) { -		const struct vio_error_entry *err = -			vio_lookup_rc(viocd_err_table, we.sub_result); -		pr_warning("bad rc %d:0x%04X on check_change: %s; Assuming no change\n", -			   we.rc, we.sub_result, err->msg); -		return 0; -	} - -	return we.changed; -} - -static int viocd_lock_door(struct cdrom_device_info *cdi, int locking) -{ -	HvLpEvent_Rc hvrc; -	u64 device_no = DEVICE_NR((struct disk_info *)cdi->handle); -	/* NOTE: flags is 1 or 0 so it won't overwrite the device_no */ -	u64 flags = !!locking; -	struct viocd_waitevent we; - -	init_completion(&we.com); - -	/* Send the lockdoor event to OS/400 */ -	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, -			HvLpEvent_Type_VirtualIo, -			viomajorsubtype_cdio | viocdlockdoor, -			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, -			viopath_sourceinst(viopath_hostLp), -			viopath_targetinst(viopath_hostLp), -			(u64)&we, VIOVERSION << 16, -			(device_no << 48) | (flags << 32), 0, 0, 0); -	if (hvrc != 0) { -		pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n", -			   (int)hvrc); -		return -EIO; -	} - -	wait_for_completion(&we.com); - -	if (we.rc != 0) -		return -EIO; -	return 0; -} - -static int viocd_packet(struct cdrom_device_info *cdi, -		struct packet_command *cgc) -{ -	unsigned int buflen = cgc->buflen; -	int ret = -EIO; - -	switch (cgc->cmd[0]) { -	case GPCMD_READ_DISC_INFO: -		{ -			disc_information *di = (disc_information *)cgc->buffer; - -			if (buflen >= 2) { -				di->disc_information_length = cpu_to_be16(1); -				ret = 0; -			} -			if (buflen >= 3) -				di->erasable = -					(cdi->ops->capability & ~cdi->mask -					 & (CDC_DVD_RAM | CDC_RAM)) != 0; -		} -		break; -	case GPCMD_GET_CONFIGURATION: -		if (cgc->cmd[3] == CDF_RWRT) { -			struct rwrt_feature_desc *rfd = (struct rwrt_feature_desc *)(cgc->buffer + sizeof(struct feature_header)); - -			if ((buflen >= -			     (sizeof(struct feature_header) + sizeof(*rfd))) && -			    (cdi->ops->capability & ~cdi->mask -			     & (CDC_DVD_RAM | CDC_RAM))) { -				rfd->feature_code = cpu_to_be16(CDF_RWRT); -				rfd->curr = 1; -				ret = 0; -			} -		} -		break; -	default: -		if (cgc->sense) { -			/* indicate Unknown code */ -			cgc->sense->sense_key = 0x05; -			cgc->sense->asc = 0x20; -			cgc->sense->ascq = 0x00; -		} -		break; -	} - -	cgc->stat = ret; -	return ret; -} - -static void restart_all_queues(int first_index) -{ -	int i; - -	for (i = first_index + 1; i < viocd_numdev; i++) -		if (viocd_diskinfo[i].viocd_disk) -			blk_run_queue(viocd_diskinfo[i].viocd_disk->queue); -	for (i = 0; i <= first_index; i++) -		if (viocd_diskinfo[i].viocd_disk) -			blk_run_queue(viocd_diskinfo[i].viocd_disk->queue); -} - -/* This routine handles incoming CD LP events */ -static void vio_handle_cd_event(struct HvLpEvent *event) -{ -	struct viocdlpevent *bevent; -	struct viocd_waitevent *pwe; -	struct disk_info *di; -	unsigned long flags; -	struct request *req; - - -	if (event == NULL) -		/* Notification that a partition went away! */ -		return; -	/* First, we should NEVER get an int here...only acks */ -	if (hvlpevent_is_int(event)) { -		pr_warning("Yikes! got an int in viocd event handler!\n"); -		if (hvlpevent_need_ack(event)) { -			event->xRc = HvLpEvent_Rc_InvalidSubtype; -			HvCallEvent_ackLpEvent(event); -		} -	} - -	bevent = (struct viocdlpevent *)event; - -	switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { -	case viocdopen: -		if (event->xRc == 0) { -			di = &viocd_diskinfo[bevent->disk]; -			blk_queue_logical_block_size(di->viocd_disk->queue, -						     bevent->block_size); -			set_capacity(di->viocd_disk, -					bevent->media_size * -					bevent->block_size / 512); -		} -		/* FALLTHROUGH !! */ -	case viocdlockdoor: -		pwe = (struct viocd_waitevent *)event->xCorrelationToken; -return_complete: -		pwe->rc = event->xRc; -		pwe->sub_result = bevent->sub_result; -		complete(&pwe->com); -		break; - -	case viocdcheck: -		pwe = (struct viocd_waitevent *)event->xCorrelationToken; -		pwe->changed = bevent->flags; -		goto return_complete; - -	case viocdclose: -		break; - -	case viocdwrite: -	case viocdread: -		/* -		 * Since this is running in interrupt mode, we need to -		 * make sure we're not stepping on any global I/O operations -		 */ -		di = &viocd_diskinfo[bevent->disk]; -		spin_lock_irqsave(&viocd_reqlock, flags); -		dma_unmap_single(di->dev, bevent->token, bevent->len, -				((event->xSubtype & VIOMINOR_SUBTYPE_MASK) == viocdread) -				?  DMA_FROM_DEVICE : DMA_TO_DEVICE); -		req = (struct request *)bevent->event.xCorrelationToken; -		rwreq--; - -		if (event->xRc != HvLpEvent_Rc_Good) { -			const struct vio_error_entry *err = -				vio_lookup_rc(viocd_err_table, -						bevent->sub_result); -			pr_warning("request %p failed with rc %d:0x%04X: %s\n", -				   req, event->xRc, -				   bevent->sub_result, err->msg); -			__blk_end_request_all(req, -EIO); -		} else -			__blk_end_request_all(req, 0); - -		/* restart handling of incoming requests */ -		spin_unlock_irqrestore(&viocd_reqlock, flags); -		restart_all_queues(bevent->disk); -		break; - -	default: -		pr_warning("message with invalid subtype %0x04X!\n", -			   event->xSubtype & VIOMINOR_SUBTYPE_MASK); -		if (hvlpevent_need_ack(event)) { -			event->xRc = HvLpEvent_Rc_InvalidSubtype; -			HvCallEvent_ackLpEvent(event); -		} -	} -} - -static int viocd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, -			     void *arg) -{ -	return -EINVAL; -} - -static struct cdrom_device_ops viocd_dops = { -	.open = viocd_open, -	.release = viocd_release, -	.media_changed = viocd_media_changed, -	.lock_door = viocd_lock_door, -	.generic_packet = viocd_packet, -	.audio_ioctl = viocd_audio_ioctl, -	.capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_RAM -}; - -static int find_capability(const char *type) -{ -	struct capability_entry *entry; - -	for(entry = capability_table; entry->type; ++entry) -		if(!strncmp(entry->type, type, 4)) -			break; -	return entry->capability; -} - -static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id) -{ -	struct gendisk *gendisk; -	int deviceno; -	struct disk_info *d; -	struct cdrom_device_info *c; -	struct request_queue *q; -	struct device_node *node = vdev->dev.of_node; - -	deviceno = vdev->unit_address; -	if (deviceno >= VIOCD_MAX_CD) -		return -ENODEV; -	if (!node) -		return -ENODEV; - -	if (deviceno >= viocd_numdev) -		viocd_numdev = deviceno + 1; - -	d = &viocd_diskinfo[deviceno]; -	d->rsrcname = of_get_property(node, "linux,vio_rsrcname", NULL); -	d->type = of_get_property(node, "linux,vio_type", NULL); -	d->model = of_get_property(node, "linux,vio_model", NULL); - -	c = &d->viocd_info; - -	c->ops = &viocd_dops; -	c->speed = 4; -	c->capacity = 1; -	c->handle = d; -	c->mask = ~find_capability(d->type); -	sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno); - -	if (register_cdrom(c) != 0) { -		pr_warning("Cannot register viocd CD-ROM %s!\n", c->name); -		goto out; -	} -	pr_info("cd %s is iSeries resource %10.10s type %4.4s, model %3.3s\n", -		c->name, d->rsrcname, d->type, d->model); -	q = blk_init_queue(do_viocd_request, &viocd_reqlock); -	if (q == NULL) { -		pr_warning("Cannot allocate queue for %s!\n", c->name); -		goto out_unregister_cdrom; -	} -	gendisk = alloc_disk(1); -	if (gendisk == NULL) { -		pr_warning("Cannot create gendisk for %s!\n", c->name); -		goto out_cleanup_queue; -	} -	gendisk->major = VIOCD_MAJOR; -	gendisk->first_minor = deviceno; -	strncpy(gendisk->disk_name, c->name, -			sizeof(gendisk->disk_name)); -	blk_queue_max_segments(q, 1); -	blk_queue_max_hw_sectors(q, 4096 / 512); -	gendisk->queue = q; -	gendisk->fops = &viocd_fops; -	gendisk->flags = GENHD_FL_CD|GENHD_FL_REMOVABLE; -	set_capacity(gendisk, 0); -	gendisk->private_data = d; -	d->viocd_disk = gendisk; -	d->dev = &vdev->dev; -	gendisk->driverfs_dev = d->dev; -	add_disk(gendisk); -	return 0; - -out_cleanup_queue: -	blk_cleanup_queue(q); -out_unregister_cdrom: -	unregister_cdrom(c); -out: -	return -ENODEV; -} - -static int viocd_remove(struct vio_dev *vdev) -{ -	struct disk_info *d = &viocd_diskinfo[vdev->unit_address]; - -	unregister_cdrom(&d->viocd_info); -	del_gendisk(d->viocd_disk); -	blk_cleanup_queue(d->viocd_disk->queue); -	put_disk(d->viocd_disk); -	return 0; -} - -/** - * viocd_device_table: Used by vio.c to match devices that we - * support. - */ -static struct vio_device_id viocd_device_table[] __devinitdata = { -	{ "block", "IBM,iSeries-viocd" }, -	{ "", "" } -}; -MODULE_DEVICE_TABLE(vio, viocd_device_table); - -static struct vio_driver viocd_driver = { -	.id_table = viocd_device_table, -	.probe = viocd_probe, -	.remove = viocd_remove, -	.driver = { -		.name = "viocd", -		.owner = THIS_MODULE, -	} -}; - -static int __init viocd_init(void) -{ -	int ret = 0; - -	if (!firmware_has_feature(FW_FEATURE_ISERIES)) -		return -ENODEV; - -	if (viopath_hostLp == HvLpIndexInvalid) { -		vio_set_hostlp(); -		/* If we don't have a host, bail out */ -		if (viopath_hostLp == HvLpIndexInvalid) -			return -ENODEV; -	} - -	pr_info("vers " VIOCD_VERS ", hosting partition %d\n", viopath_hostLp); - -	if (register_blkdev(VIOCD_MAJOR, VIOCD_DEVICE) != 0) { -		pr_warning("Unable to get major %d for %s\n", -			   VIOCD_MAJOR, VIOCD_DEVICE); -		return -EIO; -	} - -	ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio, -			MAX_CD_REQ + 2); -	if (ret) { -		pr_warning("error opening path to host partition %d\n", -			   viopath_hostLp); -		goto out_unregister; -	} - -	/* Initialize our request handler */ -	vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event); - -	spin_lock_init(&viocd_reqlock); - -	ret = vio_register_driver(&viocd_driver); -	if (ret) -		goto out_free_info; - -	proc_create("iSeries/viocd", S_IFREG|S_IRUGO, NULL, -		    &proc_viocd_operations); -	return 0; - -out_free_info: -	vio_clearHandler(viomajorsubtype_cdio); -	viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); -out_unregister: -	unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE); -	return ret; -} - -static void __exit viocd_exit(void) -{ -	remove_proc_entry("iSeries/viocd", NULL); -	vio_unregister_driver(&viocd_driver); -	viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); -	vio_clearHandler(viomajorsubtype_cdio); -	unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE); -} - -module_init(viocd_init); -module_exit(viocd_exit); -MODULE_LICENSE("GPL");  | 
