]> err.no Git - linux-2.6/commitdiff
[PATCH] cleanup cdrom_ioctl
authorChristoph Hellwig <hch@lst.de>
Thu, 23 Mar 2006 11:00:14 +0000 (03:00 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Thu, 23 Mar 2006 15:38:09 +0000 (07:38 -0800)
Add a small helper for each ioctl to cut down cdrom_ioctl to a readable
size.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Cc: Acked-by: Jens Axboe <axboe@suse.de>
Signed-off-by: Benoit Boissinot <benoit.boissinot@ens-lyon.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
drivers/cdrom/cdrom.c

index 879bbc26ce96241aa4622234db66f627d95c486a..d6653fc03b926e9816e916106b5f3b579f32b537 100644 (file)
@@ -2196,395 +2196,592 @@ retry:
        return cdrom_read_cdda_old(cdi, ubuf, lba, nframes);    
 }
 
-/* Just about every imaginable ioctl is supported in the Uniform layer
- * these days. ATAPI / SCSI specific code now mainly resides in
- * mmc_ioct().
- */
-int cdrom_ioctl(struct file * file, struct cdrom_device_info *cdi,
-               struct inode *ip, unsigned int cmd, unsigned long arg)
+static int cdrom_ioctl_multisession(struct cdrom_device_info *cdi,
+               void __user *argp)
 {
-       struct cdrom_device_ops *cdo = cdi->ops;
+       struct cdrom_multisession ms_info;
+       u8 requested_format;
        int ret;
 
-       /* Try the generic SCSI command ioctl's first.. */
-       ret = scsi_cmd_ioctl(file, ip->i_bdev->bd_disk, cmd, (void __user *)arg);
-       if (ret != -ENOTTY)
+       cdinfo(CD_DO_IOCTL, "entering CDROMMULTISESSION\n");
+
+       if (!(cdi->ops->capability & CDC_MULTI_SESSION))
+               return -ENOSYS;
+
+       if (copy_from_user(&ms_info, argp, sizeof(ms_info)))
+               return -EFAULT;
+
+       requested_format = ms_info.addr_format;
+       if (requested_format != CDROM_MSF && requested_format != CDROM_LBA)
+               return -EINVAL;
+       ms_info.addr_format = CDROM_LBA;
+
+       ret = cdi->ops->get_last_session(cdi, &ms_info);
+       if (ret)
                return ret;
 
-       /* the first few commands do not deal with audio drive_info, but
-          only with routines in cdrom device operations. */
-       switch (cmd) {
-       case CDROMMULTISESSION: {
-               struct cdrom_multisession ms_info;
-               u_char requested_format;
-               cdinfo(CD_DO_IOCTL, "entering CDROMMULTISESSION\n"); 
-                if (!(cdo->capability & CDC_MULTI_SESSION))
-                        return -ENOSYS;
-               IOCTL_IN(arg, struct cdrom_multisession, ms_info);
-               requested_format = ms_info.addr_format;
-               if (!((requested_format == CDROM_MSF) ||
-                       (requested_format == CDROM_LBA)))
-                               return -EINVAL;
-               ms_info.addr_format = CDROM_LBA;
-               if ((ret=cdo->get_last_session(cdi, &ms_info)))
+       sanitize_format(&ms_info.addr, &ms_info.addr_format, requested_format);
+
+       if (copy_to_user(argp, &ms_info, sizeof(ms_info)))
+               return -EFAULT;
+
+       cdinfo(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");
+
+       if (!CDROM_CAN(CDC_OPEN_TRAY))
+               return -ENOSYS;
+       if (cdi->use_count != 1 || keeplocked)
+               return -EBUSY;
+       if (CDROM_CAN(CDC_LOCK)) {
+               int ret = cdi->ops->lock_door(cdi, 0);
+               if (ret)
                        return ret;
-               sanitize_format(&ms_info.addr, &ms_info.addr_format,
-                               requested_format);
-               IOCTL_OUT(arg, struct cdrom_multisession, ms_info);
-               cdinfo(CD_DO_IOCTL, "CDROMMULTISESSION successful\n"); 
-               return 0;
-               }
+       }
 
-       case CDROMEJECT: {
-               cdinfo(CD_DO_IOCTL, "entering CDROMEJECT\n"); 
-               if (!CDROM_CAN(CDC_OPEN_TRAY))
-                       return -ENOSYS;
-               if (cdi->use_count != 1 || keeplocked)
-                       return -EBUSY;
-               if (CDROM_CAN(CDC_LOCK))
-                       if ((ret=cdo->lock_door(cdi, 0)))
-                               return ret;
+       return cdi->ops->tray_move(cdi, 1);
+}
 
-               return cdo->tray_move(cdi, 1);
-               }
+static int cdrom_ioctl_closetray(struct cdrom_device_info *cdi)
+{
+       cdinfo(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n");
 
-       case CDROMCLOSETRAY: {
-               cdinfo(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n"); 
-               if (!CDROM_CAN(CDC_CLOSE_TRAY))
-                       return -ENOSYS;
-               return cdo->tray_move(cdi, 0);
-               }
+       if (!CDROM_CAN(CDC_CLOSE_TRAY))
+               return -ENOSYS;
+       return cdi->ops->tray_move(cdi, 0);
+}
 
-       case CDROMEJECT_SW: {
-               cdinfo(CD_DO_IOCTL, "entering CDROMEJECT_SW\n"); 
-               if (!CDROM_CAN(CDC_OPEN_TRAY))
-                       return -ENOSYS;
-               if (keeplocked)
-                       return -EBUSY;
-               cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT);
-               if (arg)
-                       cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT;
-               return 0;
-               }
+static int cdrom_ioctl_eject_sw(struct cdrom_device_info *cdi,
+               unsigned long arg)
+{
+       cdinfo(CD_DO_IOCTL, "entering CDROMEJECT_SW\n");
 
-       case CDROM_MEDIA_CHANGED: {
-               struct cdrom_changer_info *info;
-               int changed;
+       if (!CDROM_CAN(CDC_OPEN_TRAY))
+               return -ENOSYS;
+       if (keeplocked)
+               return -EBUSY;
 
-               cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n"); 
-               if (!CDROM_CAN(CDC_MEDIA_CHANGED))
-                       return -ENOSYS;
+       cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT);
+       if (arg)
+               cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT;
+       return 0;
+}
 
-               /* cannot select disc or select current disc */
-               if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT)
-                       return media_changed(cdi, 1);
+static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi,
+               unsigned long arg)
+{
+       struct cdrom_changer_info *info;
+       int ret;
 
-               if ((unsigned int)arg >= cdi->capacity)
-                       return -EINVAL;
+       cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n");
 
-               info = kmalloc(sizeof(*info), GFP_KERNEL);
-               if (!info)
-                       return -ENOMEM;
+       if (!CDROM_CAN(CDC_MEDIA_CHANGED))
+               return -ENOSYS;
 
-               if ((ret = cdrom_read_mech_status(cdi, info))) {
-                       kfree(info);
-                       return ret;
-               }
+       /* cannot select disc or select current disc */
+       if (!CDROM_CAN(CDC_SELECT_DISC) || arg == CDSL_CURRENT)
+               return media_changed(cdi, 1);
 
-               changed = info->slots[arg].change;
-               kfree(info);
-               return changed;
-               }
+       if ((unsigned int)arg >= cdi->capacity)
+               return -EINVAL;
 
-       case CDROM_SET_OPTIONS: {
-               cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n"); 
-               /* options need to be in sync with capability. too late for
-                  that, so we have to check each one separately... */
-               switch (arg) {
-               case CDO_USE_FFLAGS:
-               case CDO_CHECK_TYPE:
-                       break;
-               case CDO_LOCK:
-                       if (!CDROM_CAN(CDC_LOCK))
-                               return -ENOSYS;
-                       break;
-               case 0:
-                       return cdi->options;
-               /* default is basically CDO_[AUTO_CLOSE|AUTO_EJECT] */
-               default:
-                       if (!CDROM_CAN(arg))
-                               return -ENOSYS;
-               }
-               cdi->options |= (int) arg;
-               return cdi->options;
-               }
+       info = kmalloc(sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
 
-       case CDROM_CLEAR_OPTIONS: {
-               cdinfo(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n"); 
-               cdi->options &= ~(int) arg;
-               return cdi->options;
-               }
+       ret = cdrom_read_mech_status(cdi, info);
+       if (!ret)
+               ret = info->slots[arg].change;
+       kfree(info);
+       return ret;
+}
 
-       case CDROM_SELECT_SPEED: {
-               cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n"); 
-               if (!CDROM_CAN(CDC_SELECT_SPEED))
-                       return -ENOSYS;
-               return cdo->select_speed(cdi, arg);
-               }
+static int cdrom_ioctl_set_options(struct cdrom_device_info *cdi,
+               unsigned long arg)
+{
+       cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n");
 
-       case CDROM_SELECT_DISC: {
-               cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n"); 
-               if (!CDROM_CAN(CDC_SELECT_DISC))
+       /*
+        * Options need to be in sync with capability.
+        * Too late for that, so we have to check each one separately.
+        */
+       switch (arg) {
+       case CDO_USE_FFLAGS:
+       case CDO_CHECK_TYPE:
+               break;
+       case CDO_LOCK:
+               if (!CDROM_CAN(CDC_LOCK))
+                       return -ENOSYS;
+               break;
+       case 0:
+               return cdi->options;
+       /* default is basically CDO_[AUTO_CLOSE|AUTO_EJECT] */
+       default:
+               if (!CDROM_CAN(arg))
                        return -ENOSYS;
+       }
+       cdi->options |= (int) arg;
+       return cdi->options;
+}
 
-                if ((arg != CDSL_CURRENT) && (arg != CDSL_NONE))
-                       if ((int)arg >= cdi->capacity)
-                               return -EINVAL;
-
-               /* cdo->select_disc is a hook to allow a driver-specific
-                * way of seleting disc.  However, since there is no
-                * equiv hook for cdrom_slot_status this may not 
-                * actually be useful...
-                */
-               if (cdo->select_disc != NULL)
-                       return cdo->select_disc(cdi, arg);
-
-               /* no driver specific select_disc(), call our own */
-               cdinfo(CD_CHANGER, "Using generic cdrom_select_disc()\n"); 
-               return cdrom_select_disc(cdi, arg);
-               }
+static int cdrom_ioctl_clear_options(struct cdrom_device_info *cdi,
+               unsigned long arg)
+{
+       cdinfo(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n");
 
-       case CDROMRESET: {
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EACCES;
-               cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n");
-               if (!CDROM_CAN(CDC_RESET))
-                       return -ENOSYS;
-               invalidate_bdev(ip->i_bdev, 0);
-               return cdo->reset(cdi);
-               }
+       cdi->options &= ~(int) arg;
+       return cdi->options;
+}
 
-       case CDROM_LOCKDOOR: {
-               cdinfo(CD_DO_IOCTL, "%socking door.\n", arg ? "L" : "Unl");
-               if (!CDROM_CAN(CDC_LOCK))
-                       return -EDRIVE_CANT_DO_THIS;
-               keeplocked = arg ? 1 : 0;
-               /* don't unlock the door on multiple opens,but allow root
-                * to do so */
-               if ((cdi->use_count != 1) && !arg && !capable(CAP_SYS_ADMIN))
-                       return -EBUSY;
-               return cdo->lock_door(cdi, arg);
-               }
+static int cdrom_ioctl_select_speed(struct cdrom_device_info *cdi,
+               unsigned long arg)
+{
+       cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n");
 
-       case CDROM_DEBUG: {
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EACCES;
-               cdinfo(CD_DO_IOCTL, "%sabling debug.\n", arg ? "En" : "Dis");
-               debug = arg ? 1 : 0;
-               return debug;
-               }
+       if (!CDROM_CAN(CDC_SELECT_SPEED))
+               return -ENOSYS;
+       return cdi->ops->select_speed(cdi, arg);
+}
 
-       case CDROM_GET_CAPABILITY: {
-               cdinfo(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n");
-               return (cdo->capability & ~cdi->mask);
-               }
+static int cdrom_ioctl_select_disc(struct cdrom_device_info *cdi,
+               unsigned long arg)
+{
+       cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n");
+
+       if (!CDROM_CAN(CDC_SELECT_DISC))
+               return -ENOSYS;
+
+       if (arg != CDSL_CURRENT && arg != CDSL_NONE) {
+               if ((int)arg >= cdi->capacity)
+                       return -EINVAL;
+       }
+
+       /*
+        * ->select_disc is a hook to allow a driver-specific way of
+        * seleting disc.  However, since there is no equivalent hook for
+        * cdrom_slot_status this may not actually be useful...
+        */
+       if (cdi->ops->select_disc)
+               return cdi->ops->select_disc(cdi, arg);
+
+       cdinfo(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");
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+       if (!CDROM_CAN(CDC_RESET))
+               return -ENOSYS;
+       invalidate_bdev(bdev, 0);
+       return cdi->ops->reset(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");
+
+       if (!CDROM_CAN(CDC_LOCK))
+               return -EDRIVE_CANT_DO_THIS;
+
+       keeplocked = arg ? 1 : 0;
+
+       /*
+        * Don't unlock the door on multiple opens by default, but allow
+        * root to do so.
+        */
+       if (cdi->use_count != 1 && !arg && !capable(CAP_SYS_ADMIN))
+               return -EBUSY;
+       return cdi->ops->lock_door(cdi, arg);
+}
+
+static int cdrom_ioctl_debug(struct cdrom_device_info *cdi,
+               unsigned long arg)
+{
+       cdinfo(CD_DO_IOCTL, "%sabling debug.\n", arg ? "En" : "Dis");
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+       debug = arg ? 1 : 0;
+       return debug;
+}
 
-/* The following function is implemented, although very few audio
+static int cdrom_ioctl_get_capability(struct cdrom_device_info *cdi)
+{
+       cdinfo(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n");
+       return (cdi->ops->capability & ~cdi->mask);
+}
+
+/*
+ * The following function is implemented, although very few audio
  * discs give Universal Product Code information, which should just be
  * the Medium Catalog Number on the box.  Note, that the way the code
  * is written on the CD is /not/ uniform across all discs!
  */
-       case CDROM_GET_MCN: {
-               struct cdrom_mcn mcn;
-               cdinfo(CD_DO_IOCTL, "entering CDROM_GET_MCN\n"); 
-               if (!(cdo->capability & CDC_MCN))
-                       return -ENOSYS;
-               if ((ret=cdo->get_mcn(cdi, &mcn)))
-                       return ret;
-               IOCTL_OUT(arg, struct cdrom_mcn, mcn);
-               cdinfo(CD_DO_IOCTL, "CDROM_GET_MCN successful\n"); 
-               return 0;
-               }
+static int cdrom_ioctl_get_mcn(struct cdrom_device_info *cdi,
+               void __user *argp)
+{
+       struct cdrom_mcn mcn;
+       int ret;
 
-       case CDROM_DRIVE_STATUS: {
-               cdinfo(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n"); 
-               if (!(cdo->capability & CDC_DRIVE_STATUS))
-                       return -ENOSYS;
-               if (!CDROM_CAN(CDC_SELECT_DISC))
-                       return cdo->drive_status(cdi, CDSL_CURRENT);
-                if ((arg == CDSL_CURRENT) || (arg == CDSL_NONE)) 
-                       return cdo->drive_status(cdi, CDSL_CURRENT);
-               if (((int)arg >= cdi->capacity))
-                       return -EINVAL;
-               return cdrom_slot_status(cdi, arg);
-               }
+       cdinfo(CD_DO_IOCTL, "entering CDROM_GET_MCN\n");
 
-       /* Ok, this is where problems start.  The current interface for the
-          CDROM_DISC_STATUS ioctl is flawed.  It makes the false assumption
-          that CDs are all CDS_DATA_1 or all CDS_AUDIO, etc.  Unfortunatly,
-          while this is often the case, it is also very common for CDs to
-          have some tracks with data, and some tracks with audio.  Just 
-          because I feel like it, I declare the following to be the best
-          way to cope.  If the CD has ANY data tracks on it, it will be
-          returned as a data CD.  If it has any XA tracks, I will return
-          it as that.  Now I could simplify this interface by combining these 
-          returns with the above, but this more clearly demonstrates
-          the problem with the current interface.  Too bad this wasn't 
-          designed to use bitmasks...         -Erik 
-
-          Well, now we have the option CDS_MIXED: a mixed-type CD. 
-          User level programmers might feel the ioctl is not very useful.
-                                               ---david
-       */
-       case CDROM_DISC_STATUS: {
-               tracktype tracks;
-               cdinfo(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n"); 
-               cdrom_count_tracks(cdi, &tracks);
-               if (tracks.error) 
-                       return(tracks.error);
-
-               /* Policy mode on */
-               if (tracks.audio > 0) {
-                       if (tracks.data==0 && tracks.cdi==0 && tracks.xa==0) 
-                               return CDS_AUDIO;
-                       else
-                               return CDS_MIXED;
-               }
-               if (tracks.cdi > 0) return CDS_XA_2_2;
-               if (tracks.xa > 0) return CDS_XA_2_1;
-               if (tracks.data > 0) return CDS_DATA_1;
-               /* Policy mode off */
+       if (!(cdi->ops->capability & CDC_MCN))
+               return -ENOSYS;
+       ret = cdi->ops->get_mcn(cdi, &mcn);
+       if (ret)
+               return ret;
 
-               cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognize!\n");
-               return CDS_NO_INFO;
-               }
+       if (copy_to_user(argp, &mcn, sizeof(mcn)))
+               return -EFAULT;
+       cdinfo(CD_DO_IOCTL, "CDROM_GET_MCN successful\n");
+       return 0;
+}
 
-       case CDROM_CHANGER_NSLOTS: {
-               cdinfo(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n"); 
-               return cdi->capacity;
-               }
+static int cdrom_ioctl_drive_status(struct cdrom_device_info *cdi,
+               unsigned long arg)
+{
+       cdinfo(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n");
+
+       if (!(cdi->ops->capability & CDC_DRIVE_STATUS))
+               return -ENOSYS;
+       if (!CDROM_CAN(CDC_SELECT_DISC) ||
+           (arg == CDSL_CURRENT || arg == CDSL_NONE))
+               return cdi->ops->drive_status(cdi, CDSL_CURRENT);
+       if (((int)arg >= cdi->capacity))
+               return -EINVAL;
+       return cdrom_slot_status(cdi, arg);
+}
+
+/*
+ * Ok, this is where problems start.  The current interface for the
+ * CDROM_DISC_STATUS ioctl is flawed.  It makes the false assumption that
+ * CDs are all CDS_DATA_1 or all CDS_AUDIO, etc.  Unfortunatly, while this
+ * is often the case, it is also very common for CDs to have some tracks
+ * with data, and some tracks with audio.  Just because I feel like it,
+ * I declare the following to be the best way to cope.  If the CD has ANY
+ * data tracks on it, it will be returned as a data CD.  If it has any XA
+ * tracks, I will return it as that.  Now I could simplify this interface
+ * by combining these  returns with the above, but this more clearly
+ * demonstrates the problem with the current interface.  Too bad this
+ * wasn't designed to use bitmasks...         -Erik
+ *
+ * Well, now we have the option CDS_MIXED: a mixed-type CD.
+ * User level programmers might feel the ioctl is not very useful.
+ *                                     ---david
+ */
+static int cdrom_ioctl_disc_status(struct cdrom_device_info *cdi)
+{
+       tracktype tracks;
+
+       cdinfo(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n");
+
+       cdrom_count_tracks(cdi, &tracks);
+       if (tracks.error)
+               return tracks.error;
+
+       /* Policy mode on */
+       if (tracks.audio > 0) {
+               if (!tracks.data && !tracks.cdi && !tracks.xa)
+                       return CDS_AUDIO;
+               else
+                       return CDS_MIXED;
+       }
+
+       if (tracks.cdi > 0)
+               return CDS_XA_2_2;
+       if (tracks.xa > 0)
+               return CDS_XA_2_1;
+       if (tracks.data > 0)
+               return CDS_DATA_1;
+       /* Policy mode off */
+
+       cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognize!\n");
+       return CDS_NO_INFO;
+}
+
+static int cdrom_ioctl_changer_nslots(struct cdrom_device_info *cdi)
+{
+       cdinfo(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n");
+       return cdi->capacity;
+}
+
+static int cdrom_ioctl_get_subchnl(struct cdrom_device_info *cdi,
+               void __user *argp)
+{
+       struct cdrom_subchnl q;
+       u8 requested, back;
+       int ret;
+
+       /* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/
+
+       if (!CDROM_CAN(CDC_PLAY_AUDIO))
+               return -ENOSYS;
+       if (copy_from_user(&q, argp, sizeof(q)))
+               return -EFAULT;
+
+       requested = q.cdsc_format;
+       if (requested != CDROM_MSF && requested != CDROM_LBA)
+               return -EINVAL;
+       q.cdsc_format = CDROM_MSF;
+
+       ret = cdi->ops->audio_ioctl(cdi, CDROMSUBCHNL, &q);
+       if (ret)
+               return ret;
+
+       back = q.cdsc_format; /* local copy */
+       sanitize_format(&q.cdsc_absaddr, &back, requested);
+       sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested);
+
+       if (copy_to_user(argp, &q, sizeof(q)))
+               return -EFAULT;
+       /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */
+       return 0;
+}
+
+static int cdrom_ioctl_read_tochdr(struct cdrom_device_info *cdi,
+               void __user *argp)
+{
+       struct cdrom_tochdr header;
+       int ret;
+
+       /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */
+
+       if (!CDROM_CAN(CDC_PLAY_AUDIO))
+               return -ENOSYS;
+       if (copy_from_user(&header, argp, sizeof(header)))
+               return -EFAULT;
+
+       ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header);
+       if (ret)
+               return ret;
+
+       if (copy_to_user(argp, &header, sizeof(header)))
+               return -EFAULT;
+       /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */
+       return 0;
+}
+
+static int cdrom_ioctl_read_tocentry(struct cdrom_device_info *cdi,
+               void __user *argp)
+{
+       struct cdrom_tocentry entry;
+       u8 requested_format;
+       int ret;
+
+       /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */
+
+       if (!CDROM_CAN(CDC_PLAY_AUDIO))
+               return -ENOSYS;
+       if (copy_from_user(&entry, argp, sizeof(entry)))
+               return -EFAULT;
+
+       requested_format = entry.cdte_format;
+       if (requested_format != CDROM_MSF && requested_format != CDROM_LBA)
+               return -EINVAL;
+       /* make interface to low-level uniform */
+       entry.cdte_format = CDROM_MSF;
+       ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry);
+       if (ret)
+               return ret;
+       sanitize_format(&entry.cdte_addr, &entry.cdte_format, requested_format);
+
+       if (copy_to_user(argp, &entry, sizeof(entry)))
+               return -EFAULT;
+       /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */
+       return 0;
+}
+
+static int cdrom_ioctl_play_msf(struct cdrom_device_info *cdi,
+               void __user *argp)
+{
+       struct cdrom_msf msf;
+
+       cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");
+
+       if (!CDROM_CAN(CDC_PLAY_AUDIO))
+               return -ENOSYS;
+       if (copy_from_user(&msf, argp, sizeof(msf)))
+               return -EFAULT;
+       return cdi->ops->audio_ioctl(cdi, CDROMPLAYMSF, &msf);
+}
+
+static int cdrom_ioctl_play_trkind(struct cdrom_device_info *cdi,
+               void __user *argp)
+{
+       struct cdrom_ti ti;
+       int ret;
+
+       cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n");
+
+       if (!CDROM_CAN(CDC_PLAY_AUDIO))
+               return -ENOSYS;
+       if (copy_from_user(&ti, argp, sizeof(ti)))
+               return -EFAULT;
+
+       ret = check_for_audio_disc(cdi, cdi->ops);
+       if (ret)
+               return ret;
+       return cdi->ops->audio_ioctl(cdi, CDROMPLAYTRKIND, &ti);
+}
+static int cdrom_ioctl_volctrl(struct cdrom_device_info *cdi,
+               void __user *argp)
+{
+       struct cdrom_volctrl volume;
+
+       cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n");
+
+       if (!CDROM_CAN(CDC_PLAY_AUDIO))
+               return -ENOSYS;
+       if (copy_from_user(&volume, argp, sizeof(volume)))
+               return -EFAULT;
+       return cdi->ops->audio_ioctl(cdi, CDROMVOLCTRL, &volume);
+}
+
+static int cdrom_ioctl_volread(struct cdrom_device_info *cdi,
+               void __user *argp)
+{
+       struct cdrom_volctrl volume;
+       int ret;
+
+       cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n");
+
+       if (!CDROM_CAN(CDC_PLAY_AUDIO))
+               return -ENOSYS;
+
+       ret = cdi->ops->audio_ioctl(cdi, CDROMVOLREAD, &volume);
+       if (ret)
+               return ret;
+
+       if (copy_to_user(argp, &volume, sizeof(volume)))
+               return -EFAULT;
+       return 0;
+}
+
+static int cdrom_ioctl_audioctl(struct cdrom_device_info *cdi,
+               unsigned int cmd)
+{
+       int ret;
+
+       cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n");
+
+       if (!CDROM_CAN(CDC_PLAY_AUDIO))
+               return -ENOSYS;
+       ret = check_for_audio_disc(cdi, cdi->ops);
+       if (ret)
+               return ret;
+       return cdi->ops->audio_ioctl(cdi, cmd, NULL);
+}
+
+/*
+ * 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 file * file, struct cdrom_device_info *cdi,
+               struct inode *ip, unsigned int cmd, unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+       int ret;
+
+       /*
+        * Try the generic SCSI command ioctl's first.
+        */
+       ret = scsi_cmd_ioctl(file, ip->i_bdev->bd_disk, 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, ip->i_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. */
+       /*
+        * 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) {
+               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. */
+       /*
+        * Note: most of the cdinfo() calls are commented out here,
+        * because they fill up the sys log when CD players poll
+        * the drive.
+        */
        switch (cmd) {
-       case CDROMSUBCHNL: {
-               struct cdrom_subchnl q;
-               u_char requested, back;
-               if (!CDROM_CAN(CDC_PLAY_AUDIO))
-                       return -ENOSYS;
-               /* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/ 
-               IOCTL_IN(arg, struct cdrom_subchnl, q);
-               requested = q.cdsc_format;
-               if (!((requested == CDROM_MSF) ||
-                     (requested == CDROM_LBA)))
-                       return -EINVAL;
-               q.cdsc_format = CDROM_MSF;
-               if ((ret=cdo->audio_ioctl(cdi, cmd, &q)))
-                       return ret;
-               back = q.cdsc_format; /* local copy */
-               sanitize_format(&q.cdsc_absaddr, &back, requested);
-               sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested);
-               IOCTL_OUT(arg, struct cdrom_subchnl, q);
-               /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */ 
-               return 0;
-               }
-       case CDROMREADTOCHDR: {
-               struct cdrom_tochdr header;
-               if (!CDROM_CAN(CDC_PLAY_AUDIO))
-                       return -ENOSYS;
-               /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */ 
-               IOCTL_IN(arg, struct cdrom_tochdr, header);
-               if ((ret=cdo->audio_ioctl(cdi, cmd, &header)))
-                       return ret;
-               IOCTL_OUT(arg, struct cdrom_tochdr, header);
-               /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */ 
-               return 0;
-               }
-       case CDROMREADTOCENTRY: {
-               struct cdrom_tocentry entry;
-               u_char requested_format;
-               if (!CDROM_CAN(CDC_PLAY_AUDIO))
-                       return -ENOSYS;
-               /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */ 
-               IOCTL_IN(arg, struct cdrom_tocentry, entry);
-               requested_format = entry.cdte_format;
-               if (!((requested_format == CDROM_MSF) || 
-                       (requested_format == CDROM_LBA)))
-                               return -EINVAL;
-               /* make interface to low-level uniform */
-               entry.cdte_format = CDROM_MSF;
-               if ((ret=cdo->audio_ioctl(cdi, cmd, &entry)))
-                       return ret;
-               sanitize_format(&entry.cdte_addr,
-               &entry.cdte_format, requested_format);
-               IOCTL_OUT(arg, struct cdrom_tocentry, entry);
-               /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */ 
-               return 0;
-               }
-       case CDROMPLAYMSF: {
-               struct cdrom_msf msf;
-               if (!CDROM_CAN(CDC_PLAY_AUDIO))
-                       return -ENOSYS;
-               cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); 
-               IOCTL_IN(arg, struct cdrom_msf, msf);
-               return cdo->audio_ioctl(cdi, cmd, &msf);
-               }
-       case CDROMPLAYTRKIND: {
-               struct cdrom_ti ti;
-               if (!CDROM_CAN(CDC_PLAY_AUDIO))
-                       return -ENOSYS;
-               cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n"); 
-               IOCTL_IN(arg, struct cdrom_ti, ti);
-               CHECKAUDIO;
-               return cdo->audio_ioctl(cdi, cmd, &ti);
-               }
-       case CDROMVOLCTRL: {
-               struct cdrom_volctrl volume;
-               if (!CDROM_CAN(CDC_PLAY_AUDIO))
-                       return -ENOSYS;
-               cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n"); 
-               IOCTL_IN(arg, struct cdrom_volctrl, volume);
-               return cdo->audio_ioctl(cdi, cmd, &volume);
-               }
-       case CDROMVOLREAD: {
-               struct cdrom_volctrl volume;
-               if (!CDROM_CAN(CDC_PLAY_AUDIO))
-                       return -ENOSYS;
-               cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n"); 
-               if ((ret=cdo->audio_ioctl(cdi, cmd, &volume)))
-                       return ret;
-               IOCTL_OUT(arg, struct cdrom_volctrl, volume);
-               return 0;
-               }
+       case 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: {
-               if (!CDROM_CAN(CDC_PLAY_AUDIO))
-                       return -ENOSYS;
-               cdinfo(CD_DO_IOCTL, "doing audio ioctl (start/stop/pause/resume)\n"); 
-               CHECKAUDIO;
-               return cdo->audio_ioctl(cdi, cmd, NULL);
-               }
-       } /* switch */
+       case CDROMRESUME:
+               return cdrom_ioctl_audioctl(cdi, cmd);
+       }
 
-       /* do the device specific ioctls */
+       /*
+        * Finally, do the device specific ioctls
+        */
        if (CDROM_CAN(CDC_IOCTLS))
-               return cdo->dev_ioctl(cdi, cmd, arg);
-       
+               return cdi->ops->dev_ioctl(cdi, cmd, arg);
+
        return -ENOSYS;
 }