]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/cdrom/mcdx.c
Remove legacy CDROM drivers
[linux-2.6-omap-h63xx.git] / drivers / cdrom / mcdx.c
diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c
deleted file mode 100644 (file)
index 972ee9c..0000000
+++ /dev/null
@@ -1,1943 +0,0 @@
-/*
- * The Mitsumi CDROM interface
- * Copyright (C) 1995 1996 Heiko Schlittermann <heiko@lotte.sax.de>
- * VERSION: 2.14(hs)
- *
- * ... anyway, I'm back again, thanks to Marcin, he adopted
- * large portions of my code (at least the parts containing
- * my main thoughts ...)
- *
- ****************** H E L P *********************************
- * If you ever plan to update your CD ROM drive and perhaps
- * want to sell or simply give away your Mitsumi FX-001[DS]
- * -- Please --
- * mail me (heiko@lotte.sax.de).  When my last drive goes
- * ballistic no more driver support will be available from me!
- *************************************************************
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Thanks to
- *  The Linux Community at all and ...
- *  Martin Harriss (he wrote the first Mitsumi Driver)
- *  Eberhard Moenkeberg (he gave me much support and the initial kick)
- *  Bernd Huebner, Ruediger Helsch (Unifix-Software GmbH, they
- *      improved the original driver)
- *  Jon Tombs, Bjorn Ekwall (module support)
- *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
- *  Gerd Knorr (he lent me his PhotoCD)
- *  Nils Faerber and Roger E. Wolff (extensively tested the LU portion)
- *  Andreas Kies (testing the mysterious hang-ups)
- *  Heiko Eissfeldt (VERIFY_READ/WRITE)
- *  Marcin Dalecki (improved performance, shortened code)
- *  ... somebody forgotten?
- *
- *  9 November 1999 -- Make kernel-parameter implementation work with 2.3.x 
- *                    Removed init_module & cleanup_module in favor of 
- *                    module_init & module_exit.
- *                    Torben Mathiasen <tmm@image.dk>
- */
-
-
-#ifdef RCS
-static const char *mcdx_c_version
-    = "$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $";
-#endif
-
-#include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/cdrom.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#include <asm/current.h>
-#include <asm/uaccess.h>
-
-#include <linux/major.h>
-#define MAJOR_NR MITSUMI_X_CDROM_MAJOR
-#include <linux/blkdev.h>
-
-#include "mcdx.h"
-
-#ifndef HZ
-#error HZ not defined
-#endif
-
-#define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)
-
-#if !MCDX_QUIET
-#define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)
-#else
-#define xinfo(fmt, args...) { ; }
-#endif
-
-#if MCDX_DEBUG
-#define xtrace(lvl, fmt, args...) \
-               { if (lvl > 0) \
-                       { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }
-#define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args)
-#else
-#define xtrace(lvl, fmt, args...) { ; }
-#define xdebug(fmt, args...) { ; }
-#endif
-
-/* CONSTANTS *******************************************************/
-
-/* Following are the number of sectors we _request_ from the drive
-   every time an access outside the already requested range is done.
-   The _direct_ size is the number of sectors we're allowed to skip
-   directly (performing a read instead of requesting the new sector
-   needed */
-static const int REQUEST_SIZE = 800;   /* should be less then 255 * 4 */
-static const int DIRECT_SIZE = 400;    /* should be less then REQUEST_SIZE */
-
-enum drivemodes { TOC, DATA, RAW, COOKED };
-enum datamodes { MODE0, MODE1, MODE2 };
-enum resetmodes { SOFT, HARD };
-
-static const int SINGLE = 0x01;                /* single speed drive (FX001S, LU) */
-static const int DOUBLE = 0x02;                /* double speed drive (FX001D, ..? */
-static const int DOOR = 0x04;          /* door locking capability */
-static const int MULTI = 0x08;         /* multi session capability */
-
-static const unsigned char READ1X = 0xc0;
-static const unsigned char READ2X = 0xc1;
-
-
-/* DECLARATIONS ****************************************************/
-struct s_subqcode {
-       unsigned char control;
-       unsigned char tno;
-       unsigned char index;
-       struct cdrom_msf0 tt;
-       struct cdrom_msf0 dt;
-};
-
-struct s_diskinfo {
-       unsigned int n_first;
-       unsigned int n_last;
-       struct cdrom_msf0 msf_leadout;
-       struct cdrom_msf0 msf_first;
-};
-
-struct s_multi {
-       unsigned char multi;
-       struct cdrom_msf0 msf_last;
-};
-
-struct s_version {
-       unsigned char code;
-       unsigned char ver;
-};
-
-/* Per drive/controller stuff **************************************/
-
-struct s_drive_stuff {
-       /* waitqueues */
-       wait_queue_head_t busyq;
-       wait_queue_head_t lockq;
-       wait_queue_head_t sleepq;
-
-       /* flags */
-       volatile int introk;    /* status of last irq operation */
-       volatile int busy;      /* drive performs an operation */
-       volatile int lock;      /* exclusive usage */
-
-       /* cd infos */
-       struct s_diskinfo di;
-       struct s_multi multi;
-       struct s_subqcode *toc; /* first entry of the toc array */
-       struct s_subqcode start;
-       struct s_subqcode stop;
-       int xa;                 /* 1 if xa disk */
-       int audio;              /* 1 if audio disk */
-       int audiostatus;
-
-       /* `buffer' control */
-       volatile int valid;     /* pending, ..., values are valid */
-       volatile int pending;   /* next sector to be read */
-       volatile int low_border;        /* first sector not to be skipped direct */
-       volatile int high_border;       /* first sector `out of area' */
-#ifdef AK2
-       volatile int int_err;
-#endif                         /* AK2 */
-
-       /* adds and odds */
-       unsigned wreg_data;     /* w data */
-       unsigned wreg_reset;    /* w hardware reset */
-       unsigned wreg_hcon;     /* w hardware conf */
-       unsigned wreg_chn;      /* w channel */
-       unsigned rreg_data;     /* r data */
-       unsigned rreg_status;   /* r status */
-
-       int irq;                /* irq used by this drive */
-       int present;            /* drive present and its capabilities */
-       unsigned char readcmd;  /* read cmd depends on single/double speed */
-       unsigned char playcmd;  /* play should always be single speed */
-       unsigned int xxx;       /* set if changed, reset while open */
-       unsigned int yyy;       /* set if changed, reset by media_changed */
-       int users;              /* keeps track of open/close */
-       int lastsector;         /* last block accessible */
-       int status;             /* last operation's error / status */
-       int readerrs;           /* # of blocks read w/o error */
-       struct cdrom_device_info info;
-       struct gendisk *disk;
-};
-
-
-/* Prototypes ******************************************************/
-
-/*     The following prototypes are already declared elsewhere.  They are
-       repeated here to show what's going on.  And to sense, if they're
-       changed elsewhere. */
-
-static int mcdx_init(void);
-
-static int mcdx_block_open(struct inode *inode, struct file *file)
-{
-       struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
-       return cdrom_open(&p->info, inode, file);
-}
-
-static int mcdx_block_release(struct inode *inode, struct file *file)
-{
-       struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
-       return cdrom_release(&p->info, file);
-}
-
-static int mcdx_block_ioctl(struct inode *inode, struct file *file,
-                               unsigned cmd, unsigned long arg)
-{
-       struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
-       return cdrom_ioctl(file, &p->info, inode, cmd, arg);
-}
-
-static int mcdx_block_media_changed(struct gendisk *disk)
-{
-       struct s_drive_stuff *p = disk->private_data;
-       return cdrom_media_changed(&p->info);
-}
-
-static struct block_device_operations mcdx_bdops =
-{
-       .owner          = THIS_MODULE,
-       .open           = mcdx_block_open,
-       .release        = mcdx_block_release,
-       .ioctl          = mcdx_block_ioctl,
-       .media_changed  = mcdx_block_media_changed,
-};
-
-
-/*     Indirect exported functions. These functions are exported by their
-       addresses, such as mcdx_open and mcdx_close in the
-       structure mcdx_dops. */
-
-/* exported by file_ops */
-static int mcdx_open(struct cdrom_device_info *cdi, int purpose);
-static void mcdx_close(struct cdrom_device_info *cdi);
-static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr);
-static int mcdx_tray_move(struct cdrom_device_info *cdi, int position);
-static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock);
-static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
-                           unsigned int cmd, void *arg);
-
-/* misc internal support functions */
-static void log2msf(unsigned int, struct cdrom_msf0 *);
-static unsigned int msf2log(const struct cdrom_msf0 *);
-static unsigned int uint2bcd(unsigned int);
-static unsigned int bcd2uint(unsigned char);
-static unsigned port(int *);
-static int irq(int *);
-static void mcdx_delay(struct s_drive_stuff *, long jifs);
-static int mcdx_transfer(struct s_drive_stuff *, char *buf, int sector,
-                        int nr_sectors);
-static int mcdx_xfer(struct s_drive_stuff *, char *buf, int sector,
-                    int nr_sectors);
-
-static int mcdx_config(struct s_drive_stuff *, int);
-static int mcdx_requestversion(struct s_drive_stuff *, struct s_version *,
-                              int);
-static int mcdx_stop(struct s_drive_stuff *, int);
-static int mcdx_hold(struct s_drive_stuff *, int);
-static int mcdx_reset(struct s_drive_stuff *, enum resetmodes, int);
-static int mcdx_setdrivemode(struct s_drive_stuff *, enum drivemodes, int);
-static int mcdx_setdatamode(struct s_drive_stuff *, enum datamodes, int);
-static int mcdx_requestsubqcode(struct s_drive_stuff *,
-                               struct s_subqcode *, int);
-static int mcdx_requestmultidiskinfo(struct s_drive_stuff *,
-                                    struct s_multi *, int);
-static int mcdx_requesttocdata(struct s_drive_stuff *, struct s_diskinfo *,
-                              int);
-static int mcdx_getstatus(struct s_drive_stuff *, int);
-static int mcdx_getval(struct s_drive_stuff *, int to, int delay, char *);
-static int mcdx_talk(struct s_drive_stuff *,
-                    const unsigned char *cmd, size_t,
-                    void *buffer, size_t size, unsigned int timeout, int);
-static int mcdx_readtoc(struct s_drive_stuff *);
-static int mcdx_playtrk(struct s_drive_stuff *, const struct cdrom_ti *);
-static int mcdx_playmsf(struct s_drive_stuff *, const struct cdrom_msf *);
-static int mcdx_setattentuator(struct s_drive_stuff *,
-                              struct cdrom_volctrl *, int);
-
-/* static variables ************************************************/
-
-static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
-static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES];
-static DEFINE_SPINLOCK(mcdx_lock);
-static struct request_queue *mcdx_queue;
-
-/* You can only set the first two pairs, from old MODULE_PARM code.  */
-static int mcdx_set(const char *val, struct kernel_param *kp)
-{
-       get_options((char *)val, 4, (int *)mcdx_drive_map);
-       return 0;
-}
-module_param_call(mcdx, mcdx_set, NULL, NULL, 0);
-
-static struct cdrom_device_ops mcdx_dops = {
-       .open           = mcdx_open,
-       .release        = mcdx_close,
-       .media_changed  = mcdx_media_changed,
-       .tray_move      = mcdx_tray_move,
-       .lock_door      = mcdx_lockdoor,
-       .audio_ioctl    = mcdx_audio_ioctl,
-       .capability     = CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED |
-                         CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
-};
-
-/* KERNEL INTERFACE FUNCTIONS **************************************/
-
-
-static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
-                           unsigned int cmd, void *arg)
-{
-       struct s_drive_stuff *stuffp = cdi->handle;
-
-       if (!stuffp->present)
-               return -ENXIO;
-
-       if (stuffp->xxx) {
-               if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
-                       stuffp->lastsector = -1;
-               } else {
-                       stuffp->lastsector = (CD_FRAMESIZE / 512)
-                           * msf2log(&stuffp->di.msf_leadout) - 1;
-               }
-
-               if (stuffp->toc) {
-                       kfree(stuffp->toc);
-                       stuffp->toc = NULL;
-                       if (-1 == mcdx_readtoc(stuffp))
-                               return -1;
-               }
-
-               stuffp->xxx = 0;
-       }
-
-       switch (cmd) {
-       case CDROMSTART:{
-                       xtrace(IOCTL, "ioctl() START\n");
-                       /* Spin up the drive.  Don't think we can do this.
-                          * For now, ignore it.
-                        */
-                       return 0;
-               }
-
-       case CDROMSTOP:{
-                       xtrace(IOCTL, "ioctl() STOP\n");
-                       stuffp->audiostatus = CDROM_AUDIO_INVALID;
-                       if (-1 == mcdx_stop(stuffp, 1))
-                               return -EIO;
-                       return 0;
-               }
-
-       case CDROMPLAYTRKIND:{
-                       struct cdrom_ti *ti = (struct cdrom_ti *) arg;
-
-                       xtrace(IOCTL, "ioctl() PLAYTRKIND\n");
-                       if ((ti->cdti_trk0 < stuffp->di.n_first)
-                           || (ti->cdti_trk0 > stuffp->di.n_last)
-                           || (ti->cdti_trk1 < stuffp->di.n_first))
-                               return -EINVAL;
-                       if (ti->cdti_trk1 > stuffp->di.n_last)
-                               ti->cdti_trk1 = stuffp->di.n_last;
-                       xtrace(PLAYTRK, "ioctl() track %d to %d\n",
-                              ti->cdti_trk0, ti->cdti_trk1);
-                       return mcdx_playtrk(stuffp, ti);
-               }
-
-       case CDROMPLAYMSF:{
-                       struct cdrom_msf *msf = (struct cdrom_msf *) arg;
-
-                       xtrace(IOCTL, "ioctl() PLAYMSF\n");
-
-                       if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)
-                           && (-1 == mcdx_hold(stuffp, 1)))
-                               return -EIO;
-
-                       msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0);
-                       msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0);
-                       msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0);
-
-                       msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1);
-                       msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1);
-                       msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1);
-
-                       stuffp->stop.dt.minute = msf->cdmsf_min1;
-                       stuffp->stop.dt.second = msf->cdmsf_sec1;
-                       stuffp->stop.dt.frame = msf->cdmsf_frame1;
-
-                       return mcdx_playmsf(stuffp, msf);
-               }
-
-       case CDROMRESUME:{
-                       xtrace(IOCTL, "ioctl() RESUME\n");
-                       return mcdx_playtrk(stuffp, NULL);
-               }
-
-       case CDROMREADTOCENTRY:{
-                       struct cdrom_tocentry *entry =
-                           (struct cdrom_tocentry *) arg;
-                       struct s_subqcode *tp = NULL;
-                       xtrace(IOCTL, "ioctl() READTOCENTRY\n");
-
-                       if (-1 == mcdx_readtoc(stuffp))
-                               return -1;
-                       if (entry->cdte_track == CDROM_LEADOUT)
-                               tp = &stuffp->toc[stuffp->di.n_last -
-                                                 stuffp->di.n_first + 1];
-                       else if (entry->cdte_track > stuffp->di.n_last
-                                || entry->cdte_track < stuffp->di.n_first)
-                               return -EINVAL;
-                       else
-                               tp = &stuffp->toc[entry->cdte_track -
-                                                 stuffp->di.n_first];
-
-                       if (NULL == tp)
-                               return -EIO;
-                       entry->cdte_adr = tp->control;
-                       entry->cdte_ctrl = tp->control >> 4;
-                       /* Always return stuff in MSF, and let the Uniform cdrom driver
-                          worry about what the user actually wants */
-                       entry->cdte_addr.msf.minute =
-                           bcd2uint(tp->dt.minute);
-                       entry->cdte_addr.msf.second =
-                           bcd2uint(tp->dt.second);
-                       entry->cdte_addr.msf.frame =
-                           bcd2uint(tp->dt.frame);
-                       return 0;
-               }
-
-       case CDROMSUBCHNL:{
-                       struct cdrom_subchnl *sub =
-                           (struct cdrom_subchnl *) arg;
-                       struct s_subqcode q;
-
-                       xtrace(IOCTL, "ioctl() SUBCHNL\n");
-
-                       if (-1 == mcdx_requestsubqcode(stuffp, &q, 2))
-                               return -EIO;
-
-                       xtrace(SUBCHNL, "audiostatus: %x\n",
-                              stuffp->audiostatus);
-                       sub->cdsc_audiostatus = stuffp->audiostatus;
-                       sub->cdsc_adr = q.control;
-                       sub->cdsc_ctrl = q.control >> 4;
-                       sub->cdsc_trk = bcd2uint(q.tno);
-                       sub->cdsc_ind = bcd2uint(q.index);
-
-                       xtrace(SUBCHNL, "trk %d, ind %d\n",
-                              sub->cdsc_trk, sub->cdsc_ind);
-                       /* Always return stuff in MSF, and let the Uniform cdrom driver
-                          worry about what the user actually wants */
-                       sub->cdsc_absaddr.msf.minute =
-                           bcd2uint(q.dt.minute);
-                       sub->cdsc_absaddr.msf.second =
-                           bcd2uint(q.dt.second);
-                       sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
-                       sub->cdsc_reladdr.msf.minute =
-                           bcd2uint(q.tt.minute);
-                       sub->cdsc_reladdr.msf.second =
-                           bcd2uint(q.tt.second);
-                       sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
-                       xtrace(SUBCHNL,
-                              "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
-                              sub->cdsc_absaddr.msf.minute,
-                              sub->cdsc_absaddr.msf.second,
-                              sub->cdsc_absaddr.msf.frame,
-                              sub->cdsc_reladdr.msf.minute,
-                              sub->cdsc_reladdr.msf.second,
-                              sub->cdsc_reladdr.msf.frame);
-
-                       return 0;
-               }
-
-       case CDROMREADTOCHDR:{
-                       struct cdrom_tochdr *toc =
-                           (struct cdrom_tochdr *) arg;
-
-                       xtrace(IOCTL, "ioctl() READTOCHDR\n");
-                       toc->cdth_trk0 = stuffp->di.n_first;
-                       toc->cdth_trk1 = stuffp->di.n_last;
-                       xtrace(TOCHDR,
-                              "ioctl() track0 = %d, track1 = %d\n",
-                              stuffp->di.n_first, stuffp->di.n_last);
-                       return 0;
-               }
-
-       case CDROMPAUSE:{
-                       xtrace(IOCTL, "ioctl() PAUSE\n");
-                       if (stuffp->audiostatus != CDROM_AUDIO_PLAY)
-                               return -EINVAL;
-                       if (-1 == mcdx_stop(stuffp, 1))
-                               return -EIO;
-                       stuffp->audiostatus = CDROM_AUDIO_PAUSED;
-                       if (-1 ==
-                           mcdx_requestsubqcode(stuffp, &stuffp->start,
-                                                1))
-                               return -EIO;
-                       return 0;
-               }
-
-       case CDROMMULTISESSION:{
-                       struct cdrom_multisession *ms =
-                           (struct cdrom_multisession *) arg;
-                       xtrace(IOCTL, "ioctl() MULTISESSION\n");
-                       /* Always return stuff in LBA, and let the Uniform cdrom driver
-                          worry about what the user actually wants */
-                       ms->addr.lba = msf2log(&stuffp->multi.msf_last);
-                       ms->xa_flag = !!stuffp->multi.multi;
-                       xtrace(MS,
-                              "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
-                              ms->xa_flag, ms->addr.lba,
-                              stuffp->multi.msf_last.minute,
-                              stuffp->multi.msf_last.second,
-                              stuffp->multi.msf_last.frame);
-
-                       return 0;
-               }
-
-       case CDROMEJECT:{
-                       xtrace(IOCTL, "ioctl() EJECT\n");
-                       if (stuffp->users > 1)
-                               return -EBUSY;
-                       return (mcdx_tray_move(cdi, 1));
-               }
-
-       case CDROMCLOSETRAY:{
-                       xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n");
-                       return (mcdx_tray_move(cdi, 0));
-               }
-
-       case CDROMVOLCTRL:{
-                       struct cdrom_volctrl *volctrl =
-                           (struct cdrom_volctrl *) arg;
-                       xtrace(IOCTL, "ioctl() VOLCTRL\n");
-
-#if 0                          /* not tested! */
-                       /* adjust for the weirdness of workman (md) */
-                       /* can't test it (hs) */
-                       volctrl.channel2 = volctrl.channel1;
-                       volctrl.channel1 = volctrl.channel3 = 0x00;
-#endif
-                       return mcdx_setattentuator(stuffp, volctrl, 2);
-               }
-
-       default:
-               return -EINVAL;
-       }
-}
-
-static void do_mcdx_request(request_queue_t * q)
-{
-       struct s_drive_stuff *stuffp;
-       struct request *req;
-
-      again:
-
-       req = elv_next_request(q);
-       if (!req)
-               return;
-
-       stuffp = req->rq_disk->private_data;
-
-       if (!stuffp->present) {
-               xwarn("do_request(): bad device: %s\n",req->rq_disk->disk_name);
-               xtrace(REQUEST, "end_request(0): bad device\n");
-               end_request(req, 0);
-               return;
-       }
-
-       if (stuffp->audio) {
-               xwarn("do_request() attempt to read from audio cd\n");
-               xtrace(REQUEST, "end_request(0): read from audio\n");
-               end_request(req, 0);
-               return;
-       }
-
-       xtrace(REQUEST, "do_request() (%lu + %lu)\n",
-              req->sector, req->nr_sectors);
-
-       if (rq_data_dir(req) != READ) {
-               xwarn("do_request(): non-read command to cd!!\n");
-               xtrace(REQUEST, "end_request(0): write\n");
-               end_request(req, 0);
-               return;
-       }
-       else {
-               stuffp->status = 0;
-               while (req->nr_sectors) {
-                       int i;
-
-                       i = mcdx_transfer(stuffp,
-                                         req->buffer,
-                                         req->sector,
-                                         req->nr_sectors);
-
-                       if (i == -1) {
-                               end_request(req, 0);
-                               goto again;
-                       }
-                       req->sector += i;
-                       req->nr_sectors -= i;
-                       req->buffer += (i * 512);
-               }
-               end_request(req, 1);
-               goto again;
-
-               xtrace(REQUEST, "end_request(1)\n");
-               end_request(req, 1);
-       }
-
-       goto again;
-}
-
-static int mcdx_open(struct cdrom_device_info *cdi, int purpose)
-{
-       struct s_drive_stuff *stuffp;
-       xtrace(OPENCLOSE, "open()\n");
-       stuffp = cdi->handle;
-       if (!stuffp->present)
-               return -ENXIO;
-
-       /* Make the modules looking used ... (thanx bjorn).
-        * But we shouldn't forget to decrement the module counter
-        * on error return */
-
-       /* this is only done to test if the drive talks with us */
-       if (-1 == mcdx_getstatus(stuffp, 1))
-               return -EIO;
-
-       if (stuffp->xxx) {
-
-               xtrace(OPENCLOSE, "open() media changed\n");
-               stuffp->audiostatus = CDROM_AUDIO_INVALID;
-               stuffp->readcmd = 0;
-               xtrace(OPENCLOSE, "open() Request multisession info\n");
-               if (-1 ==
-                   mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6))
-                       xinfo("No multidiskinfo\n");
-       } else {
-               /* multisession ? */
-               if (!stuffp->multi.multi)
-                       stuffp->multi.msf_last.second = 2;
-
-               xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
-                      stuffp->multi.multi,
-                      stuffp->multi.msf_last.minute,
-                      stuffp->multi.msf_last.second,
-                      stuffp->multi.msf_last.frame);
-
-               {;
-               }               /* got multisession information */
-               /* request the disks table of contents (aka diskinfo) */
-               if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
-
-                       stuffp->lastsector = -1;
-
-               } else {
-
-                       stuffp->lastsector = (CD_FRAMESIZE / 512)
-                           * msf2log(&stuffp->di.msf_leadout) - 1;
-
-                       xtrace(OPENCLOSE,
-                              "open() start %d (%02x:%02x.%02x) %d\n",
-                              stuffp->di.n_first,
-                              stuffp->di.msf_first.minute,
-                              stuffp->di.msf_first.second,
-                              stuffp->di.msf_first.frame,
-                              msf2log(&stuffp->di.msf_first));
-                       xtrace(OPENCLOSE,
-                              "open() last %d (%02x:%02x.%02x) %d\n",
-                              stuffp->di.n_last,
-                              stuffp->di.msf_leadout.minute,
-                              stuffp->di.msf_leadout.second,
-                              stuffp->di.msf_leadout.frame,
-                              msf2log(&stuffp->di.msf_leadout));
-               }
-
-               if (stuffp->toc) {
-                       xtrace(MALLOC, "open() free old toc @ %p\n",
-                              stuffp->toc);
-                       kfree(stuffp->toc);
-
-                       stuffp->toc = NULL;
-               }
-
-               xtrace(OPENCLOSE, "open() init irq generation\n");
-               if (-1 == mcdx_config(stuffp, 1))
-                       return -EIO;
-#ifdef FALLBACK
-               /* Set the read speed */
-               xwarn("AAA %x AAA\n", stuffp->readcmd);
-               if (stuffp->readerrs)
-                       stuffp->readcmd = READ1X;
-               else
-                       stuffp->readcmd =
-                           stuffp->present | SINGLE ? READ1X : READ2X;
-               xwarn("XXX %x XXX\n", stuffp->readcmd);
-#else
-               stuffp->readcmd =
-                   stuffp->present | SINGLE ? READ1X : READ2X;
-#endif
-
-               /* try to get the first sector, iff any ... */
-               if (stuffp->lastsector >= 0) {
-                       char buf[512];
-                       int ans;
-                       int tries;
-
-                       stuffp->xa = 0;
-                       stuffp->audio = 0;
-
-                       for (tries = 6; tries; tries--) {
-
-                               stuffp->introk = 1;
-
-                               xtrace(OPENCLOSE, "open() try as %s\n",
-                                      stuffp->xa ? "XA" : "normal");
-                               /* set data mode */
-                               if (-1 == (ans = mcdx_setdatamode(stuffp,
-                                                                 stuffp->
-                                                                 xa ?
-                                                                 MODE2 :
-                                                                 MODE1,
-                                                                 1))) {
-                                       /* return -EIO; */
-                                       stuffp->xa = 0;
-                                       break;
-                               }
-
-                               if ((stuffp->audio = e_audio(ans)))
-                                       break;
-
-                               while (0 ==
-                                      (ans =
-                                       mcdx_transfer(stuffp, buf, 0, 1)));
-
-                               if (ans == 1)
-                                       break;
-                               stuffp->xa = !stuffp->xa;
-                       }
-               }
-               /* xa disks will be read in raw mode, others not */
-               if (-1 == mcdx_setdrivemode(stuffp,
-                                           stuffp->xa ? RAW : COOKED,
-                                           1))
-                       return -EIO;
-               if (stuffp->audio) {
-                       xinfo("open() audio disk found\n");
-               } else if (stuffp->lastsector >= 0) {
-                       xinfo("open() %s%s disk found\n",
-                             stuffp->xa ? "XA / " : "",
-                             stuffp->multi.
-                             multi ? "Multi Session" : "Single Session");
-               }
-       }
-       stuffp->xxx = 0;
-       stuffp->users++;
-       return 0;
-}
-
-static void mcdx_close(struct cdrom_device_info *cdi)
-{
-       struct s_drive_stuff *stuffp;
-
-       xtrace(OPENCLOSE, "close()\n");
-
-       stuffp = cdi->handle;
-
-       --stuffp->users;
-}
-
-static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr)
-/*     Return: 1 if media changed since last call to this function
-                       0 otherwise */
-{
-       struct s_drive_stuff *stuffp;
-
-       xinfo("mcdx_media_changed called for device %s\n", cdi->name);
-
-       stuffp = cdi->handle;
-       mcdx_getstatus(stuffp, 1);
-
-       if (stuffp->yyy == 0)
-               return 0;
-
-       stuffp->yyy = 0;
-       return 1;
-}
-
-#ifndef MODULE
-static int __init mcdx_setup(char *str)
-{
-       int pi[4];
-       (void) get_options(str, ARRAY_SIZE(pi), pi);
-
-       if (pi[0] > 0)
-               mcdx_drive_map[0][0] = pi[1];
-       if (pi[0] > 1)
-               mcdx_drive_map[0][1] = pi[2];
-       return 1;
-}
-
-__setup("mcdx=", mcdx_setup);
-
-#endif
-
-/* DIRTY PART ******************************************************/
-
-static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
-/* This routine is used for sleeping.
- * A jifs value <0 means NO sleeping,
- *              =0 means minimal sleeping (let the kernel
- *                 run for other processes)
- *              >0 means at least sleep for that amount.
- *     May be we could use a simple count loop w/ jumps to itself, but
- *     I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
-{
-       if (jifs < 0)
-               return;
-
-       xtrace(SLEEP, "*** delay: sleepq\n");
-       interruptible_sleep_on_timeout(&stuff->sleepq, jifs);
-       xtrace(SLEEP, "delay awoken\n");
-       if (signal_pending(current)) {
-               xtrace(SLEEP, "got signal\n");
-       }
-}
-
-static irqreturn_t mcdx_intr(int irq, void *dev_id)
-{
-       struct s_drive_stuff *stuffp = dev_id;
-       unsigned char b;
-
-#ifdef AK2
-       if (!stuffp->busy && stuffp->pending)
-               stuffp->int_err = 1;
-
-#endif                         /* AK2 */
-       /* get the interrupt status */
-       b = inb(stuffp->rreg_status);
-       stuffp->introk = ~b & MCDX_RBIT_DTEN;
-
-       /* NOTE: We only should get interrupts if the data we
-        * requested are ready to transfer.
-        * But the drive seems to generate ``asynchronous'' interrupts
-        * on several error conditions too.  (Despite the err int enable
-        * setting during initialisation) */
-
-       /* if not ok, read the next byte as the drives status */
-       if (!stuffp->introk) {
-               xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b);
-               if (~b & MCDX_RBIT_STEN) {
-                       xinfo("intr() irq %d    status 0x%02x\n",
-                             irq, inb(stuffp->rreg_data));
-               } else {
-                       xinfo("intr() irq %d ambiguous hw status\n", irq);
-               }
-       } else {
-               xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b);
-       }
-
-       stuffp->busy = 0;
-       wake_up_interruptible(&stuffp->busyq);
-       return IRQ_HANDLED;
-}
-
-
-static int mcdx_talk(struct s_drive_stuff *stuffp,
-         const unsigned char *cmd, size_t cmdlen,
-         void *buffer, size_t size, unsigned int timeout, int tries)
-/* Send a command to the drive, wait for the result.
- * returns -1 on timeout, drive status otherwise
- * If buffer is not zero, the result (length size) is stored there.
- * If buffer is zero the size should be the number of bytes to read
- * from the drive.  These bytes are discarded.
- */
-{
-       int st;
-       char c;
-       int discard;
-
-       /* Somebody wants the data read? */
-       if ((discard = (buffer == NULL)))
-               buffer = &c;
-
-       while (stuffp->lock) {
-               xtrace(SLEEP, "*** talk: lockq\n");
-               interruptible_sleep_on(&stuffp->lockq);
-               xtrace(SLEEP, "talk: awoken\n");
-       }
-
-       stuffp->lock = 1;
-
-       /* An operation other then reading data destroys the
-          * data already requested and remembered in stuffp->request, ... */
-       stuffp->valid = 0;
-
-#if MCDX_DEBUG & TALK
-       {
-               unsigned char i;
-               xtrace(TALK,
-                      "talk() %d / %d tries, res.size %d, command 0x%02x",
-                      tries, timeout, size, (unsigned char) cmd[0]);
-               for (i = 1; i < cmdlen; i++)
-                       xtrace(TALK, " 0x%02x", cmd[i]);
-               xtrace(TALK, "\n");
-       }
-#endif
-
-       /*  give up if all tries are done (bad) or if the status
-        *  st != -1 (good) */
-       for (st = -1; st == -1 && tries; tries--) {
-
-               char *bp = (char *) buffer;
-               size_t sz = size;
-
-               outsb(stuffp->wreg_data, cmd, cmdlen);
-               xtrace(TALK, "talk() command sent\n");
-
-               /* get the status byte */
-               if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
-                       xinfo("talk() %02x timed out (status), %d tr%s left\n",
-                            cmd[0], tries - 1, tries == 2 ? "y" : "ies");
-                       continue;
-               }
-               st = *bp;
-               sz--;
-               if (!discard)
-                       bp++;
-
-               xtrace(TALK, "talk() got status 0x%02x\n", st);
-
-               /* command error? */
-               if (e_cmderr(st)) {
-                       xwarn("command error cmd = %02x %s \n",
-                             cmd[0], cmdlen > 1 ? "..." : "");
-                       st = -1;
-                       continue;
-               }
-
-               /* audio status? */
-               if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
-                       stuffp->audiostatus =
-                           e_audiobusy(st) ? CDROM_AUDIO_PLAY :
-                           CDROM_AUDIO_NO_STATUS;
-               else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
-                        && e_audiobusy(st) == 0)
-                       stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
-
-               /* media change? */
-               if (e_changed(st)) {
-                       xinfo("talk() media changed\n");
-                       stuffp->xxx = stuffp->yyy = 1;
-               }
-
-               /* now actually get the data */
-               while (sz--) {
-                       if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
-                               xinfo("talk() %02x timed out (data), %d tr%s left\n",
-                                    cmd[0], tries - 1,
-                                    tries == 2 ? "y" : "ies");
-                               st = -1;
-                               break;
-                       }
-                       if (!discard)
-                               bp++;
-                       xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1));
-               }
-       }
-
-#if !MCDX_QUIET
-       if (!tries && st == -1)
-               xinfo("talk() giving up\n");
-#endif
-
-       stuffp->lock = 0;
-       wake_up_interruptible(&stuffp->lockq);
-
-       xtrace(TALK, "talk() done with 0x%02x\n", st);
-       return st;
-}
-
-/* MODULE STUFF ***********************************************************/
-
-static int __init __mcdx_init(void)
-{
-       int i;
-       int drives = 0;
-
-       mcdx_init();
-       for (i = 0; i < MCDX_NDRIVES; i++) {
-               if (mcdx_stuffp[i]) {
-                       xtrace(INIT, "init_module() drive %d stuff @ %p\n",
-                              i, mcdx_stuffp[i]);
-                       drives++;
-               }
-       }
-
-       if (!drives)
-               return -EIO;
-
-       return 0;
-}
-
-static void __exit mcdx_exit(void)
-{
-       int i;
-
-       xinfo("cleanup_module called\n");
-
-       for (i = 0; i < MCDX_NDRIVES; i++) {
-               struct s_drive_stuff *stuffp = mcdx_stuffp[i];
-               if (!stuffp)
-                       continue;
-               del_gendisk(stuffp->disk);
-               if (unregister_cdrom(&stuffp->info)) {
-                       printk(KERN_WARNING "Can't unregister cdrom mcdx\n");
-                       continue;
-               }
-               put_disk(stuffp->disk);
-               release_region(stuffp->wreg_data, MCDX_IO_SIZE);
-               free_irq(stuffp->irq, NULL);
-               if (stuffp->toc) {
-                       xtrace(MALLOC, "cleanup_module() free toc @ %p\n",
-                              stuffp->toc);
-                       kfree(stuffp->toc);
-               }
-               xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n",
-                      stuffp);
-               mcdx_stuffp[i] = NULL;
-               kfree(stuffp);
-       }
-
-       if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) {
-               xwarn("cleanup() unregister_blkdev() failed\n");
-       }
-#if !MCDX_QUIET
-       else
-       xinfo("cleanup() succeeded\n");
-#endif
-       blk_cleanup_queue(mcdx_queue);
-}
-
-#ifdef MODULE
-module_init(__mcdx_init);
-#endif
-module_exit(mcdx_exit);
-
-
-/* Support functions ************************************************/
-
-static int __init mcdx_init_drive(int drive)
-{
-       struct s_version version;
-       struct gendisk *disk;
-       struct s_drive_stuff *stuffp;
-       int size = sizeof(*stuffp);
-       char msg[80];
-
-       xtrace(INIT, "init() try drive %d\n", drive);
-
-       xtrace(INIT, "kmalloc space for stuffpt's\n");
-       xtrace(MALLOC, "init() malloc %d bytes\n", size);
-       if (!(stuffp = kzalloc(size, GFP_KERNEL))) {
-               xwarn("init() malloc failed\n");
-               return 1;
-       }
-
-       disk = alloc_disk(1);
-       if (!disk) {
-               xwarn("init() malloc failed\n");
-               kfree(stuffp);
-               return 1;
-       }
-
-       xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n",
-              sizeof(*stuffp), stuffp);
-
-       /* set default values */
-       stuffp->present = 0;    /* this should be 0 already */
-       stuffp->toc = NULL;     /* this should be NULL already */
-
-       /* setup our irq and i/o addresses */
-       stuffp->irq = irq(mcdx_drive_map[drive]);
-       stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]);
-       stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;
-       stuffp->wreg_hcon = stuffp->wreg_reset + 1;
-       stuffp->wreg_chn = stuffp->wreg_hcon + 1;
-
-       init_waitqueue_head(&stuffp->busyq);
-       init_waitqueue_head(&stuffp->lockq);
-       init_waitqueue_head(&stuffp->sleepq);
-
-       /* check if i/o addresses are available */
-       if (!request_region(stuffp->wreg_data, MCDX_IO_SIZE, "mcdx")) {
-               xwarn("0x%03x,%d: Init failed. "
-                     "I/O ports (0x%03x..0x%03x) already in use.\n",
-                     stuffp->wreg_data, stuffp->irq,
-                     stuffp->wreg_data,
-                     stuffp->wreg_data + MCDX_IO_SIZE - 1);
-               xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
-               kfree(stuffp);
-               put_disk(disk);
-               xtrace(INIT, "init() continue at next drive\n");
-               return 0;       /* next drive */
-       }
-
-       xtrace(INIT, "init() i/o port is available at 0x%03x\n"
-              stuffp->wreg_data);
-       xtrace(INIT, "init() hardware reset\n");
-       mcdx_reset(stuffp, HARD, 1);
-
-       xtrace(INIT, "init() get version\n");
-       if (-1 == mcdx_requestversion(stuffp, &version, 4)) {
-               /* failed, next drive */
-               release_region(stuffp->wreg_data, MCDX_IO_SIZE);
-               xwarn("%s=0x%03x,%d: Init failed. Can't get version.\n",
-                     MCDX, stuffp->wreg_data, stuffp->irq);
-               xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
-               kfree(stuffp);
-               put_disk(disk);
-               xtrace(INIT, "init() continue at next drive\n");
-               return 0;
-       }
-
-       switch (version.code) {
-       case 'D':
-               stuffp->readcmd = READ2X;
-               stuffp->present = DOUBLE | DOOR | MULTI;
-               break;
-       case 'F':
-               stuffp->readcmd = READ1X;
-               stuffp->present = SINGLE | DOOR | MULTI;
-               break;
-       case 'M':
-               stuffp->readcmd = READ1X;
-               stuffp->present = SINGLE;
-               break;
-       default:
-               stuffp->present = 0;
-               break;
-       }
-
-       stuffp->playcmd = READ1X;
-
-       if (!stuffp->present) {
-               release_region(stuffp->wreg_data, MCDX_IO_SIZE);
-               xwarn("%s=0x%03x,%d: Init failed. No Mitsumi CD-ROM?.\n",
-                     MCDX, stuffp->wreg_data, stuffp->irq);
-               kfree(stuffp);
-               put_disk(disk);
-               return 0;       /* next drive */
-       }
-
-       xtrace(INIT, "init() register blkdev\n");
-       if (register_blkdev(MAJOR_NR, "mcdx")) {
-               release_region(stuffp->wreg_data, MCDX_IO_SIZE);
-               kfree(stuffp);
-               put_disk(disk);
-               return 1;
-       }
-
-       mcdx_queue = blk_init_queue(do_mcdx_request, &mcdx_lock);
-       if (!mcdx_queue) {
-               unregister_blkdev(MAJOR_NR, "mcdx");
-               release_region(stuffp->wreg_data, MCDX_IO_SIZE);
-               kfree(stuffp);
-               put_disk(disk);
-               return 1;
-       }
-
-       xtrace(INIT, "init() subscribe irq and i/o\n");
-       if (request_irq(stuffp->irq, mcdx_intr, IRQF_DISABLED, "mcdx", stuffp)) {
-               release_region(stuffp->wreg_data, MCDX_IO_SIZE);
-               xwarn("%s=0x%03x,%d: Init failed. Can't get irq (%d).\n",
-                     MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq);
-               stuffp->irq = 0;
-               blk_cleanup_queue(mcdx_queue);
-               kfree(stuffp);
-               put_disk(disk);
-               return 0;
-       }
-
-       xtrace(INIT, "init() get garbage\n");
-       {
-               int i;
-               mcdx_delay(stuffp, HZ / 2);
-               for (i = 100; i; i--)
-                       (void) inb(stuffp->rreg_status);
-       }
-
-
-#ifdef WE_KNOW_WHY
-       /* irq 11 -> channel register */
-       outb(0x50, stuffp->wreg_chn);
-#endif
-
-       xtrace(INIT, "init() set non dma but irq mode\n");
-       mcdx_config(stuffp, 1);
-
-       stuffp->info.ops = &mcdx_dops;
-       stuffp->info.speed = 2;
-       stuffp->info.capacity = 1;
-       stuffp->info.handle = stuffp;
-       sprintf(stuffp->info.name, "mcdx%d", drive);
-       disk->major = MAJOR_NR;
-       disk->first_minor = drive;
-       strcpy(disk->disk_name, stuffp->info.name);
-       disk->fops = &mcdx_bdops;
-       disk->flags = GENHD_FL_CD;
-       stuffp->disk = disk;
-
-       sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%03x, irq %d."
-               " (Firmware version %c %x)\n",
-               stuffp->wreg_data, stuffp->irq, version.code, version.ver);
-       mcdx_stuffp[drive] = stuffp;
-       xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp);
-       if (register_cdrom(&stuffp->info) != 0) {
-               printk("Cannot register Mitsumi CD-ROM!\n");
-               free_irq(stuffp->irq, NULL);
-               release_region(stuffp->wreg_data, MCDX_IO_SIZE);
-               kfree(stuffp);
-               put_disk(disk);
-               if (unregister_blkdev(MAJOR_NR, "mcdx") != 0)
-                       xwarn("cleanup() unregister_blkdev() failed\n");
-               blk_cleanup_queue(mcdx_queue);
-               return 2;
-       }
-       disk->private_data = stuffp;
-       disk->queue = mcdx_queue;
-       add_disk(disk);
-       printk(msg);
-       return 0;
-}
-
-static int __init mcdx_init(void)
-{
-       int drive;
-       xwarn("Version 2.14(hs) \n");
-
-       xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");
-
-       /* zero the pointer array */
-       for (drive = 0; drive < MCDX_NDRIVES; drive++)
-               mcdx_stuffp[drive] = NULL;
-
-       /* do the initialisation */
-       for (drive = 0; drive < MCDX_NDRIVES; drive++) {
-               switch (mcdx_init_drive(drive)) {
-               case 2:
-                       return -EIO;
-               case 1:
-                       break;
-               }
-       }
-       return 0;
-}
-
-static int mcdx_transfer(struct s_drive_stuff *stuffp,
-             char *p, int sector, int nr_sectors)
-/*     This seems to do the actually transfer.  But it does more.  It
-       keeps track of errors occurred and will (if possible) fall back
-       to single speed on error.
-       Return: -1 on timeout or other error
-                       else status byte (as in stuff->st) */
-{
-       int ans;
-
-       ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
-       return ans;
-#ifdef FALLBACK
-       if (-1 == ans)
-               stuffp->readerrs++;
-       else
-               return ans;
-
-       if (stuffp->readerrs && stuffp->readcmd == READ1X) {
-               xwarn("XXX Already reading 1x -- no chance\n");
-               return -1;
-       }
-
-       xwarn("XXX Fallback to 1x\n");
-
-       stuffp->readcmd = READ1X;
-       return mcdx_transfer(stuffp, p, sector, nr_sectors);
-#endif
-
-}
-
-
-static int mcdx_xfer(struct s_drive_stuff *stuffp,
-                    char *p, int sector, int nr_sectors)
-/*     This does actually the transfer from the drive.
-       Return: -1 on timeout or other error
-                       else status byte (as in stuff->st) */
-{
-       int border;
-       int done = 0;
-       long timeout;
-
-       if (stuffp->audio) {
-               xwarn("Attempt to read from audio CD.\n");
-               return -1;
-       }
-
-       if (!stuffp->readcmd) {
-               xinfo("Can't transfer from missing disk.\n");
-               return -1;
-       }
-
-       while (stuffp->lock) {
-               interruptible_sleep_on(&stuffp->lockq);
-       }
-
-       if (stuffp->valid && (sector >= stuffp->pending)
-           && (sector < stuffp->low_border)) {
-
-               /* All (or at least a part of the sectors requested) seems
-                  * to be already requested, so we don't need to bother the
-                  * drive with new requests ...
-                  * Wait for the drive become idle, but first
-                  * check for possible occurred errors --- the drive
-                  * seems to report them asynchronously */
-
-
-               border = stuffp->high_border < (border =
-                                               sector + nr_sectors)
-                   ? stuffp->high_border : border;
-
-               stuffp->lock = current->pid;
-
-               do {
-
-                       while (stuffp->busy) {
-
-                               timeout =
-                                   interruptible_sleep_on_timeout
-                                   (&stuffp->busyq, 5 * HZ);
-
-                               if (!stuffp->introk) {
-                                       xtrace(XFER,
-                                              "error via interrupt\n");
-                               } else if (!timeout) {
-                                       xtrace(XFER, "timeout\n");
-                               } else if (signal_pending(current)) {
-                                       xtrace(XFER, "signal\n");
-                               } else
-                                       continue;
-
-                               stuffp->lock = 0;
-                               stuffp->busy = 0;
-                               stuffp->valid = 0;
-
-                               wake_up_interruptible(&stuffp->lockq);
-                               xtrace(XFER, "transfer() done (-1)\n");
-                               return -1;
-                       }
-
-                       /* check if we need to set the busy flag (as we
-                        * expect an interrupt */
-                       stuffp->busy = (3 == (stuffp->pending & 3));
-
-                       /* Test if it's the first sector of a block,
-                        * there we have to skip some bytes as we read raw data */
-                       if (stuffp->xa && (0 == (stuffp->pending & 3))) {
-                               const int HEAD =
-                                   CD_FRAMESIZE_RAW - CD_XA_TAIL -
-                                   CD_FRAMESIZE;
-                               insb(stuffp->rreg_data, p, HEAD);
-                       }
-
-                       /* now actually read the data */
-                       insb(stuffp->rreg_data, p, 512);
-
-                       /* test if it's the last sector of a block,
-                        * if so, we have to handle XA special */
-                       if ((3 == (stuffp->pending & 3)) && stuffp->xa) {
-                               char dummy[CD_XA_TAIL];
-                               insb(stuffp->rreg_data, &dummy[0], CD_XA_TAIL);
-                       }
-
-                       if (stuffp->pending == sector) {
-                               p += 512;
-                               done++;
-                               sector++;
-                       }
-               } while (++(stuffp->pending) < border);
-
-               stuffp->lock = 0;
-               wake_up_interruptible(&stuffp->lockq);
-
-       } else {
-
-               /* The requested sector(s) is/are out of the
-                * already requested range, so we have to bother the drive
-                * with a new request. */
-
-               static unsigned char cmd[] = {
-                       0,
-                       0, 0, 0,
-                       0, 0, 0
-               };
-
-               cmd[0] = stuffp->readcmd;
-
-               /* The numbers held in ->pending, ..., should be valid */
-               stuffp->valid = 1;
-               stuffp->pending = sector & ~3;
-
-               /* do some sanity checks */
-               if (stuffp->pending > stuffp->lastsector) {
-                       xwarn
-                           ("transfer() sector %d from nirvana requested.\n",
-                            stuffp->pending);
-                       stuffp->status = MCDX_ST_EOM;
-                       stuffp->valid = 0;
-                       xtrace(XFER, "transfer() done (-1)\n");
-                       return -1;
-               }
-
-               if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE)
-                   > stuffp->lastsector + 1) {
-                       xtrace(XFER, "cut low_border\n");
-                       stuffp->low_border = stuffp->lastsector + 1;
-               }
-               if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE)
-                   > stuffp->lastsector + 1) {
-                       xtrace(XFER, "cut high_border\n");
-                       stuffp->high_border = stuffp->lastsector + 1;
-               }
-
-               {               /* Convert the sector to be requested to MSF format */
-                       struct cdrom_msf0 pending;
-                       log2msf(stuffp->pending / 4, &pending);
-                       cmd[1] = pending.minute;
-                       cmd[2] = pending.second;
-                       cmd[3] = pending.frame;
-               }
-
-               cmd[6] =
-                   (unsigned
-                    char) ((stuffp->high_border - stuffp->pending) / 4);
-               xtrace(XFER, "[%2d]\n", cmd[6]);
-
-               stuffp->busy = 1;
-               /* Now really issue the request command */
-               outsb(stuffp->wreg_data, cmd, sizeof cmd);
-
-       }
-#ifdef AK2
-       if (stuffp->int_err) {
-               stuffp->valid = 0;
-               stuffp->int_err = 0;
-               return -1;
-       }
-#endif                         /* AK2 */
-
-       stuffp->low_border = (stuffp->low_border +=
-                             done) <
-           stuffp->high_border ? stuffp->low_border : stuffp->high_border;
-
-       return done;
-}
-
-
-/*     Access to elements of the mcdx_drive_map members */
-
-static unsigned port(int *ip)
-{
-       return ip[0];
-}
-static int irq(int *ip)
-{
-       return ip[1];
-}
-
-/*     Misc number converters */
-
-static unsigned int bcd2uint(unsigned char c)
-{
-       return (c >> 4) * 10 + (c & 0x0f);
-}
-
-static unsigned int uint2bcd(unsigned int ival)
-{
-       return ((ival / 10) << 4) | (ival % 10);
-}
-
-static void log2msf(unsigned int l, struct cdrom_msf0 *pmsf)
-{
-       l += CD_MSF_OFFSET;
-       pmsf->minute = uint2bcd(l / 4500), l %= 4500;
-       pmsf->second = uint2bcd(l / 75);
-       pmsf->frame = uint2bcd(l % 75);
-}
-
-static unsigned int msf2log(const struct cdrom_msf0 *pmsf)
-{
-       return bcd2uint(pmsf->frame)
-           + bcd2uint(pmsf->second) * 75
-           + bcd2uint(pmsf->minute) * 4500 - CD_MSF_OFFSET;
-}
-
-int mcdx_readtoc(struct s_drive_stuff *stuffp)
-/*  Read the toc entries from the CD,
- *  Return: -1 on failure, else 0 */
-{
-
-       if (stuffp->toc) {
-               xtrace(READTOC, "ioctl() toc already read\n");
-               return 0;
-       }
-
-       xtrace(READTOC, "ioctl() readtoc for %d tracks\n",
-              stuffp->di.n_last - stuffp->di.n_first + 1);
-
-       if (-1 == mcdx_hold(stuffp, 1))
-               return -1;
-
-       xtrace(READTOC, "ioctl() tocmode\n");
-       if (-1 == mcdx_setdrivemode(stuffp, TOC, 1))
-               return -EIO;
-
-       /* all seems to be ok so far ... malloc */
-       {
-               int size;
-               size =
-                   sizeof(struct s_subqcode) * (stuffp->di.n_last -
-                                                stuffp->di.n_first + 2);
-
-               xtrace(MALLOC, "ioctl() malloc %d bytes\n", size);
-               stuffp->toc = kmalloc(size, GFP_KERNEL);
-               if (!stuffp->toc) {
-                       xwarn("Cannot malloc %d bytes for toc\n", size);
-                       mcdx_setdrivemode(stuffp, DATA, 1);
-                       return -EIO;
-               }
-       }
-
-       /* now read actually the index */
-       {
-               int trk;
-               int retries;
-
-               for (trk = 0;
-                    trk < (stuffp->di.n_last - stuffp->di.n_first + 1);
-                    trk++)
-                       stuffp->toc[trk].index = 0;
-
-               for (retries = 300; retries; retries--) {       /* why 300? */
-                       struct s_subqcode q;
-                       unsigned int idx;
-
-                       if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
-                               mcdx_setdrivemode(stuffp, DATA, 1);
-                               return -EIO;
-                       }
-
-                       idx = bcd2uint(q.index);
-
-                       if ((idx > 0)
-                           && (idx <= stuffp->di.n_last)
-                           && (q.tno == 0)
-                           && (stuffp->toc[idx - stuffp->di.n_first].
-                               index == 0)) {
-                               stuffp->toc[idx - stuffp->di.n_first] = q;
-                               xtrace(READTOC,
-                                      "ioctl() toc idx %d (trk %d)\n",
-                                      idx, trk);
-                               trk--;
-                       }
-                       if (trk == 0)
-                               break;
-               }
-               memset(&stuffp->
-                      toc[stuffp->di.n_last - stuffp->di.n_first + 1], 0,
-                      sizeof(stuffp->toc[0]));
-               stuffp->toc[stuffp->di.n_last - stuffp->di.n_first +
-                           1].dt = stuffp->di.msf_leadout;
-       }
-
-       /* unset toc mode */
-       xtrace(READTOC, "ioctl() undo toc mode\n");
-       if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
-               return -EIO;
-
-#if MCDX_DEBUG && READTOC
-       {
-               int trk;
-               for (trk = 0;
-                    trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
-                    trk++)
-                       xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x"
-                              "  %02x:%02x.%02x  %02x:%02x.%02x\n",
-                              trk + stuffp->di.n_first,
-                              stuffp->toc[trk].control,
-                              stuffp->toc[trk].tno,
-                              stuffp->toc[trk].index,
-                              stuffp->toc[trk].tt.minute,
-                              stuffp->toc[trk].tt.second,
-                              stuffp->toc[trk].tt.frame,
-                              stuffp->toc[trk].dt.minute,
-                              stuffp->toc[trk].dt.second,
-                              stuffp->toc[trk].dt.frame);
-       }
-#endif
-
-       return 0;
-}
-
-static int
-mcdx_playmsf(struct s_drive_stuff *stuffp, const struct cdrom_msf *msf)
-{
-       unsigned char cmd[7] = {
-               0, 0, 0, 0, 0, 0, 0
-       };
-
-       if (!stuffp->readcmd) {
-               xinfo("Can't play from missing disk.\n");
-               return -1;
-       }
-
-       cmd[0] = stuffp->playcmd;
-
-       cmd[1] = msf->cdmsf_min0;
-       cmd[2] = msf->cdmsf_sec0;
-       cmd[3] = msf->cdmsf_frame0;
-       cmd[4] = msf->cdmsf_min1;
-       cmd[5] = msf->cdmsf_sec1;
-       cmd[6] = msf->cdmsf_frame1;
-
-       xtrace(PLAYMSF, "ioctl(): play %x "
-              "%02x:%02x:%02x -- %02x:%02x:%02x\n",
-              cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]);
-
-       outsb(stuffp->wreg_data, cmd, sizeof cmd);
-
-       if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
-               xwarn("playmsf() timeout\n");
-               return -1;
-       }
-
-       stuffp->audiostatus = CDROM_AUDIO_PLAY;
-       return 0;
-}
-
-static int
-mcdx_playtrk(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti)
-{
-       struct s_subqcode *p;
-       struct cdrom_msf msf;
-
-       if (-1 == mcdx_readtoc(stuffp))
-               return -1;
-
-       if (ti)
-               p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
-       else
-               p = &stuffp->start;
-
-       msf.cdmsf_min0 = p->dt.minute;
-       msf.cdmsf_sec0 = p->dt.second;
-       msf.cdmsf_frame0 = p->dt.frame;
-
-       if (ti) {
-               p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
-               stuffp->stop = *p;
-       } else
-               p = &stuffp->stop;
-
-       msf.cdmsf_min1 = p->dt.minute;
-       msf.cdmsf_sec1 = p->dt.second;
-       msf.cdmsf_frame1 = p->dt.frame;
-
-       return mcdx_playmsf(stuffp, &msf);
-}
-
-
-/* Drive functions ************************************************/
-
-static int mcdx_tray_move(struct cdrom_device_info *cdi, int position)
-{
-       struct s_drive_stuff *stuffp = cdi->handle;
-
-       if (!stuffp->present)
-               return -ENXIO;
-       if (!(stuffp->present & DOOR))
-               return -ENOSYS;
-
-       if (position)           /* 1: eject */
-               return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, 3);
-       else                    /* 0: close */
-               return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, 3);
-       return 1;
-}
-
-static int mcdx_stop(struct s_drive_stuff *stuffp, int tries)
-{
-       return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries);
-}
-
-static int mcdx_hold(struct s_drive_stuff *stuffp, int tries)
-{
-       return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries);
-}
-
-static int mcdx_requestsubqcode(struct s_drive_stuff *stuffp,
-                    struct s_subqcode *sub, int tries)
-{
-       char buf[11];
-       int ans;
-
-       if (-1 == (ans = mcdx_talk(stuffp, "\x20", 1, buf, sizeof(buf),
-                                  2 * HZ, tries)))
-               return -1;
-       sub->control = buf[1];
-       sub->tno = buf[2];
-       sub->index = buf[3];
-       sub->tt.minute = buf[4];
-       sub->tt.second = buf[5];
-       sub->tt.frame = buf[6];
-       sub->dt.minute = buf[8];
-       sub->dt.second = buf[9];
-       sub->dt.frame = buf[10];
-
-       return ans;
-}
-
-static int mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp,
-                         struct s_multi *multi, int tries)
-{
-       char buf[5];
-       int ans;
-
-       if (stuffp->present & MULTI) {
-               ans =
-                   mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ,
-                             tries);
-               multi->multi = buf[1];
-               multi->msf_last.minute = buf[2];
-               multi->msf_last.second = buf[3];
-               multi->msf_last.frame = buf[4];
-               return ans;
-       } else {
-               multi->multi = 0;
-               return 0;
-       }
-}
-
-static int mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info,
-                   int tries)
-{
-       char buf[9];
-       int ans;
-       ans =
-           mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries);
-       if (ans == -1) {
-               info->n_first = 0;
-               info->n_last = 0;
-       } else {
-               info->n_first = bcd2uint(buf[1]);
-               info->n_last = bcd2uint(buf[2]);
-               info->msf_leadout.minute = buf[3];
-               info->msf_leadout.second = buf[4];
-               info->msf_leadout.frame = buf[5];
-               info->msf_first.minute = buf[6];
-               info->msf_first.second = buf[7];
-               info->msf_first.frame = buf[8];
-       }
-       return ans;
-}
-
-static int mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode,
-                 int tries)
-{
-       char cmd[2];
-       int ans;
-
-       xtrace(HW, "setdrivemode() %d\n", mode);
-
-       if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
-               return -1;
-
-       switch (mode) {
-       case TOC:
-               cmd[1] |= 0x04;
-               break;
-       case DATA:
-               cmd[1] &= ~0x04;
-               break;
-       case RAW:
-               cmd[1] |= 0x40;
-               break;
-       case COOKED:
-               cmd[1] &= ~0x40;
-               break;
-       default:
-               break;
-       }
-       cmd[0] = 0x50;
-       return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
-}
-
-static int mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode,
-                int tries)
-{
-       unsigned char cmd[2] = { 0xa0 };
-       xtrace(HW, "setdatamode() %d\n", mode);
-       switch (mode) {
-       case MODE0:
-               cmd[1] = 0x00;
-               break;
-       case MODE1:
-               cmd[1] = 0x01;
-               break;
-       case MODE2:
-               cmd[1] = 0x02;
-               break;
-       default:
-               return -EINVAL;
-       }
-       return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
-}
-
-static int mcdx_config(struct s_drive_stuff *stuffp, int tries)
-{
-       char cmd[4];
-
-       xtrace(HW, "config()\n");
-
-       cmd[0] = 0x90;
-
-       cmd[1] = 0x10;          /* irq enable */
-       cmd[2] = 0x05;          /* pre, err irq enable */
-
-       if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
-               return -1;
-
-       cmd[1] = 0x02;          /* dma select */
-       cmd[2] = 0x00;          /* no dma */
-
-       return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
-}
-
-static int mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver,
-                   int tries)
-{
-       char buf[3];
-       int ans;
-
-       if (-1 == (ans = mcdx_talk(stuffp, "\xdc",
-                                  1, buf, sizeof(buf), 2 * HZ, tries)))
-               return ans;
-
-       ver->code = buf[1];
-       ver->ver = buf[2];
-
-       return ans;
-}
-
-static int mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
-{
-       if (mode == HARD) {
-               outb(0, stuffp->wreg_chn);      /* no dma, no irq -> hardware */
-               outb(0, stuffp->wreg_reset);    /* hw reset */
-               return 0;
-       } else
-               return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
-}
-
-static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock)
-{
-       struct s_drive_stuff *stuffp = cdi->handle;
-       char cmd[2] = { 0xfe };
-
-       if (!(stuffp->present & DOOR))
-               return -ENOSYS;
-       if (stuffp->present & DOOR) {
-               cmd[1] = lock ? 0x01 : 0x00;
-               return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, 3);
-       } else
-               return 0;
-}
-
-static int mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
-{
-       return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries);
-}
-
-static int
-mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char *buf)
-{
-       unsigned long timeout = to + jiffies;
-       char c;
-
-       if (!buf)
-               buf = &c;
-
-       while (inb(stuffp->rreg_status) & MCDX_RBIT_STEN) {
-               if (time_after(jiffies, timeout))
-                       return -1;
-               mcdx_delay(stuffp, delay);
-       }
-
-       *buf = (unsigned char) inb(stuffp->rreg_data) & 0xff;
-
-       return 0;
-}
-
-static int mcdx_setattentuator(struct s_drive_stuff *stuffp,
-                   struct cdrom_volctrl *vol, int tries)
-{
-       char cmd[5];
-       cmd[0] = 0xae;
-       cmd[1] = vol->channel0;
-       cmd[2] = 0;
-       cmd[3] = vol->channel1;
-       cmd[4] = 0;
-
-       return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
-}
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_X_CDROM_MAJOR);