Commit 737f1cd8 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-5.16/cdrom-2021-10-29' of git://git.kernel.dk/linux-block

Pull CDROM updates from Jens Axboe:
 "On behalf of Phillip, here are the CDROM updates for the 5.16-rc1
  merge window:

   - Add ioctl for improved media change detection (Lukas)

   - Reformat some documentation (Phillip)

   - Redundant variable removal (luo)"

* tag 'for-5.16/cdrom-2021-10-29' of git://git.kernel.dk/linux-block:
  cdrom: Remove redundant variable and its assignment
  cdrom: docs: reformat table in Documentation/userspace-api/ioctl/cdrom.rst
  drivers/cdrom: improved ioctl for media change detection
parents fcaec17b bbc3925c
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -907,6 +907,17 @@ commands can be identified by the underscores in their names.
	specifies the slot for which the information is given. The special
	value *CDSL_CURRENT* requests that information about the currently
	selected slot be returned.
`CDROM_TIMED_MEDIA_CHANGE`
	Checks whether the disc has been changed since a user supplied time
	and returns the time of the last disc change.

	*arg* is a pointer to a *cdrom_timed_media_change_info* struct.
	*arg->last_media_change* may be set by calling code to signal
	the timestamp of the last known media change (by the caller).
	Upon successful return, this ioctl call will set
	*arg->last_media_change* to the latest media change timestamp (in ms)
	known by the kernel/driver and set *arg->has_changed* to 1 if
	that timestamp is more recent than the timestamp set by the caller.
`CDROM_DRIVE_STATUS`
	Returns the status of the drive by a call to
	*drive_status()*. Return values are defined in cdrom_drive_status_.
+58 −55
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@ in drivers/cdrom/cdrom.c and drivers/block/scsi_ioctl.c
ioctl values are listed in <linux/cdrom.h>.  As of this writing, they
are as follows:

	======================	===============================================
	========================  ===============================================
	CDROMPAUSE		  Pause Audio Operation
	CDROMRESUME		  Resume paused Audio Operation
	CDROMPLAYMSF		  Play Audio MSF (struct cdrom_msf)
@@ -54,6 +54,9 @@ are as follows:
	CDROM_SELECT_SPEED	  Set the CD-ROM speed
	CDROM_SELECT_DISC	  Select disc (for juke-boxes)
	CDROM_MEDIA_CHANGED	  Check is media changed
	CDROM_TIMED_MEDIA_CHANGE  Check if media changed
				  since given time
				  (struct cdrom_timed_media_change_info)
	CDROM_DRIVE_STATUS	  Get tray position, etc.
	CDROM_DISC_STATUS	  Get disc type, etc.
	CDROM_CHANGER_NSLOTS	  Get number of slots
@@ -67,7 +70,7 @@ are as follows:
	CDROM_SEND_PACKET	  send a packet to the drive
	CDROM_NEXT_WRITABLE	  get next writable block
	CDROM_LAST_WRITTEN	  get last block written on disc
	======================	===============================================
	========================  ===============================================


The information that follows was determined from reading kernel source
+57 −6
Original line number Diff line number Diff line
@@ -344,6 +344,12 @@ static void cdrom_sysctl_register(void);

static LIST_HEAD(cdrom_list);

static void signal_media_change(struct cdrom_device_info *cdi)
{
	cdi->mc_flags = 0x3; /* set media changed bits, on both queues */
	cdi->last_media_change_ms = ktime_to_ms(ktime_get());
}

int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi,
			       struct packet_command *cgc)
{
@@ -616,6 +622,7 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi)
	ENSURE(cdo, generic_packet, CDC_GENERIC_PACKET);
	cdi->mc_flags = 0;
	cdi->options = CDO_USE_FFLAGS;
	cdi->last_media_change_ms = ktime_to_ms(ktime_get());

	if (autoclose == 1 && CDROM_CAN(CDC_CLOSE_TRAY))
		cdi->options |= (int) CDO_AUTO_CLOSE;
@@ -864,7 +871,7 @@ static void cdrom_mmc3_profile(struct cdrom_device_info *cdi)
{
	struct packet_command cgc;
	char buffer[32];
	int ret, mmc3_profile;
	int mmc3_profile;

	init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);

@@ -874,7 +881,7 @@ static void cdrom_mmc3_profile(struct cdrom_device_info *cdi)
	cgc.cmd[8] = sizeof(buffer);		/* Allocation Length */
	cgc.quiet = 1;

	if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
	if (cdi->ops->generic_packet(cdi, &cgc))
		mmc3_profile = 0xffff;
	else
		mmc3_profile = (buffer[6] << 8) | buffer[7];
@@ -1421,8 +1428,7 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot)
		cdi->ops->check_events(cdi, 0, slot);

	if (slot == CDSL_NONE) {
		/* set media changed bits, on both queues */
		cdi->mc_flags = 0x3;
		signal_media_change(cdi);
		return cdrom_load_unload(cdi, -1);
	}

@@ -1455,7 +1461,7 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot)
		slot = curslot;

	/* set media changed bits on both queues */
	cdi->mc_flags = 0x3;
	signal_media_change(cdi);
	if ((ret = cdrom_load_unload(cdi, slot)))
		return ret;

@@ -1521,7 +1527,7 @@ int media_changed(struct cdrom_device_info *cdi, int queue)
	cdi->ioctl_events = 0;

	if (changed) {
		cdi->mc_flags = 0x3;    /* set bit on both queues */
		signal_media_change(cdi);
		ret |= 1;
		cdi->media_written = 0;
	}
@@ -2336,6 +2342,49 @@ static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi,
	return ret;
}

/*
 * Media change detection with timing information.
 *
 * arg is a pointer to a cdrom_timed_media_change_info struct.
 * arg->last_media_change may be set by calling code to signal
 * the timestamp (in ms) of the last known media change (by the caller).
 * Upon successful return, ioctl call will set arg->last_media_change
 * to the latest media change timestamp known by the kernel/driver
 * and set arg->has_changed to 1 if that timestamp is more recent
 * than the timestamp set by the caller.
 */
static int cdrom_ioctl_timed_media_change(struct cdrom_device_info *cdi,
		unsigned long arg)
{
	int ret;
	struct cdrom_timed_media_change_info __user *info;
	struct cdrom_timed_media_change_info tmp_info;

	if (!CDROM_CAN(CDC_MEDIA_CHANGED))
		return -ENOSYS;

	info = (struct cdrom_timed_media_change_info __user *)arg;
	cd_dbg(CD_DO_IOCTL, "entering CDROM_TIMED_MEDIA_CHANGE\n");

	ret = cdrom_ioctl_media_changed(cdi, CDSL_CURRENT);
	if (ret < 0)
		return ret;

	if (copy_from_user(&tmp_info, info, sizeof(tmp_info)) != 0)
		return -EFAULT;

	tmp_info.media_flags = 0;
	if (tmp_info.last_media_change - cdi->last_media_change_ms < 0)
		tmp_info.media_flags |= MEDIA_CHANGED_FLAG;

	tmp_info.last_media_change = cdi->last_media_change_ms;

	if (copy_to_user(info, &tmp_info, sizeof(*info)) != 0)
		return -EFAULT;

	return 0;
}

static int cdrom_ioctl_set_options(struct cdrom_device_info *cdi,
		unsigned long arg)
{
@@ -3313,6 +3362,8 @@ int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev,
		return cdrom_ioctl_eject_sw(cdi, arg);
	case CDROM_MEDIA_CHANGED:
		return cdrom_ioctl_media_changed(cdi, arg);
	case CDROM_TIMED_MEDIA_CHANGE:
		return cdrom_ioctl_timed_media_change(cdi, arg);
	case CDROM_SET_OPTIONS:
		return cdrom_ioctl_set_options(cdi, arg);
	case CDROM_CLEAR_OPTIONS:
+1 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ struct cdrom_device_info {
	int for_data;
	int (*exit)(struct cdrom_device_info *);
	int mrw_mode_page;
	__s64 last_media_change_ms;
};

struct cdrom_device_ops {
+19 −0
Original line number Diff line number Diff line
@@ -147,6 +147,8 @@
#define CDROM_NEXT_WRITABLE	0x5394	/* get next writable block */
#define CDROM_LAST_WRITTEN	0x5395	/* get last block written on disc */

#define CDROM_TIMED_MEDIA_CHANGE   0x5396  /* get the timestamp of the last media change */

/*******************************************************
 * CDROM IOCTL structures
 *******************************************************/
@@ -295,6 +297,23 @@ struct cdrom_generic_command
	};
};

/* This struct is used by CDROM_TIMED_MEDIA_CHANGE */
struct cdrom_timed_media_change_info {
	__s64	last_media_change;	/* Timestamp of the last detected media
					 * change in ms. May be set by caller,
					 * updated upon successful return of
					 * ioctl.
					 */
	__u64	media_flags;		/* Flags returned by ioctl to indicate
					 * media status.
					 */
};
#define MEDIA_CHANGED_FLAG	0x1	/* Last detected media change was more
					 * recent than last_media_change set by
					 * caller.
					 */
/* other bits of media_flags available for future use */

/*
 * A CD-ROM physical sector size is 2048, 2052, 2056, 2324, 2332, 2336, 
 * 2340, or 2352 bytes long.