ARM64: dts: rk3366-tb: add regulator-ramp-delay of vdd_arm
[firefly-linux-kernel-4.4.55.git] / drivers / cdrom / cdrom.c
index d620b44957454a80fcf444d10cb967e66fb9d7d5..c206ccda899b388fe7856424078c505f99c87830 100644 (file)
@@ -312,36 +312,24 @@ static const char *mrw_format_status[] = {
 
 static const char *mrw_address_space[] = { "DMA", "GAA" };
 
-#if (ERRLOGMASK!=CD_NOTHING)
-#define cdinfo(type, fmt, args...)                     \
+#if (ERRLOGMASK != CD_NOTHING)
+#define cd_dbg(type, fmt, ...)                         \
 do {                                                   \
        if ((ERRLOGMASK & type) || debug == 1)          \
-               pr_info(fmt, ##args);                   \
+               pr_debug(fmt, ##__VA_ARGS__);           \
 } while (0)
 #else
-#define cdinfo(type, fmt, args...)                     \
+#define cd_dbg(type, fmt, ...)                         \
 do {                                                   \
        if (0 && (ERRLOGMASK & type) || debug == 1)     \
-               pr_info(fmt, ##args);                   \
+               pr_debug(fmt, ##__VA_ARGS__);           \
 } while (0)
 #endif
 
-/* These are used to simplify getting data in from and back to user land */
-#define IOCTL_IN(arg, type, in)                                        \
-       if (copy_from_user(&(in), (type __user *) (arg), sizeof (in)))  \
-               return -EFAULT;
-
-#define IOCTL_OUT(arg, type, out) \
-       if (copy_to_user((type __user *) (arg), &(out), sizeof (out)))  \
-               return -EFAULT;
-
 /* The (cdo->capability & ~cdi->mask & CDC_XXX) construct was used in
    a lot of places. This macro makes the code more clear. */
 #define CDROM_CAN(type) (cdi->ops->capability & ~cdi->mask & (type))
 
-/* used in the audio ioctls */
-#define CHECKAUDIO if ((ret=check_for_audio_disc(cdi, cdo))) return ret
-
 /*
  * Another popular OS uses 7 seconds as the hard timeout for default
  * commands, so it is a good choice for us as well.
@@ -349,21 +337,6 @@ do {                                                       \
 #define CDROM_DEF_TIMEOUT      (7 * HZ)
 
 /* Not-exported routines. */
-static int open_for_data(struct cdrom_device_info * cdi);
-static int check_for_audio_disc(struct cdrom_device_info * cdi,
-                        struct cdrom_device_ops * cdo);
-static void sanitize_format(union cdrom_addr *addr, 
-               u_char * curr, u_char requested);
-static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
-                    unsigned long arg);
-
-int cdrom_get_last_written(struct cdrom_device_info *, long *);
-static int cdrom_get_next_writable(struct cdrom_device_info *, long *);
-static void cdrom_count_tracks(struct cdrom_device_info *, tracktype*);
-
-static int cdrom_mrw_exit(struct cdrom_device_info *cdi);
-
-static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information *di);
 
 static void cdrom_sysctl_register(void);
 
@@ -382,113 +355,65 @@ static int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi,
        return -EIO;
 }
 
-/* This macro makes sure we don't have to check on cdrom_device_ops
- * existence in the run-time routines below. Change_capability is a
- * hack to have the capability flags defined const, while we can still
- * change it here without gcc complaining at every line.
- */
-#define ENSURE(call, bits) if (cdo->call == NULL) *change_capability &= ~(bits)
-
-int register_cdrom(struct cdrom_device_info *cdi)
-{
-       static char banner_printed;
-        struct cdrom_device_ops *cdo = cdi->ops;
-        int *change_capability = (int *)&cdo->capability; /* hack */
-
-       cdinfo(CD_OPEN, "entering register_cdrom\n"); 
-
-       if (cdo->open == NULL || cdo->release == NULL)
-               return -EINVAL;
-       if (!banner_printed) {
-               pr_info("Uniform CD-ROM driver " REVISION "\n");
-               banner_printed = 1;
-               cdrom_sysctl_register();
-       }
-
-       ENSURE(drive_status, CDC_DRIVE_STATUS );
-       if (cdo->check_events == NULL && cdo->media_changed == NULL)
-               *change_capability = ~(CDC_MEDIA_CHANGED | CDC_SELECT_DISC);
-       ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY);
-       ENSURE(lock_door, CDC_LOCK);
-       ENSURE(select_speed, CDC_SELECT_SPEED);
-       ENSURE(get_last_session, CDC_MULTI_SESSION);
-       ENSURE(get_mcn, CDC_MCN);
-       ENSURE(reset, CDC_RESET);
-       ENSURE(generic_packet, CDC_GENERIC_PACKET);
-       cdi->mc_flags = 0;
-       cdo->n_minors = 0;
-        cdi->options = CDO_USE_FFLAGS;
-       
-       if (autoclose==1 && CDROM_CAN(CDC_CLOSE_TRAY))
-               cdi->options |= (int) CDO_AUTO_CLOSE;
-       if (autoeject==1 && CDROM_CAN(CDC_OPEN_TRAY))
-               cdi->options |= (int) CDO_AUTO_EJECT;
-       if (lockdoor==1)
-               cdi->options |= (int) CDO_LOCK;
-       if (check_media_type==1)
-               cdi->options |= (int) CDO_CHECK_TYPE;
-
-       if (CDROM_CAN(CDC_MRW_W))
-               cdi->exit = cdrom_mrw_exit;
-
-       if (cdi->disk)
-               cdi->cdda_method = CDDA_BPC_FULL;
-       else
-               cdi->cdda_method = CDDA_OLD;
-
-       if (!cdo->generic_packet)
-               cdo->generic_packet = cdrom_dummy_generic_packet;
-
-       cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
-       mutex_lock(&cdrom_mutex);
-       list_add(&cdi->list, &cdrom_list);
-       mutex_unlock(&cdrom_mutex);
-       return 0;
-}
-#undef ENSURE
-
-void unregister_cdrom(struct cdrom_device_info *cdi)
+static int cdrom_flush_cache(struct cdrom_device_info *cdi)
 {
-       cdinfo(CD_OPEN, "entering unregister_cdrom\n"); 
+       struct packet_command cgc;
 
-       mutex_lock(&cdrom_mutex);
-       list_del(&cdi->list);
-       mutex_unlock(&cdrom_mutex);
+       init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
+       cgc.cmd[0] = GPCMD_FLUSH_CACHE;
 
-       if (cdi->exit)
-               cdi->exit(cdi);
+       cgc.timeout = 5 * 60 * HZ;
 
-       cdi->ops->n_minors--;
-       cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name);
+       return cdi->ops->generic_packet(cdi, &cgc);
 }
 
-int cdrom_get_media_event(struct cdrom_device_info *cdi,
-                         struct media_event_desc *med)
+/* requires CD R/RW */
+static int cdrom_get_disc_info(struct cdrom_device_info *cdi,
+                              disc_information *di)
 {
+       struct cdrom_device_ops *cdo = cdi->ops;
        struct packet_command cgc;
-       unsigned char buffer[8];
-       struct event_header *eh = (struct event_header *) buffer;
+       int ret, buflen;
 
-       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
-       cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION;
-       cgc.cmd[1] = 1;         /* IMMED */
-       cgc.cmd[4] = 1 << 4;    /* media event */
-       cgc.cmd[8] = sizeof(buffer);
+       /* set up command and get the disc info */
+       init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ);
+       cgc.cmd[0] = GPCMD_READ_DISC_INFO;
+       cgc.cmd[8] = cgc.buflen = 2;
        cgc.quiet = 1;
 
-       if (cdi->ops->generic_packet(cdi, &cgc))
-               return 1;
+       ret = cdo->generic_packet(cdi, &cgc);
+       if (ret)
+               return ret;
 
-       if (be16_to_cpu(eh->data_len) < sizeof(*med))
-               return 1;
+       /* not all drives have the same disc_info length, so requeue
+        * packet with the length the drive tells us it can supply
+        */
+       buflen = be16_to_cpu(di->disc_information_length) +
+               sizeof(di->disc_information_length);
 
-       if (eh->nea || eh->notification_class != 0x4)
-               return 1;
+       if (buflen > sizeof(disc_information))
+               buflen = sizeof(disc_information);
 
-       memcpy(med, &buffer[sizeof(*eh)], sizeof(*med));
-       return 0;
+       cgc.cmd[8] = cgc.buflen = buflen;
+       ret = cdo->generic_packet(cdi, &cgc);
+       if (ret)
+               return ret;
+
+       /* return actual fill size */
+       return buflen;
 }
 
+/* This macro makes sure we don't have to check on cdrom_device_ops
+ * existence in the run-time routines below. Change_capability is a
+ * hack to have the capability flags defined const, while we can still
+ * change it here without gcc complaining at every line.
+ */
+#define ENSURE(call, bits)                     \
+do {                                           \
+       if (cdo->call == NULL)                  \
+               *change_capability &= ~(bits);  \
+} while (0)
+
 /*
  * the first prototypes used 0x2c as the page code for the mrw mode page,
  * subsequently this was changed to 0x03. probe the one used by this drive
@@ -605,18 +530,6 @@ static int cdrom_mrw_bgformat_susp(struct cdrom_device_info *cdi, int immed)
        return cdi->ops->generic_packet(cdi, &cgc);
 }
 
-static int cdrom_flush_cache(struct cdrom_device_info *cdi)
-{
-       struct packet_command cgc;
-
-       init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
-       cgc.cmd[0] = GPCMD_FLUSH_CACHE;
-
-       cgc.timeout = 5 * 60 * HZ;
-
-       return cdi->ops->generic_packet(cdi, &cgc);
-}
-
 static int cdrom_mrw_exit(struct cdrom_device_info *cdi)
 {
        disc_information di;
@@ -650,17 +563,19 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space)
        cgc.buffer = buffer;
        cgc.buflen = sizeof(buffer);
 
-       if ((ret = cdrom_mode_sense(cdi, &cgc, cdi->mrw_mode_page, 0)))
+       ret = cdrom_mode_sense(cdi, &cgc, cdi->mrw_mode_page, 0);
+       if (ret)
                return ret;
 
-       mph = (struct mode_page_header *) buffer;
+       mph = (struct mode_page_header *)buffer;
        offset = be16_to_cpu(mph->desc_length);
        size = be16_to_cpu(mph->mode_data_length) + 2;
 
        buffer[offset + 3] = space;
        cgc.buflen = size;
 
-       if ((ret = cdrom_mode_select(cdi, &cgc)))
+       ret = cdrom_mode_select(cdi, &cgc);
+       if (ret)
                return ret;
 
        pr_info("%s: mrw address space %s selected\n",
@@ -668,6 +583,106 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space)
        return 0;
 }
 
+int register_cdrom(struct cdrom_device_info *cdi)
+{
+       static char banner_printed;
+       struct cdrom_device_ops *cdo = cdi->ops;
+       int *change_capability = (int *)&cdo->capability; /* hack */
+
+       cd_dbg(CD_OPEN, "entering register_cdrom\n");
+
+       if (cdo->open == NULL || cdo->release == NULL)
+               return -EINVAL;
+       if (!banner_printed) {
+               pr_info("Uniform CD-ROM driver " REVISION "\n");
+               banner_printed = 1;
+               cdrom_sysctl_register();
+       }
+
+       ENSURE(drive_status, CDC_DRIVE_STATUS);
+       if (cdo->check_events == NULL && cdo->media_changed == NULL)
+               *change_capability = ~(CDC_MEDIA_CHANGED | CDC_SELECT_DISC);
+       ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY);
+       ENSURE(lock_door, CDC_LOCK);
+       ENSURE(select_speed, CDC_SELECT_SPEED);
+       ENSURE(get_last_session, CDC_MULTI_SESSION);
+       ENSURE(get_mcn, CDC_MCN);
+       ENSURE(reset, CDC_RESET);
+       ENSURE(generic_packet, CDC_GENERIC_PACKET);
+       cdi->mc_flags = 0;
+       cdo->n_minors = 0;
+       cdi->options = CDO_USE_FFLAGS;
+
+       if (autoclose == 1 && CDROM_CAN(CDC_CLOSE_TRAY))
+               cdi->options |= (int) CDO_AUTO_CLOSE;
+       if (autoeject == 1 && CDROM_CAN(CDC_OPEN_TRAY))
+               cdi->options |= (int) CDO_AUTO_EJECT;
+       if (lockdoor == 1)
+               cdi->options |= (int) CDO_LOCK;
+       if (check_media_type == 1)
+               cdi->options |= (int) CDO_CHECK_TYPE;
+
+       if (CDROM_CAN(CDC_MRW_W))
+               cdi->exit = cdrom_mrw_exit;
+
+       if (cdi->disk)
+               cdi->cdda_method = CDDA_BPC_FULL;
+       else
+               cdi->cdda_method = CDDA_OLD;
+
+       if (!cdo->generic_packet)
+               cdo->generic_packet = cdrom_dummy_generic_packet;
+
+       cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
+       mutex_lock(&cdrom_mutex);
+       list_add(&cdi->list, &cdrom_list);
+       mutex_unlock(&cdrom_mutex);
+       return 0;
+}
+#undef ENSURE
+
+void unregister_cdrom(struct cdrom_device_info *cdi)
+{
+       cd_dbg(CD_OPEN, "entering unregister_cdrom\n");
+
+       mutex_lock(&cdrom_mutex);
+       list_del(&cdi->list);
+       mutex_unlock(&cdrom_mutex);
+
+       if (cdi->exit)
+               cdi->exit(cdi);
+
+       cdi->ops->n_minors--;
+       cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name);
+}
+
+int cdrom_get_media_event(struct cdrom_device_info *cdi,
+                         struct media_event_desc *med)
+{
+       struct packet_command cgc;
+       unsigned char buffer[8];
+       struct event_header *eh = (struct event_header *)buffer;
+
+       init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
+       cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION;
+       cgc.cmd[1] = 1;         /* IMMED */
+       cgc.cmd[4] = 1 << 4;    /* media event */
+       cgc.cmd[8] = sizeof(buffer);
+       cgc.quiet = 1;
+
+       if (cdi->ops->generic_packet(cdi, &cgc))
+               return 1;
+
+       if (be16_to_cpu(eh->data_len) < sizeof(*med))
+               return 1;
+
+       if (eh->nea || eh->notification_class != 0x4)
+               return 1;
+
+       memcpy(med, &buffer[sizeof(*eh)], sizeof(*med));
+       return 0;
+}
+
 static int cdrom_get_random_writable(struct cdrom_device_info *cdi,
                              struct rwrt_feature_desc *rfd)
 {
@@ -839,7 +854,7 @@ static int cdrom_ram_open_write(struct cdrom_device_info *cdi)
        else if (CDF_RWRT == be16_to_cpu(rfd.feature_code))
                ret = !rfd.curr;
 
-       cdinfo(CD_OPEN, "can open for random write\n");
+       cd_dbg(CD_OPEN, "can open for random write\n");
        return ret;
 }
 
@@ -870,6 +885,7 @@ static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi)
        switch (cdi->mmc3_profile) {
        case 0x12:      /* DVD-RAM      */
        case 0x1A:      /* DVD+RW       */
+       case 0x43:      /* BD-RE        */
                return 0;
        default:
                return 1;
@@ -928,12 +944,12 @@ static void cdrom_dvd_rw_close_write(struct cdrom_device_info *cdi)
        struct packet_command cgc;
 
        if (cdi->mmc3_profile != 0x1a) {
-               cdinfo(CD_CLOSE, "%s: No DVD+RW\n", cdi->name);
+               cd_dbg(CD_CLOSE, "%s: No DVD+RW\n", cdi->name);
                return;
        }
 
        if (!cdi->media_written) {
-               cdinfo(CD_CLOSE, "%s: DVD+RW media clean\n", cdi->name);
+               cd_dbg(CD_CLOSE, "%s: DVD+RW media clean\n", cdi->name);
                return;
        }
 
@@ -969,82 +985,74 @@ static int cdrom_close_write(struct cdrom_device_info *cdi)
 #endif
 }
 
-/* We use the open-option O_NONBLOCK to indicate that the
- * purpose of opening is only for subsequent ioctl() calls; no device
- * integrity checks are performed.
- *
- * We hope that all cd-player programs will adopt this convention. It
- * is in their own interest: device control becomes a lot easier
- * this way.
- */
-int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, fmode_t mode)
+/* badly broken, I know. Is due for a fixup anytime. */
+static void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype *tracks)
 {
-       int ret;
-
-       cdinfo(CD_OPEN, "entering cdrom_open\n"); 
-
-       /* open is event synchronization point, check events first */
-       check_disk_change(bdev);
-
-       /* if this was a O_NONBLOCK open and we should honor the flags,
-        * do a quick open without drive/disc integrity checks. */
-       cdi->use_count++;
-       if ((mode & FMODE_NDELAY) && (cdi->options & CDO_USE_FFLAGS)) {
-               ret = cdi->ops->open(cdi, 1);
-       } else {
-               ret = open_for_data(cdi);
-               if (ret)
-                       goto err;
-               cdrom_mmc3_profile(cdi);
-               if (mode & FMODE_WRITE) {
-                       ret = -EROFS;
-                       if (cdrom_open_write(cdi))
-                               goto err_release;
-                       if (!CDROM_CAN(CDC_RAM))
-                               goto err_release;
-                       ret = 0;
-                       cdi->media_written = 0;
-               }
+       struct cdrom_tochdr header;
+       struct cdrom_tocentry entry;
+       int ret, i;
+       tracks->data = 0;
+       tracks->audio = 0;
+       tracks->cdi = 0;
+       tracks->xa = 0;
+       tracks->error = 0;
+       cd_dbg(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n");
+       /* Grab the TOC header so we can see how many tracks there are */
+       ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header);
+       if (ret) {
+               if (ret == -ENOMEDIUM)
+                       tracks->error = CDS_NO_DISC;
+               else
+                       tracks->error = CDS_NO_INFO;
+               return;
        }
-
-       if (ret)
-               goto err;
-
-       cdinfo(CD_OPEN, "Use count for \"/dev/%s\" now %d\n",
-                       cdi->name, cdi->use_count);
-       return 0;
-err_release:
-       if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) {
-               cdi->ops->lock_door(cdi, 0);
-               cdinfo(CD_OPEN, "door unlocked.\n");
+       /* check what type of tracks are on this disc */
+       entry.cdte_format = CDROM_MSF;
+       for (i = header.cdth_trk0; i <= header.cdth_trk1; i++) {
+               entry.cdte_track = i;
+               if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) {
+                       tracks->error = CDS_NO_INFO;
+                       return;
+               }
+               if (entry.cdte_ctrl & CDROM_DATA_TRACK) {
+                       if (entry.cdte_format == 0x10)
+                               tracks->cdi++;
+                       else if (entry.cdte_format == 0x20)
+                               tracks->xa++;
+                       else
+                               tracks->data++;
+               } else {
+                       tracks->audio++;
+               }
+               cd_dbg(CD_COUNT_TRACKS, "track %d: format=%d, ctrl=%d\n",
+                      i, entry.cdte_format, entry.cdte_ctrl);
        }
-       cdi->ops->release(cdi);
-err:
-       cdi->use_count--;
-       return ret;
+       cd_dbg(CD_COUNT_TRACKS, "disc has %d tracks: %d=audio %d=data %d=Cd-I %d=XA\n",
+              header.cdth_trk1, tracks->audio, tracks->data,
+              tracks->cdi, tracks->xa);
 }
 
 static
-int open_for_data(struct cdrom_device_info * cdi)
+int open_for_data(struct cdrom_device_info *cdi)
 {
        int ret;
        struct cdrom_device_ops *cdo = cdi->ops;
        tracktype tracks;
-       cdinfo(CD_OPEN, "entering open_for_data\n");
+       cd_dbg(CD_OPEN, "entering open_for_data\n");
        /* Check if the driver can report drive status.  If it can, we
           can do clever things.  If it can't, well, we at least tried! */
        if (cdo->drive_status != NULL) {
                ret = cdo->drive_status(cdi, CDSL_CURRENT);
-               cdinfo(CD_OPEN, "drive_status=%d\n", ret); 
+               cd_dbg(CD_OPEN, "drive_status=%d\n", ret);
                if (ret == CDS_TRAY_OPEN) {
-                       cdinfo(CD_OPEN, "the tray is open...\n"); 
+                       cd_dbg(CD_OPEN, "the tray is open...\n");
                        /* can/may i close it? */
                        if (CDROM_CAN(CDC_CLOSE_TRAY) &&
                            cdi->options & CDO_AUTO_CLOSE) {
-                               cdinfo(CD_OPEN, "trying to close the tray.\n"); 
+                               cd_dbg(CD_OPEN, "trying to close the tray\n");
                                ret=cdo->tray_move(cdi,0);
                                if (ret) {
-                                       cdinfo(CD_OPEN, "bummer. tried to close the tray but failed.\n"); 
+                                       cd_dbg(CD_OPEN, "bummer. tried to close the tray but failed.\n");
                                        /* Ignore the error from the low
                                        level driver.  We don't care why it
                                        couldn't close the tray.  We only care 
@@ -1054,19 +1062,19 @@ int open_for_data(struct cdrom_device_info * cdi)
                                        goto clean_up_and_return;
                                }
                        } else {
-                               cdinfo(CD_OPEN, "bummer. this drive can't close the tray.\n"); 
+                               cd_dbg(CD_OPEN, "bummer. this drive can't close the tray.\n");
                                ret=-ENOMEDIUM;
                                goto clean_up_and_return;
                        }
                        /* Ok, the door should be closed now.. Check again */
                        ret = cdo->drive_status(cdi, CDSL_CURRENT);
                        if ((ret == CDS_NO_DISC) || (ret==CDS_TRAY_OPEN)) {
-                               cdinfo(CD_OPEN, "bummer. the tray is still not closed.\n"); 
-                               cdinfo(CD_OPEN, "tray might not contain a medium.\n");
+                               cd_dbg(CD_OPEN, "bummer. the tray is still not closed.\n");
+                               cd_dbg(CD_OPEN, "tray might not contain a medium\n");
                                ret=-ENOMEDIUM;
                                goto clean_up_and_return;
                        }
-                       cdinfo(CD_OPEN, "the tray is now closed.\n"); 
+                       cd_dbg(CD_OPEN, "the tray is now closed\n");
                }
                /* the door should be closed now, check for the disc */
                ret = cdo->drive_status(cdi, CDSL_CURRENT);
@@ -1077,7 +1085,7 @@ int open_for_data(struct cdrom_device_info * cdi)
        }
        cdrom_count_tracks(cdi, &tracks);
        if (tracks.error == CDS_NO_DISC) {
-               cdinfo(CD_OPEN, "bummer. no disc.\n");
+               cd_dbg(CD_OPEN, "bummer. no disc.\n");
                ret=-ENOMEDIUM;
                goto clean_up_and_return;
        }
@@ -1087,34 +1095,34 @@ int open_for_data(struct cdrom_device_info * cdi)
                if (cdi->options & CDO_CHECK_TYPE) {
                    /* give people a warning shot, now that CDO_CHECK_TYPE
                       is the default case! */
-                   cdinfo(CD_OPEN, "bummer. wrong media type.\n"); 
-                   cdinfo(CD_WARNING, "pid %d must open device O_NONBLOCK!\n",
-                                       (unsigned int)task_pid_nr(current));
+                   cd_dbg(CD_OPEN, "bummer. wrong media type.\n");
+                   cd_dbg(CD_WARNING, "pid %d must open device O_NONBLOCK!\n",
+                          (unsigned int)task_pid_nr(current));
                    ret=-EMEDIUMTYPE;
                    goto clean_up_and_return;
                }
                else {
-                   cdinfo(CD_OPEN, "wrong media type, but CDO_CHECK_TYPE not set.\n");
+                   cd_dbg(CD_OPEN, "wrong media type, but CDO_CHECK_TYPE not set\n");
                }
        }
 
-       cdinfo(CD_OPEN, "all seems well, opening the device.\n"); 
+       cd_dbg(CD_OPEN, "all seems well, opening the devicen");
 
        /* all seems well, we can open the device */
        ret = cdo->open(cdi, 0); /* open for data */
-       cdinfo(CD_OPEN, "opening the device gave me %d.\n", ret); 
+       cd_dbg(CD_OPEN, "opening the device gave me %d\n", ret);
        /* After all this careful checking, we shouldn't have problems
           opening the device, but we don't want the device locked if 
           this somehow fails... */
        if (ret) {
-               cdinfo(CD_OPEN, "open device failed.\n"); 
+               cd_dbg(CD_OPEN, "open device failed\n");
                goto clean_up_and_return;
        }
        if (CDROM_CAN(CDC_LOCK) && (cdi->options & CDO_LOCK)) {
                        cdo->lock_door(cdi, 1);
-                       cdinfo(CD_OPEN, "door locked.\n");
+                       cd_dbg(CD_OPEN, "door locked\n");
        }
-       cdinfo(CD_OPEN, "device opened successfully.\n"); 
+       cd_dbg(CD_OPEN, "device opened successfully\n");
        return ret;
 
        /* Something failed.  Try to unlock the drive, because some drivers
@@ -1123,11 +1131,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;
 }
 
@@ -1139,21 +1203,21 @@ static int check_for_audio_disc(struct cdrom_device_info * cdi,
 {
         int ret;
        tracktype tracks;
-       cdinfo(CD_OPEN, "entering check_for_audio_disc\n");
+       cd_dbg(CD_OPEN, "entering check_for_audio_disc\n");
        if (!(cdi->options & CDO_CHECK_TYPE))
                return 0;
        if (cdo->drive_status != NULL) {
                ret = cdo->drive_status(cdi, CDSL_CURRENT);
-               cdinfo(CD_OPEN, "drive_status=%d\n", ret); 
+               cd_dbg(CD_OPEN, "drive_status=%d\n", ret);
                if (ret == CDS_TRAY_OPEN) {
-                       cdinfo(CD_OPEN, "the tray is open...\n"); 
+                       cd_dbg(CD_OPEN, "the tray is open...\n");
                        /* can/may i close it? */
                        if (CDROM_CAN(CDC_CLOSE_TRAY) &&
                            cdi->options & CDO_AUTO_CLOSE) {
-                               cdinfo(CD_OPEN, "trying to close the tray.\n"); 
+                               cd_dbg(CD_OPEN, "trying to close the tray\n");
                                ret=cdo->tray_move(cdi,0);
                                if (ret) {
-                                       cdinfo(CD_OPEN, "bummer. tried to close tray but failed.\n"); 
+                                       cd_dbg(CD_OPEN, "bummer. tried to close tray but failed.\n");
                                        /* Ignore the error from the low
                                        level driver.  We don't care why it
                                        couldn't close the tray.  We only care 
@@ -1162,20 +1226,20 @@ static int check_for_audio_disc(struct cdrom_device_info * cdi,
                                        return -ENOMEDIUM;
                                }
                        } else {
-                               cdinfo(CD_OPEN, "bummer. this driver can't close the tray.\n"); 
+                               cd_dbg(CD_OPEN, "bummer. this driver can't close the tray.\n");
                                return -ENOMEDIUM;
                        }
                        /* Ok, the door should be closed now.. Check again */
                        ret = cdo->drive_status(cdi, CDSL_CURRENT);
                        if ((ret == CDS_NO_DISC) || (ret==CDS_TRAY_OPEN)) {
-                               cdinfo(CD_OPEN, "bummer. the tray is still not closed.\n"); 
+                               cd_dbg(CD_OPEN, "bummer. the tray is still not closed.\n");
                                return -ENOMEDIUM;
                        }       
                        if (ret!=CDS_DISC_OK) {
-                               cdinfo(CD_OPEN, "bummer. disc isn't ready.\n"); 
+                               cd_dbg(CD_OPEN, "bummer. disc isn't ready.\n");
                                return -EIO;
                        }       
-                       cdinfo(CD_OPEN, "the tray is now closed.\n"); 
+                       cd_dbg(CD_OPEN, "the tray is now closed\n");
                }       
        }
        cdrom_count_tracks(cdi, &tracks);
@@ -1193,17 +1257,18 @@ void cdrom_release(struct cdrom_device_info *cdi, fmode_t mode)
        struct cdrom_device_ops *cdo = cdi->ops;
        int opened_for_data;
 
-       cdinfo(CD_CLOSE, "entering cdrom_release\n");
+       cd_dbg(CD_CLOSE, "entering cdrom_release\n");
 
        if (cdi->use_count > 0)
                cdi->use_count--;
 
        if (cdi->use_count == 0) {
-               cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name);
+               cd_dbg(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n",
+                      cdi->name);
                cdrom_dvd_rw_close_write(cdi);
 
                if ((cdo->capability & CDC_LOCK) && !cdi->keeplocked) {
-                       cdinfo(CD_CLOSE, "Unlocking door!\n");
+                       cd_dbg(CD_CLOSE, "Unlocking door!\n");
                        cdo->lock_door(cdi, 0);
                }
        }
@@ -1262,7 +1327,7 @@ static int cdrom_slot_status(struct cdrom_device_info *cdi, int slot)
        struct cdrom_changer_info *info;
        int ret;
 
-       cdinfo(CD_CHANGER, "entering cdrom_slot_status()\n"); 
+       cd_dbg(CD_CHANGER, "entering cdrom_slot_status()\n");
        if (cdi->sanyo_slot)
                return CDS_NO_INFO;
        
@@ -1292,7 +1357,7 @@ int cdrom_number_of_slots(struct cdrom_device_info *cdi)
        int nslots = 1;
        struct cdrom_changer_info *info;
 
-       cdinfo(CD_CHANGER, "entering cdrom_number_of_slots()\n"); 
+       cd_dbg(CD_CHANGER, "entering cdrom_number_of_slots()\n");
        /* cdrom_read_mech_status requires a valid value for capacity: */
        cdi->capacity = 0; 
 
@@ -1313,7 +1378,7 @@ static int cdrom_load_unload(struct cdrom_device_info *cdi, int slot)
 {
        struct packet_command cgc;
 
-       cdinfo(CD_CHANGER, "entering cdrom_load_unload()\n"); 
+       cd_dbg(CD_CHANGER, "entering cdrom_load_unload()\n");
        if (cdi->sanyo_slot && slot < 0)
                return 0;
 
@@ -1342,7 +1407,7 @@ static int cdrom_select_disc(struct cdrom_device_info *cdi, int slot)
        int curslot;
        int ret;
 
-       cdinfo(CD_CHANGER, "entering cdrom_select_disc()\n"); 
+       cd_dbg(CD_CHANGER, "entering cdrom_select_disc()\n");
        if (!CDROM_CAN(CDC_SELECT_DISC))
                return -EDRIVE_CANT_DO_THIS;
 
@@ -1476,51 +1541,6 @@ int cdrom_media_changed(struct cdrom_device_info *cdi)
        return media_changed(cdi, 0);
 }
 
-/* badly broken, I know. Is due for a fixup anytime. */
-static void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype* tracks)
-{
-       struct cdrom_tochdr header;
-       struct cdrom_tocentry entry;
-       int ret, i;
-       tracks->data=0;
-       tracks->audio=0;
-       tracks->cdi=0;
-       tracks->xa=0;
-       tracks->error=0;
-       cdinfo(CD_COUNT_TRACKS, "entering cdrom_count_tracks\n"); 
-       /* Grab the TOC header so we can see how many tracks there are */
-       if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCHDR, &header))) {
-               if (ret == -ENOMEDIUM)
-                       tracks->error = CDS_NO_DISC;
-               else
-                       tracks->error = CDS_NO_INFO;
-               return;
-       }       
-       /* check what type of tracks are on this disc */
-       entry.cdte_format = CDROM_MSF;
-       for (i = header.cdth_trk0; i <= header.cdth_trk1; i++) {
-               entry.cdte_track  = i;
-               if (cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &entry)) {
-                       tracks->error=CDS_NO_INFO;
-                       return;
-               }       
-               if (entry.cdte_ctrl & CDROM_DATA_TRACK) {
-                   if (entry.cdte_format == 0x10)
-                       tracks->cdi++;
-                   else if (entry.cdte_format == 0x20) 
-                       tracks->xa++;
-                   else
-                       tracks->data++;
-               } else
-                   tracks->audio++;
-               cdinfo(CD_COUNT_TRACKS, "track %d: format=%d, ctrl=%d\n",
-                      i, entry.cdte_format, entry.cdte_ctrl);
-       }       
-       cdinfo(CD_COUNT_TRACKS, "disc has %d tracks: %d=audio %d=data %d=Cd-I %d=XA\n", 
-               header.cdth_trk1, tracks->audio, tracks->data, 
-               tracks->cdi, tracks->xa);
-}      
-
 /* Requests to the low-level drivers will /always/ be done in the
    following format convention:
 
@@ -1632,7 +1652,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
        switch (ai->type) {
        /* LU data send */
        case DVD_LU_SEND_AGID:
-               cdinfo(CD_DVD, "entering DVD_LU_SEND_AGID\n"); 
+               cd_dbg(CD_DVD, "entering DVD_LU_SEND_AGID\n");
                cgc.quiet = 1;
                setup_report_key(&cgc, ai->lsa.agid, 0);
 
@@ -1644,7 +1664,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                break;
 
        case DVD_LU_SEND_KEY1:
-               cdinfo(CD_DVD, "entering DVD_LU_SEND_KEY1\n"); 
+               cd_dbg(CD_DVD, "entering DVD_LU_SEND_KEY1\n");
                setup_report_key(&cgc, ai->lsk.agid, 2);
 
                if ((ret = cdo->generic_packet(cdi, &cgc)))
@@ -1655,7 +1675,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                break;
 
        case DVD_LU_SEND_CHALLENGE:
-               cdinfo(CD_DVD, "entering DVD_LU_SEND_CHALLENGE\n"); 
+               cd_dbg(CD_DVD, "entering DVD_LU_SEND_CHALLENGE\n");
                setup_report_key(&cgc, ai->lsc.agid, 1);
 
                if ((ret = cdo->generic_packet(cdi, &cgc)))
@@ -1667,7 +1687,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
 
        /* Post-auth key */
        case DVD_LU_SEND_TITLE_KEY:
-               cdinfo(CD_DVD, "entering DVD_LU_SEND_TITLE_KEY\n"); 
+               cd_dbg(CD_DVD, "entering DVD_LU_SEND_TITLE_KEY\n");
                cgc.quiet = 1;
                setup_report_key(&cgc, ai->lstk.agid, 4);
                cgc.cmd[5] = ai->lstk.lba;
@@ -1686,7 +1706,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                break;
 
        case DVD_LU_SEND_ASF:
-               cdinfo(CD_DVD, "entering DVD_LU_SEND_ASF\n"); 
+               cd_dbg(CD_DVD, "entering DVD_LU_SEND_ASF\n");
                setup_report_key(&cgc, ai->lsasf.agid, 5);
                
                if ((ret = cdo->generic_packet(cdi, &cgc)))
@@ -1697,7 +1717,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
 
        /* LU data receive (LU changes state) */
        case DVD_HOST_SEND_CHALLENGE:
-               cdinfo(CD_DVD, "entering DVD_HOST_SEND_CHALLENGE\n"); 
+               cd_dbg(CD_DVD, "entering DVD_HOST_SEND_CHALLENGE\n");
                setup_send_key(&cgc, ai->hsc.agid, 1);
                buf[1] = 0xe;
                copy_chal(&buf[4], ai->hsc.chal);
@@ -1709,7 +1729,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                break;
 
        case DVD_HOST_SEND_KEY2:
-               cdinfo(CD_DVD, "entering DVD_HOST_SEND_KEY2\n"); 
+               cd_dbg(CD_DVD, "entering DVD_HOST_SEND_KEY2\n");
                setup_send_key(&cgc, ai->hsk.agid, 3);
                buf[1] = 0xa;
                copy_key(&buf[4], ai->hsk.key);
@@ -1724,7 +1744,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
        /* Misc */
        case DVD_INVALIDATE_AGID:
                cgc.quiet = 1;
-               cdinfo(CD_DVD, "entering DVD_INVALIDATE_AGID\n"); 
+               cd_dbg(CD_DVD, "entering DVD_INVALIDATE_AGID\n");
                setup_report_key(&cgc, ai->lsa.agid, 0x3f);
                if ((ret = cdo->generic_packet(cdi, &cgc)))
                        return ret;
@@ -1732,7 +1752,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
 
        /* Get region settings */
        case DVD_LU_SEND_RPC_STATE:
-               cdinfo(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n");
+               cd_dbg(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n");
                setup_report_key(&cgc, 0, 8);
                memset(&rpc_state, 0, sizeof(rpc_state_t));
                cgc.buffer = (char *) &rpc_state;
@@ -1749,7 +1769,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
 
        /* Set region settings */
        case DVD_HOST_SEND_RPC_STATE:
-               cdinfo(CD_DVD, "entering DVD_HOST_SEND_RPC_STATE\n");
+               cd_dbg(CD_DVD, "entering DVD_HOST_SEND_RPC_STATE\n");
                setup_send_key(&cgc, 0, 6);
                buf[1] = 6;
                buf[4] = ai->hrpcs.pdrc;
@@ -1759,7 +1779,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
                break;
 
        default:
-               cdinfo(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type);
+               cd_dbg(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type);
                return -ENOTTY;
        }
 
@@ -1891,7 +1911,8 @@ static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s,
 
        s->bca.len = buf[0] << 8 | buf[1];
        if (s->bca.len < 12 || s->bca.len > 188) {
-               cdinfo(CD_WARNING, "Received invalid BCA length (%d)\n", s->bca.len);
+               cd_dbg(CD_WARNING, "Received invalid BCA length (%d)\n",
+                      s->bca.len);
                ret = -EIO;
                goto out;
        }
@@ -1927,14 +1948,13 @@ static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s,
 
        s->manufact.len = buf[0] << 8 | buf[1];
        if (s->manufact.len < 0) {
-               cdinfo(CD_WARNING, "Received invalid manufacture info length"
-                                  " (%d)\n", s->manufact.len);
+               cd_dbg(CD_WARNING, "Received invalid manufacture info length (%d)\n",
+                      s->manufact.len);
                ret = -EIO;
        } else {
                if (s->manufact.len > 2048) {
-                       cdinfo(CD_WARNING, "Received invalid manufacture info "
-                                       "length (%d): truncating to 2048\n",
-                                       s->manufact.len);
+                       cd_dbg(CD_WARNING, "Received invalid manufacture info length (%d): truncating to 2048\n",
+                              s->manufact.len);
                        s->manufact.len = 2048;
                }
                memcpy(s->manufact.value, &buf[4], s->manufact.len);
@@ -1965,8 +1985,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;
        }
 }
@@ -2161,10 +2181,11 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
                len = nr * CD_FRAMESIZE_RAW;
 
                rq = blk_get_request(q, READ, GFP_KERNEL);
-               if (!rq) {
-                       ret = -ENOMEM;
+               if (IS_ERR(rq)) {
+                       ret = PTR_ERR(rq);
                        break;
                }
+               blk_rq_set_block_pc(rq);
 
                ret = blk_rq_map_user(q, rq, NULL, ubuf, len, GFP_KERNEL);
                if (ret) {
@@ -2184,7 +2205,6 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
                rq->cmd[9] = 0xf8;
 
                rq->cmd_len = 12;
-               rq->cmd_type = REQ_TYPE_BLOCK_PC;
                rq->timeout = 60 * HZ;
                bio = rq->bio;
 
@@ -2255,7 +2275,7 @@ static int cdrom_ioctl_multisession(struct cdrom_device_info *cdi,
        u8 requested_format;
        int ret;
 
-       cdinfo(CD_DO_IOCTL, "entering CDROMMULTISESSION\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMMULTISESSION\n");
 
        if (!(cdi->ops->capability & CDC_MULTI_SESSION))
                return -ENOSYS;
@@ -2277,13 +2297,13 @@ static int cdrom_ioctl_multisession(struct cdrom_device_info *cdi,
        if (copy_to_user(argp, &ms_info, sizeof(ms_info)))
                return -EFAULT;
 
-       cdinfo(CD_DO_IOCTL, "CDROMMULTISESSION successful\n");
+       cd_dbg(CD_DO_IOCTL, "CDROMMULTISESSION successful\n");
        return 0;
 }
 
 static int cdrom_ioctl_eject(struct cdrom_device_info *cdi)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROMEJECT\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMEJECT\n");
 
        if (!CDROM_CAN(CDC_OPEN_TRAY))
                return -ENOSYS;
@@ -2300,7 +2320,7 @@ static int cdrom_ioctl_eject(struct cdrom_device_info *cdi)
 
 static int cdrom_ioctl_closetray(struct cdrom_device_info *cdi)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMCLOSETRAY\n");
 
        if (!CDROM_CAN(CDC_CLOSE_TRAY))
                return -ENOSYS;
@@ -2310,7 +2330,7 @@ static int cdrom_ioctl_closetray(struct cdrom_device_info *cdi)
 static int cdrom_ioctl_eject_sw(struct cdrom_device_info *cdi,
                unsigned long arg)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROMEJECT_SW\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMEJECT_SW\n");
 
        if (!CDROM_CAN(CDC_OPEN_TRAY))
                return -ENOSYS;
@@ -2329,7 +2349,7 @@ static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi,
        struct cdrom_changer_info *info;
        int ret;
 
-       cdinfo(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_MEDIA_CHANGED\n");
 
        if (!CDROM_CAN(CDC_MEDIA_CHANGED))
                return -ENOSYS;
@@ -2355,7 +2375,7 @@ static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi,
 static int cdrom_ioctl_set_options(struct cdrom_device_info *cdi,
                unsigned long arg)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n");
 
        /*
         * Options need to be in sync with capability.
@@ -2383,7 +2403,7 @@ static int cdrom_ioctl_set_options(struct cdrom_device_info *cdi,
 static int cdrom_ioctl_clear_options(struct cdrom_device_info *cdi,
                unsigned long arg)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_CLEAR_OPTIONS\n");
 
        cdi->options &= ~(int) arg;
        return cdi->options;
@@ -2392,7 +2412,7 @@ static int cdrom_ioctl_clear_options(struct cdrom_device_info *cdi,
 static int cdrom_ioctl_select_speed(struct cdrom_device_info *cdi,
                unsigned long arg)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_SELECT_SPEED\n");
 
        if (!CDROM_CAN(CDC_SELECT_SPEED))
                return -ENOSYS;
@@ -2402,7 +2422,7 @@ static int cdrom_ioctl_select_speed(struct cdrom_device_info *cdi,
 static int cdrom_ioctl_select_disc(struct cdrom_device_info *cdi,
                unsigned long arg)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_SELECT_DISC\n");
 
        if (!CDROM_CAN(CDC_SELECT_DISC))
                return -ENOSYS;
@@ -2420,14 +2440,14 @@ static int cdrom_ioctl_select_disc(struct cdrom_device_info *cdi,
        if (cdi->ops->select_disc)
                return cdi->ops->select_disc(cdi, arg);
 
-       cdinfo(CD_CHANGER, "Using generic cdrom_select_disc()\n");
+       cd_dbg(CD_CHANGER, "Using generic cdrom_select_disc()\n");
        return cdrom_select_disc(cdi, arg);
 }
 
 static int cdrom_ioctl_reset(struct cdrom_device_info *cdi,
                struct block_device *bdev)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROM_RESET\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_RESET\n");
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
@@ -2440,7 +2460,7 @@ static int cdrom_ioctl_reset(struct cdrom_device_info *cdi,
 static int cdrom_ioctl_lock_door(struct cdrom_device_info *cdi,
                unsigned long arg)
 {
-       cdinfo(CD_DO_IOCTL, "%socking door.\n", arg ? "L" : "Unl");
+       cd_dbg(CD_DO_IOCTL, "%socking door\n", arg ? "L" : "Unl");
 
        if (!CDROM_CAN(CDC_LOCK))
                return -EDRIVE_CANT_DO_THIS;
@@ -2459,7 +2479,7 @@ static int cdrom_ioctl_lock_door(struct cdrom_device_info *cdi,
 static int cdrom_ioctl_debug(struct cdrom_device_info *cdi,
                unsigned long arg)
 {
-       cdinfo(CD_DO_IOCTL, "%sabling debug.\n", arg ? "En" : "Dis");
+       cd_dbg(CD_DO_IOCTL, "%sabling debug\n", arg ? "En" : "Dis");
 
        if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
@@ -2469,7 +2489,7 @@ static int cdrom_ioctl_debug(struct cdrom_device_info *cdi,
 
 static int cdrom_ioctl_get_capability(struct cdrom_device_info *cdi)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_GET_CAPABILITY\n");
        return (cdi->ops->capability & ~cdi->mask);
 }
 
@@ -2485,7 +2505,7 @@ static int cdrom_ioctl_get_mcn(struct cdrom_device_info *cdi,
        struct cdrom_mcn mcn;
        int ret;
 
-       cdinfo(CD_DO_IOCTL, "entering CDROM_GET_MCN\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_GET_MCN\n");
 
        if (!(cdi->ops->capability & CDC_MCN))
                return -ENOSYS;
@@ -2495,14 +2515,14 @@ static int cdrom_ioctl_get_mcn(struct cdrom_device_info *cdi,
 
        if (copy_to_user(argp, &mcn, sizeof(mcn)))
                return -EFAULT;
-       cdinfo(CD_DO_IOCTL, "CDROM_GET_MCN successful\n");
+       cd_dbg(CD_DO_IOCTL, "CDROM_GET_MCN successful\n");
        return 0;
 }
 
 static int cdrom_ioctl_drive_status(struct cdrom_device_info *cdi,
                unsigned long arg)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_DRIVE_STATUS\n");
 
        if (!(cdi->ops->capability & CDC_DRIVE_STATUS))
                return -ENOSYS;
@@ -2535,7 +2555,7 @@ static int cdrom_ioctl_disc_status(struct cdrom_device_info *cdi)
 {
        tracktype tracks;
 
-       cdinfo(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_DISC_STATUS\n");
 
        cdrom_count_tracks(cdi, &tracks);
        if (tracks.error)
@@ -2557,13 +2577,13 @@ static int cdrom_ioctl_disc_status(struct cdrom_device_info *cdi)
                return CDS_DATA_1;
        /* Policy mode off */
 
-       cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognize!\n");
+       cd_dbg(CD_WARNING, "This disc doesn't have any tracks I recognize!\n");
        return CDS_NO_INFO;
 }
 
 static int cdrom_ioctl_changer_nslots(struct cdrom_device_info *cdi)
 {
-       cdinfo(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_CHANGER_NSLOTS\n");
        return cdi->capacity;
 }
 
@@ -2574,7 +2594,7 @@ static int cdrom_ioctl_get_subchnl(struct cdrom_device_info *cdi,
        u8 requested, back;
        int ret;
 
-       /* cdinfo(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/
+       /* cd_dbg(CD_DO_IOCTL,"entering CDROMSUBCHNL\n");*/
 
        if (copy_from_user(&q, argp, sizeof(q)))
                return -EFAULT;
@@ -2594,7 +2614,7 @@ static int cdrom_ioctl_get_subchnl(struct cdrom_device_info *cdi,
 
        if (copy_to_user(argp, &q, sizeof(q)))
                return -EFAULT;
-       /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */
+       /* cd_dbg(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */
        return 0;
 }
 
@@ -2604,7 +2624,7 @@ static int cdrom_ioctl_read_tochdr(struct cdrom_device_info *cdi,
        struct cdrom_tochdr header;
        int ret;
 
-       /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */
+       /* cd_dbg(CD_DO_IOCTL, "entering CDROMREADTOCHDR\n"); */
 
        if (copy_from_user(&header, argp, sizeof(header)))
                return -EFAULT;
@@ -2615,7 +2635,7 @@ static int cdrom_ioctl_read_tochdr(struct cdrom_device_info *cdi,
 
        if (copy_to_user(argp, &header, sizeof(header)))
                return -EFAULT;
-       /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */
+       /* cd_dbg(CD_DO_IOCTL, "CDROMREADTOCHDR successful\n"); */
        return 0;
 }
 
@@ -2626,7 +2646,7 @@ static int cdrom_ioctl_read_tocentry(struct cdrom_device_info *cdi,
        u8 requested_format;
        int ret;
 
-       /* cdinfo(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */
+       /* cd_dbg(CD_DO_IOCTL, "entering CDROMREADTOCENTRY\n"); */
 
        if (copy_from_user(&entry, argp, sizeof(entry)))
                return -EFAULT;
@@ -2643,7 +2663,7 @@ static int cdrom_ioctl_read_tocentry(struct cdrom_device_info *cdi,
 
        if (copy_to_user(argp, &entry, sizeof(entry)))
                return -EFAULT;
-       /* cdinfo(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */
+       /* cd_dbg(CD_DO_IOCTL, "CDROMREADTOCENTRY successful\n"); */
        return 0;
 }
 
@@ -2652,7 +2672,7 @@ static int cdrom_ioctl_play_msf(struct cdrom_device_info *cdi,
 {
        struct cdrom_msf msf;
 
-       cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");
 
        if (!CDROM_CAN(CDC_PLAY_AUDIO))
                return -ENOSYS;
@@ -2667,7 +2687,7 @@ static int cdrom_ioctl_play_trkind(struct cdrom_device_info *cdi,
        struct cdrom_ti ti;
        int ret;
 
-       cdinfo(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYTRKIND\n");
 
        if (!CDROM_CAN(CDC_PLAY_AUDIO))
                return -ENOSYS;
@@ -2684,7 +2704,7 @@ static int cdrom_ioctl_volctrl(struct cdrom_device_info *cdi,
 {
        struct cdrom_volctrl volume;
 
-       cdinfo(CD_DO_IOCTL, "entering CDROMVOLCTRL\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMVOLCTRL\n");
 
        if (!CDROM_CAN(CDC_PLAY_AUDIO))
                return -ENOSYS;
@@ -2699,7 +2719,7 @@ static int cdrom_ioctl_volread(struct cdrom_device_info *cdi,
        struct cdrom_volctrl volume;
        int ret;
 
-       cdinfo(CD_DO_IOCTL, "entering CDROMVOLREAD\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMVOLREAD\n");
 
        if (!CDROM_CAN(CDC_PLAY_AUDIO))
                return -ENOSYS;
@@ -2718,7 +2738,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;
@@ -2728,103 +2748,6 @@ static int cdrom_ioctl_audioctl(struct cdrom_device_info *cdi,
        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 cdrom_device_info *cdi, struct block_device *bdev,
-               fmode_t mode, unsigned int cmd, unsigned long arg)
-{
-       void __user *argp = (void __user *)arg;
-       int ret;
-
-       /*
-        * Try the generic SCSI command ioctl's first.
-        */
-       ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
-       if (ret != -ENOTTY)
-               return ret;
-
-       switch (cmd) {
-       case CDROMMULTISESSION:
-               return cdrom_ioctl_multisession(cdi, argp);
-       case CDROMEJECT:
-               return cdrom_ioctl_eject(cdi);
-       case CDROMCLOSETRAY:
-               return cdrom_ioctl_closetray(cdi);
-       case CDROMEJECT_SW:
-               return cdrom_ioctl_eject_sw(cdi, arg);
-       case CDROM_MEDIA_CHANGED:
-               return cdrom_ioctl_media_changed(cdi, arg);
-       case CDROM_SET_OPTIONS:
-               return cdrom_ioctl_set_options(cdi, arg);
-       case CDROM_CLEAR_OPTIONS:
-               return cdrom_ioctl_clear_options(cdi, arg);
-       case CDROM_SELECT_SPEED:
-               return cdrom_ioctl_select_speed(cdi, arg);
-       case CDROM_SELECT_DISC:
-               return cdrom_ioctl_select_disc(cdi, arg);
-       case CDROMRESET:
-               return cdrom_ioctl_reset(cdi, bdev);
-       case CDROM_LOCKDOOR:
-               return cdrom_ioctl_lock_door(cdi, arg);
-       case CDROM_DEBUG:
-               return cdrom_ioctl_debug(cdi, arg);
-       case CDROM_GET_CAPABILITY:
-               return cdrom_ioctl_get_capability(cdi);
-       case CDROM_GET_MCN:
-               return cdrom_ioctl_get_mcn(cdi, argp);
-       case CDROM_DRIVE_STATUS:
-               return cdrom_ioctl_drive_status(cdi, arg);
-       case CDROM_DISC_STATUS:
-               return cdrom_ioctl_disc_status(cdi);
-       case CDROM_CHANGER_NSLOTS:
-               return cdrom_ioctl_changer_nslots(cdi);
-       }
-
-       /*
-        * Use the ioctls that are implemented through the generic_packet()
-        * interface. this may look at bit funny, but if -ENOTTY is
-        * returned that particular ioctl is not implemented and we
-        * let it go through the device specific ones.
-        */
-       if (CDROM_CAN(CDC_GENERIC_PACKET)) {
-               ret = mmc_ioctl(cdi, cmd, arg);
-               if (ret != -ENOTTY)
-                       return ret;
-       }
-
-       /*
-        * Note: most of the cdinfo() calls are commented out here,
-        * because they fill up the sys log when CD players poll
-        * the drive.
-        */
-       switch (cmd) {
-       case CDROMSUBCHNL:
-               return cdrom_ioctl_get_subchnl(cdi, argp);
-       case CDROMREADTOCHDR:
-               return cdrom_ioctl_read_tochdr(cdi, argp);
-       case CDROMREADTOCENTRY:
-               return cdrom_ioctl_read_tocentry(cdi, argp);
-       case CDROMPLAYMSF:
-               return cdrom_ioctl_play_msf(cdi, argp);
-       case CDROMPLAYTRKIND:
-               return cdrom_ioctl_play_trkind(cdi, argp);
-       case CDROMVOLCTRL:
-               return cdrom_ioctl_volctrl(cdi, argp);
-       case CDROMVOLREAD:
-               return cdrom_ioctl_volread(cdi, argp);
-       case CDROMSTART:
-       case CDROMSTOP:
-       case CDROMPAUSE:
-       case CDROMRESUME:
-               return cdrom_ioctl_audioctl(cdi, cmd);
-       }
-
-       return -ENOSYS;
-}
-
 /*
  * Required when we need to use READ_10 to issue other than 2048 block
  * reads
@@ -2854,71 +2777,222 @@ static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size)
        return cdo->generic_packet(cdi, &cgc);
 }
 
-static noinline int mmc_ioctl_cdrom_read_data(struct cdrom_device_info *cdi,
-                                       void __user *arg,
-                                       struct packet_command *cgc,
-                                       int cmd)
+static int cdrom_get_track_info(struct cdrom_device_info *cdi,
+                               __u16 track, __u8 type, track_information *ti)
 {
-       struct request_sense sense;
-       struct cdrom_msf msf;
-       int blocksize = 0, format = 0, lba;
-       int ret;
+       struct cdrom_device_ops *cdo = cdi->ops;
+       struct packet_command cgc;
+       int ret, buflen;
 
-       switch (cmd) {
-       case CDROMREADRAW:
-               blocksize = CD_FRAMESIZE_RAW;
-               break;
-       case CDROMREADMODE1:
-               blocksize = CD_FRAMESIZE;
-               format = 2;
-               break;
-       case CDROMREADMODE2:
-               blocksize = CD_FRAMESIZE_RAW0;
-               break;
-       }
-       IOCTL_IN(arg, struct cdrom_msf, msf);
-       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;
+       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;
 
-       cgc->buffer = kmalloc(blocksize, GFP_KERNEL);
-       if (cgc->buffer == NULL)
-               return -ENOMEM;
+       ret = cdo->generic_packet(cdi, &cgc);
+       if (ret)
+               return ret;
 
-       memset(&sense, 0, sizeof(sense));
-       cgc->sense = &sense;
-       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) {
-               /*
-                * SCSI-II devices are not required to support
-                * READ_CD, so let's try switching block size
-                */
-               /* FIXME: switch back again... */
-               ret = cdrom_switch_blocksize(cdi, blocksize);
-               if (ret)
-                       goto out;
-               cgc->sense = NULL;
-               ret = cdrom_read_cd(cdi, cgc, lba, blocksize, 1);
-               ret |= cdrom_switch_blocksize(cdi, blocksize);
-       }
-       if (!ret && copy_to_user(arg, cgc->buffer, blocksize))
-               ret = -EFAULT;
-out:
+       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)
+{
+       struct request_sense sense;
+       struct cdrom_msf msf;
+       int blocksize = 0, format = 0, lba;
+       int ret;
+
+       switch (cmd) {
+       case CDROMREADRAW:
+               blocksize = CD_FRAMESIZE_RAW;
+               break;
+       case CDROMREADMODE1:
+               blocksize = CD_FRAMESIZE;
+               format = 2;
+               break;
+       case CDROMREADMODE2:
+               blocksize = CD_FRAMESIZE_RAW0;
+               break;
+       }
+       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 = kzalloc(blocksize, GFP_KERNEL);
+       if (cgc->buffer == NULL)
+               return -ENOMEM;
+
+       memset(&sense, 0, sizeof(sense));
+       cgc->sense = &sense;
+       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) {
+               /*
+                * SCSI-II devices are not required to support
+                * READ_CD, so let's try switching block size
+                */
+               /* FIXME: switch back again... */
+               ret = cdrom_switch_blocksize(cdi, blocksize);
+               if (ret)
+                       goto out;
+               cgc->sense = NULL;
+               ret = cdrom_read_cd(cdi, cgc, lba, blocksize, 1);
+               ret |= cdrom_switch_blocksize(cdi, blocksize);
+       }
+       if (!ret && copy_to_user(arg, cgc->buffer, blocksize))
+               ret = -EFAULT;
+out:
        kfree(cgc->buffer);
        return ret;
 }
 
 static noinline int mmc_ioctl_cdrom_read_audio(struct cdrom_device_info *cdi,
-                                       void __user *arg)
+                                              void __user *arg)
 {
        struct cdrom_read_audio ra;
        int lba;
 
-       IOCTL_IN(arg, struct cdrom_read_audio, ra);
+       if (copy_from_user(&ra, (struct cdrom_read_audio __user *)arg,
+                          sizeof(ra)))
+               return -EFAULT;
 
        if (ra.addr_format == CDROM_MSF)
                lba = msf_to_lba(ra.addr.msf.minute,
@@ -2937,12 +3011,13 @@ static noinline int mmc_ioctl_cdrom_read_audio(struct cdrom_device_info *cdi,
 }
 
 static noinline int mmc_ioctl_cdrom_subchannel(struct cdrom_device_info *cdi,
-                                       void __user *arg)
+                                              void __user *arg)
 {
        int ret;
        struct cdrom_subchnl q;
        u_char requested, back;
-       IOCTL_IN(arg, struct cdrom_subchnl, q);
+       if (copy_from_user(&q, (struct cdrom_subchnl __user *)arg, sizeof(q)))
+               return -EFAULT;
        requested = q.cdsc_format;
        if (!((requested == CDROM_MSF) ||
              (requested == CDROM_LBA)))
@@ -2954,19 +3029,21 @@ static noinline int mmc_ioctl_cdrom_subchannel(struct cdrom_device_info *cdi,
        back = q.cdsc_format; /* local copy */
        sanitize_format(&q.cdsc_absaddr, &back, requested);
        sanitize_format(&q.cdsc_reladdr, &q.cdsc_format, requested);
-       IOCTL_OUT(arg, struct cdrom_subchnl, q);
-       /* cdinfo(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */
+       if (copy_to_user((struct cdrom_subchnl __user *)arg, &q, sizeof(q)))
+               return -EFAULT;
+       /* cd_dbg(CD_DO_IOCTL, "CDROMSUBCHNL successful\n"); */
        return 0;
 }
 
 static noinline int mmc_ioctl_cdrom_play_msf(struct cdrom_device_info *cdi,
-                                       void __user *arg,
-                                       struct packet_command *cgc)
+                                            void __user *arg,
+                                            struct packet_command *cgc)
 {
        struct cdrom_device_ops *cdo = cdi->ops;
        struct cdrom_msf msf;
-       cdinfo(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");
-       IOCTL_IN(arg, struct cdrom_msf, msf);
+       cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYMSF\n");
+       if (copy_from_user(&msf, (struct cdrom_msf __user *)arg, sizeof(msf)))
+               return -EFAULT;
        cgc->cmd[0] = GPCMD_PLAY_AUDIO_MSF;
        cgc->cmd[3] = msf.cdmsf_min0;
        cgc->cmd[4] = msf.cdmsf_sec0;
@@ -2979,13 +3056,14 @@ static noinline int mmc_ioctl_cdrom_play_msf(struct cdrom_device_info *cdi,
 }
 
 static noinline int mmc_ioctl_cdrom_play_blk(struct cdrom_device_info *cdi,
-                                       void __user *arg,
-                                       struct packet_command *cgc)
+                                            void __user *arg,
+                                            struct packet_command *cgc)
 {
        struct cdrom_device_ops *cdo = cdi->ops;
        struct cdrom_blk blk;
-       cdinfo(CD_DO_IOCTL, "entering CDROMPLAYBLK\n");
-       IOCTL_IN(arg, struct cdrom_blk, blk);
+       cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYBLK\n");
+       if (copy_from_user(&blk, (struct cdrom_blk __user *)arg, sizeof(blk)))
+               return -EFAULT;
        cgc->cmd[0] = GPCMD_PLAY_AUDIO_10;
        cgc->cmd[2] = (blk.from >> 24) & 0xff;
        cgc->cmd[3] = (blk.from >> 16) & 0xff;
@@ -2998,9 +3076,9 @@ static noinline int mmc_ioctl_cdrom_play_blk(struct cdrom_device_info *cdi,
 }
 
 static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,
-                                       void __user *arg,
-                                       struct packet_command *cgc,
-                                       unsigned int cmd)
+                                          void __user *arg,
+                                          struct packet_command *cgc,
+                                          unsigned int cmd)
 {
        struct cdrom_volctrl volctrl;
        unsigned char buffer[32];
@@ -3008,9 +3086,11 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,
        unsigned short offset;
        int ret;
 
-       cdinfo(CD_DO_IOCTL, "entering CDROMVOLUME\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMVOLUME\n");
 
-       IOCTL_IN(arg, struct cdrom_volctrl, volctrl);
+       if (copy_from_user(&volctrl, (struct cdrom_volctrl __user *)arg,
+                          sizeof(volctrl)))
+               return -EFAULT;
 
        cgc->buffer = buffer;
        cgc->buflen = 24;
@@ -3030,14 +3110,14 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,
        if (offset + 16 > cgc->buflen) {
                cgc->buflen = offset + 16;
                ret = cdrom_mode_sense(cdi, cgc,
-                                       GPMODE_AUDIO_CTL_PAGE, 0);
+                                      GPMODE_AUDIO_CTL_PAGE, 0);
                if (ret)
                        return ret;
        }
 
        /* sanity check */
        if ((buffer[offset] & 0x3f) != GPMODE_AUDIO_CTL_PAGE ||
-                       buffer[offset + 1] < 14)
+           buffer[offset + 1] < 14)
                return -EINVAL;
 
        /* now we have the current volume settings. if it was only
@@ -3047,7 +3127,9 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,
                volctrl.channel1 = buffer[offset+11];
                volctrl.channel2 = buffer[offset+13];
                volctrl.channel3 = buffer[offset+15];
-               IOCTL_OUT(arg, struct cdrom_volctrl, volctrl);
+               if (copy_to_user((struct cdrom_volctrl __user *)arg, &volctrl,
+                                sizeof(volctrl)))
+                       return -EFAULT;
                return 0;
        }
                
@@ -3069,11 +3151,11 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,
 }
 
 static noinline int mmc_ioctl_cdrom_start_stop(struct cdrom_device_info *cdi,
-                                       struct packet_command *cgc,
-                                       int cmd)
+                                              struct packet_command *cgc,
+                                              int cmd)
 {
        struct cdrom_device_ops *cdo = cdi->ops;
-       cdinfo(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n");
        cgc->cmd[0] = GPCMD_START_STOP_UNIT;
        cgc->cmd[1] = 1;
        cgc->cmd[4] = (cmd == CDROMSTART) ? 1 : 0;
@@ -3082,11 +3164,11 @@ static noinline int mmc_ioctl_cdrom_start_stop(struct cdrom_device_info *cdi,
 }
 
 static noinline int mmc_ioctl_cdrom_pause_resume(struct cdrom_device_info *cdi,
-                                       struct packet_command *cgc,
-                                       int cmd)
+                                                struct packet_command *cgc,
+                                                int cmd)
 {
        struct cdrom_device_ops *cdo = cdi->ops;
-       cdinfo(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n");
        cgc->cmd[0] = GPCMD_PAUSE_RESUME;
        cgc->cmd[8] = (cmd == CDROMRESUME) ? 1 : 0;
        cgc->data_direction = CGC_DATA_NONE;
@@ -3094,8 +3176,8 @@ static noinline int mmc_ioctl_cdrom_pause_resume(struct cdrom_device_info *cdi,
 }
 
 static noinline int mmc_ioctl_dvd_read_struct(struct cdrom_device_info *cdi,
-                                               void __user *arg,
-                                               struct packet_command *cgc)
+                                             void __user *arg,
+                                             struct packet_command *cgc)
 {
        int ret;
        dvd_struct *s;
@@ -3108,7 +3190,7 @@ static noinline int mmc_ioctl_dvd_read_struct(struct cdrom_device_info *cdi,
        if (!s)
                return -ENOMEM;
 
-       cdinfo(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n");
+       cd_dbg(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n");
        if (copy_from_user(s, arg, size)) {
                kfree(s);
                return -EFAULT;
@@ -3126,44 +3208,48 @@ out:
 }
 
 static noinline int mmc_ioctl_dvd_auth(struct cdrom_device_info *cdi,
-                                       void __user *arg)
+                                      void __user *arg)
 {
        int ret;
        dvd_authinfo ai;
        if (!CDROM_CAN(CDC_DVD))
                return -ENOSYS;
-       cdinfo(CD_DO_IOCTL, "entering DVD_AUTH\n");
-       IOCTL_IN(arg, dvd_authinfo, ai);
+       cd_dbg(CD_DO_IOCTL, "entering DVD_AUTH\n");
+       if (copy_from_user(&ai, (dvd_authinfo __user *)arg, sizeof(ai)))
+               return -EFAULT;
        ret = dvd_do_auth(cdi, &ai);
        if (ret)
                return ret;
-       IOCTL_OUT(arg, dvd_authinfo, ai);
+       if (copy_to_user((dvd_authinfo __user *)arg, &ai, sizeof(ai)))
+               return -EFAULT;
        return 0;
 }
 
 static noinline int mmc_ioctl_cdrom_next_writable(struct cdrom_device_info *cdi,
-                                               void __user *arg)
+                                                 void __user *arg)
 {
        int ret;
        long next = 0;
-       cdinfo(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_NEXT_WRITABLE\n");
        ret = cdrom_get_next_writable(cdi, &next);
        if (ret)
                return ret;
-       IOCTL_OUT(arg, long, next);
+       if (copy_to_user((long __user *)arg, &next, sizeof(next)))
+               return -EFAULT;
        return 0;
 }
 
 static noinline int mmc_ioctl_cdrom_last_written(struct cdrom_device_info *cdi,
-                                               void __user *arg)
+                                                void __user *arg)
 {
        int ret;
        long last = 0;
-       cdinfo(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n");
+       cd_dbg(CD_DO_IOCTL, "entering CDROM_LAST_WRITTEN\n");
        ret = cdrom_get_last_written(cdi, &last);
        if (ret)
                return ret;
-       IOCTL_OUT(arg, long, last);
+       if (copy_to_user((long __user *)arg, &last, sizeof(last)))
+               return -EFAULT;
        return 0;
 }
 
@@ -3212,181 +3298,101 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
        return -ENOTTY;
 }
 
-static int cdrom_get_track_info(struct cdrom_device_info *cdi, __u16 track, __u8 type,
-                        track_information *ti)
-{
-       struct cdrom_device_ops *cdo = cdi->ops;
-       struct packet_command cgc;
-       int ret, buflen;
-
-       init_cdrom_command(&cgc, ti, 8, CGC_DATA_READ);
-       cgc.cmd[0] = GPCMD_READ_TRACK_RZONE_INFO;
-       cgc.cmd[1] = type & 3;
-       cgc.cmd[4] = (track & 0xff00) >> 8;
-       cgc.cmd[5] = track & 0xff;
-       cgc.cmd[8] = 8;
-       cgc.quiet = 1;
-
-       if ((ret = cdo->generic_packet(cdi, &cgc)))
-               return ret;
-       
-       buflen = be16_to_cpu(ti->track_information_length) +
-                    sizeof(ti->track_information_length);
-
-       if (buflen > sizeof(track_information))
-               buflen = sizeof(track_information);
-
-       cgc.cmd[8] = cgc.buflen = buflen;
-       if ((ret = cdo->generic_packet(cdi, &cgc)))
-               return ret;
-
-       /* return actual fill size */
-       return buflen;
-}
-
-/* requires CD R/RW */
-static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information *di)
+/*
+ * Just about every imaginable ioctl is supported in the Uniform layer
+ * these days.
+ * ATAPI / SCSI specific code now mainly resides in mmc_ioctl().
+ */
+int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev,
+               fmode_t mode, unsigned int cmd, unsigned long arg)
 {
-       struct cdrom_device_ops *cdo = cdi->ops;
-       struct packet_command cgc;
-       int ret, buflen;
-
-       /* set up command and get the disc info */
-       init_cdrom_command(&cgc, di, sizeof(*di), CGC_DATA_READ);
-       cgc.cmd[0] = GPCMD_READ_DISC_INFO;
-       cgc.cmd[8] = cgc.buflen = 2;
-       cgc.quiet = 1;
-
-       if ((ret = cdo->generic_packet(cdi, &cgc)))
-               return ret;
+       void __user *argp = (void __user *)arg;
+       int ret;
 
-       /* not all drives have the same disc_info length, so requeue
-        * packet with the length the drive tells us it can supply
+       /*
+        * Try the generic SCSI command ioctl's first.
         */
-       buflen = be16_to_cpu(di->disc_information_length) +
-                    sizeof(di->disc_information_length);
-
-       if (buflen > sizeof(disc_information))
-               buflen = sizeof(disc_information);
-
-       cgc.cmd[8] = cgc.buflen = buflen;
-       if ((ret = cdo->generic_packet(cdi, &cgc)))
+       ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp);
+       if (ret != -ENOTTY)
                return ret;
 
-       /* return actual fill size */
-       return buflen;
-}
-
-/* return the last written block on the CD-R media. this is for the udf
-   file system. */
-int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written)
-{
-       struct cdrom_tocentry toc;
-       disc_information di;
-       track_information ti;
-       __u32 last_track;
-       int ret = -1, ti_size;
-
-       if (!CDROM_CAN(CDC_GENERIC_PACKET))
-               goto use_toc;
-
-       ret = cdrom_get_disc_info(cdi, &di);
-       if (ret < (int)(offsetof(typeof(di), last_track_lsb)
-                       + sizeof(di.last_track_lsb)))
-               goto use_toc;
-
-       /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */
-       last_track = (di.last_track_msb << 8) | di.last_track_lsb;
-       ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti);
-       if (ti_size < (int)offsetof(typeof(ti), track_start))
-               goto use_toc;
-
-       /* if this track is blank, try the previous. */
-       if (ti.blank) {
-               if (last_track==1)
-                       goto use_toc;
-               last_track--;
-               ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti);
-       }
-
-       if (ti_size < (int)(offsetof(typeof(ti), track_size)
-                               + sizeof(ti.track_size)))
-               goto use_toc;
-
-       /* if last recorded field is valid, return it. */
-       if (ti.lra_v && ti_size >= (int)(offsetof(typeof(ti), last_rec_address)
-                               + sizeof(ti.last_rec_address))) {
-               *last_written = be32_to_cpu(ti.last_rec_address);
-       } else {
-               /* make it up instead */
-               *last_written = be32_to_cpu(ti.track_start) +
-                               be32_to_cpu(ti.track_size);
-               if (ti.free_blocks)
-                       *last_written -= (be32_to_cpu(ti.free_blocks) + 7);
+       switch (cmd) {
+       case CDROMMULTISESSION:
+               return cdrom_ioctl_multisession(cdi, argp);
+       case CDROMEJECT:
+               return cdrom_ioctl_eject(cdi);
+       case CDROMCLOSETRAY:
+               return cdrom_ioctl_closetray(cdi);
+       case CDROMEJECT_SW:
+               return cdrom_ioctl_eject_sw(cdi, arg);
+       case CDROM_MEDIA_CHANGED:
+               return cdrom_ioctl_media_changed(cdi, arg);
+       case CDROM_SET_OPTIONS:
+               return cdrom_ioctl_set_options(cdi, arg);
+       case CDROM_CLEAR_OPTIONS:
+               return cdrom_ioctl_clear_options(cdi, arg);
+       case CDROM_SELECT_SPEED:
+               return cdrom_ioctl_select_speed(cdi, arg);
+       case CDROM_SELECT_DISC:
+               return cdrom_ioctl_select_disc(cdi, arg);
+       case CDROMRESET:
+               return cdrom_ioctl_reset(cdi, bdev);
+       case CDROM_LOCKDOOR:
+               return cdrom_ioctl_lock_door(cdi, arg);
+       case CDROM_DEBUG:
+               return cdrom_ioctl_debug(cdi, arg);
+       case CDROM_GET_CAPABILITY:
+               return cdrom_ioctl_get_capability(cdi);
+       case CDROM_GET_MCN:
+               return cdrom_ioctl_get_mcn(cdi, argp);
+       case CDROM_DRIVE_STATUS:
+               return cdrom_ioctl_drive_status(cdi, arg);
+       case CDROM_DISC_STATUS:
+               return cdrom_ioctl_disc_status(cdi);
+       case CDROM_CHANGER_NSLOTS:
+               return cdrom_ioctl_changer_nslots(cdi);
        }
-       return 0;
 
-       /* this is where we end up if the drive either can't do a
-          GPCMD_READ_DISC_INFO or GPCMD_READ_TRACK_RZONE_INFO or if
-          it doesn't give enough information or fails. then we return
-          the toc contents. */
-use_toc:
-       toc.cdte_format = CDROM_MSF;
-       toc.cdte_track = CDROM_LEADOUT;
-       if ((ret = cdi->ops->audio_ioctl(cdi, CDROMREADTOCENTRY, &toc)))
-               return ret;
-       sanitize_format(&toc.cdte_addr, &toc.cdte_format, CDROM_LBA);
-       *last_written = toc.cdte_addr.lba;
-       return 0;
-}
-
-/* return the next writable block. also for udf file system. */
-static int cdrom_get_next_writable(struct cdrom_device_info *cdi, long *next_writable)
-{
-       disc_information di;
-       track_information ti;
-       __u16 last_track;
-       int ret, ti_size;
-
-       if (!CDROM_CAN(CDC_GENERIC_PACKET))
-               goto use_last_written;
-
-       ret = cdrom_get_disc_info(cdi, &di);
-       if (ret < 0 || ret < offsetof(typeof(di), last_track_lsb)
-                               + sizeof(di.last_track_lsb))
-               goto use_last_written;
-
-       /* if unit didn't return msb, it's zeroed by cdrom_get_disc_info */
-       last_track = (di.last_track_msb << 8) | di.last_track_lsb;
-       ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti);
-       if (ti_size < 0 || ti_size < offsetof(typeof(ti), track_start))
-               goto use_last_written;
-
-        /* if this track is blank, try the previous. */
-       if (ti.blank) {
-               if (last_track == 1)
-                       goto use_last_written;
-               last_track--;
-               ti_size = cdrom_get_track_info(cdi, last_track, 1, &ti);
-               if (ti_size < 0)
-                       goto use_last_written;
+       /*
+        * Use the ioctls that are implemented through the generic_packet()
+        * interface. this may look at bit funny, but if -ENOTTY is
+        * returned that particular ioctl is not implemented and we
+        * let it go through the device specific ones.
+        */
+       if (CDROM_CAN(CDC_GENERIC_PACKET)) {
+               ret = mmc_ioctl(cdi, cmd, arg);
+               if (ret != -ENOTTY)
+                       return ret;
        }
 
-       /* if next recordable address field is valid, use it. */
-       if (ti.nwa_v && ti_size >= offsetof(typeof(ti), next_writable)
-                               + sizeof(ti.next_writable)) {
-               *next_writable = be32_to_cpu(ti.next_writable);
-               return 0;
+       /*
+        * Note: most of the cd_dbg() calls are commented out here,
+        * because they fill up the sys log when CD players poll
+        * the drive.
+        */
+       switch (cmd) {
+       case CDROMSUBCHNL:
+               return cdrom_ioctl_get_subchnl(cdi, argp);
+       case CDROMREADTOCHDR:
+               return cdrom_ioctl_read_tochdr(cdi, argp);
+       case CDROMREADTOCENTRY:
+               return cdrom_ioctl_read_tocentry(cdi, argp);
+       case CDROMPLAYMSF:
+               return cdrom_ioctl_play_msf(cdi, argp);
+       case CDROMPLAYTRKIND:
+               return cdrom_ioctl_play_trkind(cdi, argp);
+       case CDROMVOLCTRL:
+               return cdrom_ioctl_volctrl(cdi, argp);
+       case CDROMVOLREAD:
+               return cdrom_ioctl_volread(cdi, argp);
+       case CDROMSTART:
+       case CDROMSTOP:
+       case CDROMPAUSE:
+       case CDROMRESUME:
+               return cdrom_ioctl_audioctl(cdi, cmd);
        }
 
-use_last_written:
-       if ((ret = cdrom_get_last_written(cdi, next_writable))) {
-               *next_writable = 0;
-               return ret;
-       } else {
-               *next_writable += 7;
-               return 0;
-       }
+       return -ENOSYS;
 }
 
 EXPORT_SYMBOL(cdrom_get_last_written);
@@ -3465,7 +3471,7 @@ static int cdrom_print_info(const char *header, int val, char *info,
        return 0;
 }
 
-static int cdrom_sysctl_info(ctl_table *ctl, int write,
+static int cdrom_sysctl_info(struct ctl_table *ctl, int write,
                            void __user *buffer, size_t *lenp, loff_t *ppos)
 {
        int pos;
@@ -3578,7 +3584,7 @@ static void cdrom_update_settings(void)
        mutex_unlock(&cdrom_mutex);
 }
 
-static int cdrom_sysctl_handler(ctl_table *ctl, int write,
+static int cdrom_sysctl_handler(struct ctl_table *ctl, int write,
                                void __user *buffer, size_t *lenp, loff_t *ppos)
 {
        int ret;
@@ -3604,7 +3610,7 @@ static int cdrom_sysctl_handler(ctl_table *ctl, int write,
 }
 
 /* Place files in /proc/sys/dev/cdrom */
-static ctl_table cdrom_table[] = {
+static struct ctl_table cdrom_table[] = {
        {
                .procname       = "info",
                .data           = &cdrom_sysctl_settings.info, 
@@ -3650,7 +3656,7 @@ static ctl_table cdrom_table[] = {
        { }
 };
 
-static ctl_table cdrom_cdrom_table[] = {
+static struct ctl_table cdrom_cdrom_table[] = {
        {
                .procname       = "cdrom",
                .maxlen         = 0,
@@ -3661,7 +3667,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,