linux-bk/drivers/cdrom/mcdx.c
<<
>>
Prefs
   1/*
   2 * The Mitsumi CDROM interface
   3 * Copyright (C) 1995 1996 Heiko Schlittermann <heiko@lotte.sax.de>
   4 * VERSION: 2.14(hs)
   5 *
   6 * ... anyway, I'm back again, thanks to Marcin, he adopted
   7 * large portions of my code (at least the parts containing
   8 * my main thoughts ...)
   9 *
  10 ****************** H E L P *********************************
  11 * If you ever plan to update your CD ROM drive and perhaps
  12 * want to sell or simply give away your Mitsumi FX-001[DS]
  13 * -- Please --
  14 * mail me (heiko@lotte.sax.de).  When my last drive goes
  15 * ballistic no more driver support will be available from me!
  16 *************************************************************
  17 *
  18 * This program is free software; you can redistribute it and/or modify
  19 * it under the terms of the GNU General Public License as published by
  20 * the Free Software Foundation; either version 2, or (at your option)
  21 * any later version.
  22 *
  23 * This program is distributed in the hope that it will be useful,
  24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26 * GNU General Public License for more details.
  27 *
  28 * You should have received a copy of the GNU General Public License
  29 * along with this program; see the file COPYING.  If not, write to
  30 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  31 *
  32 * Thanks to
  33 *  The Linux Community at all and ...
  34 *  Martin Harriss (he wrote the first Mitsumi Driver)
  35 *  Eberhard Moenkeberg (he gave me much support and the initial kick)
  36 *  Bernd Huebner, Ruediger Helsch (Unifix-Software GmbH, they
  37 *      improved the original driver)
  38 *  Jon Tombs, Bjorn Ekwall (module support)
  39 *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
  40 *  Gerd Knorr (he lent me his PhotoCD)
  41 *  Nils Faerber and Roger E. Wolff (extensively tested the LU portion)
  42 *  Andreas Kies (testing the mysterious hang-ups)
  43 *  Heiko Eissfeldt (VERIFY_READ/WRITE)
  44 *  Marcin Dalecki (improved performance, shortened code)
  45 *  ... somebody forgotten?
  46 *
  47 *  9 November 1999 -- Make kernel-parameter implementation work with 2.3.x 
  48 *                     Removed init_module & cleanup_module in favor of 
  49 *                     module_init & module_exit.
  50 *                     Torben Mathiasen <tmm@image.dk>
  51 */
  52
  53
  54#if RCS
  55static const char *mcdx_c_version
  56    = "$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $";
  57#endif
  58
  59#include <linux/version.h>
  60#include <linux/module.h>
  61
  62#include <linux/errno.h>
  63#include <linux/interrupt.h>
  64#include <linux/fs.h>
  65#include <linux/kernel.h>
  66#include <linux/cdrom.h>
  67#include <linux/ioport.h>
  68#include <linux/mm.h>
  69#include <linux/slab.h>
  70#include <linux/init.h>
  71#include <asm/io.h>
  72#include <asm/current.h>
  73#include <asm/uaccess.h>
  74
  75#include <linux/major.h>
  76#define MAJOR_NR MITSUMI_X_CDROM_MAJOR
  77#include <linux/blkdev.h>
  78#include <linux/devfs_fs_kernel.h>
  79
  80/* for compatible parameter passing with "insmod" */
  81#define mcdx_drive_map mcdx
  82#include "mcdx.h"
  83
  84#ifndef HZ
  85#error HZ not defined
  86#endif
  87
  88#define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)
  89
  90#if !MCDX_QUIET
  91#define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)
  92#else
  93#define xinfo(fmt, args...) { ; }
  94#endif
  95
  96#if MCDX_DEBUG
  97#define xtrace(lvl, fmt, args...) \
  98                { if (lvl > 0) \
  99                        { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }
 100#define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args)
 101#else
 102#define xtrace(lvl, fmt, args...) { ; }
 103#define xdebug(fmt, args...) { ; }
 104#endif
 105
 106/* CONSTANTS *******************************************************/
 107
 108/* Following are the number of sectors we _request_ from the drive
 109   every time an access outside the already requested range is done.
 110   The _direct_ size is the number of sectors we're allowed to skip
 111   directly (performing a read instead of requesting the new sector
 112   needed */
 113const int REQUEST_SIZE = 800;   /* should be less then 255 * 4 */
 114const int DIRECT_SIZE = 400;    /* should be less then REQUEST_SIZE */
 115
 116enum drivemodes { TOC, DATA, RAW, COOKED };
 117enum datamodes { MODE0, MODE1, MODE2 };
 118enum resetmodes { SOFT, HARD };
 119
 120const int SINGLE = 0x01;        /* single speed drive (FX001S, LU) */
 121const int DOUBLE = 0x02;        /* double speed drive (FX001D, ..? */
 122const int DOOR = 0x04;          /* door locking capability */
 123const int MULTI = 0x08;         /* multi session capability */
 124
 125const unsigned char READ1X = 0xc0;
 126const unsigned char READ2X = 0xc1;
 127
 128
 129/* DECLARATIONS ****************************************************/
 130struct s_subqcode {
 131        unsigned char control;
 132        unsigned char tno;
 133        unsigned char index;
 134        struct cdrom_msf0 tt;
 135        struct cdrom_msf0 dt;
 136};
 137
 138struct s_diskinfo {
 139        unsigned int n_first;
 140        unsigned int n_last;
 141        struct cdrom_msf0 msf_leadout;
 142        struct cdrom_msf0 msf_first;
 143};
 144
 145struct s_multi {
 146        unsigned char multi;
 147        struct cdrom_msf0 msf_last;
 148};
 149
 150struct s_version {
 151        unsigned char code;
 152        unsigned char ver;
 153};
 154
 155/* Per drive/controller stuff **************************************/
 156
 157struct s_drive_stuff {
 158        /* waitqueues */
 159        wait_queue_head_t busyq;
 160        wait_queue_head_t lockq;
 161        wait_queue_head_t sleepq;
 162
 163        /* flags */
 164        volatile int introk;    /* status of last irq operation */
 165        volatile int busy;      /* drive performs an operation */
 166        volatile int lock;      /* exclusive usage */
 167
 168        /* cd infos */
 169        struct s_diskinfo di;
 170        struct s_multi multi;
 171        struct s_subqcode *toc; /* first entry of the toc array */
 172        struct s_subqcode start;
 173        struct s_subqcode stop;
 174        int xa;                 /* 1 if xa disk */
 175        int audio;              /* 1 if audio disk */
 176        int audiostatus;
 177
 178        /* `buffer' control */
 179        volatile int valid;     /* pending, ..., values are valid */
 180        volatile int pending;   /* next sector to be read */
 181        volatile int low_border;        /* first sector not to be skipped direct */
 182        volatile int high_border;       /* first sector `out of area' */
 183#ifdef AK2
 184        volatile int int_err;
 185#endif                          /* AK2 */
 186
 187        /* adds and odds */
 188        unsigned wreg_data;     /* w data */
 189        unsigned wreg_reset;    /* w hardware reset */
 190        unsigned wreg_hcon;     /* w hardware conf */
 191        unsigned wreg_chn;      /* w channel */
 192        unsigned rreg_data;     /* r data */
 193        unsigned rreg_status;   /* r status */
 194
 195        int irq;                /* irq used by this drive */
 196        int present;            /* drive present and its capabilities */
 197        unsigned char readcmd;  /* read cmd depends on single/double speed */
 198        unsigned char playcmd;  /* play should always be single speed */
 199        unsigned int xxx;       /* set if changed, reset while open */
 200        unsigned int yyy;       /* set if changed, reset by media_changed */
 201        int users;              /* keeps track of open/close */
 202        int lastsector;         /* last block accessible */
 203        int status;             /* last operation's error / status */
 204        int readerrs;           /* # of blocks read w/o error */
 205        struct cdrom_device_info info;
 206        struct gendisk *disk;
 207};
 208
 209
 210/* Prototypes ******************************************************/
 211
 212/*      The following prototypes are already declared elsewhere.  They are
 213        repeated here to show what's going on.  And to sense, if they're
 214        changed elsewhere. */
 215
 216/* declared in blk.h */
 217int mcdx_init(void);
 218void do_mcdx_request(request_queue_t * q);
 219
 220static int mcdx_block_open(struct inode *inode, struct file *file)
 221{
 222        struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
 223        return cdrom_open(&p->info, inode, file);
 224}
 225
 226static int mcdx_block_release(struct inode *inode, struct file *file)
 227{
 228        struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
 229        return cdrom_release(&p->info, file);
 230}
 231
 232static int mcdx_block_ioctl(struct inode *inode, struct file *file,
 233                                unsigned cmd, unsigned long arg)
 234{
 235        struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
 236        return cdrom_ioctl(file, &p->info, inode, cmd, arg);
 237}
 238
 239static int mcdx_block_media_changed(struct gendisk *disk)
 240{
 241        struct s_drive_stuff *p = disk->private_data;
 242        return cdrom_media_changed(&p->info);
 243}
 244
 245static struct block_device_operations mcdx_bdops =
 246{
 247        .owner          = THIS_MODULE,
 248        .open           = mcdx_block_open,
 249        .release        = mcdx_block_release,
 250        .ioctl          = mcdx_block_ioctl,
 251        .media_changed  = mcdx_block_media_changed,
 252};
 253
 254
 255/*      Indirect exported functions. These functions are exported by their
 256        addresses, such as mcdx_open and mcdx_close in the
 257        structure mcdx_dops. */
 258
 259/* exported by file_ops */
 260static int mcdx_open(struct cdrom_device_info *cdi, int purpose);
 261static void mcdx_close(struct cdrom_device_info *cdi);
 262static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr);
 263static int mcdx_tray_move(struct cdrom_device_info *cdi, int position);
 264static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock);
 265static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
 266                            unsigned int cmd, void *arg);
 267
 268/* misc internal support functions */
 269static void log2msf(unsigned int, struct cdrom_msf0 *);
 270static unsigned int msf2log(const struct cdrom_msf0 *);
 271static unsigned int uint2bcd(unsigned int);
 272static unsigned int bcd2uint(unsigned char);
 273static unsigned port(int *);
 274static int irq(int *);
 275static void mcdx_delay(struct s_drive_stuff *, long jifs);
 276static int mcdx_transfer(struct s_drive_stuff *, char *buf, int sector,
 277                         int nr_sectors);
 278static int mcdx_xfer(struct s_drive_stuff *, char *buf, int sector,
 279                     int nr_sectors);
 280
 281static int mcdx_config(struct s_drive_stuff *, int);
 282static int mcdx_requestversion(struct s_drive_stuff *, struct s_version *,
 283                               int);
 284static int mcdx_stop(struct s_drive_stuff *, int);
 285static int mcdx_hold(struct s_drive_stuff *, int);
 286static int mcdx_reset(struct s_drive_stuff *, enum resetmodes, int);
 287static int mcdx_setdrivemode(struct s_drive_stuff *, enum drivemodes, int);
 288static int mcdx_setdatamode(struct s_drive_stuff *, enum datamodes, int);
 289static int mcdx_requestsubqcode(struct s_drive_stuff *,
 290                                struct s_subqcode *, int);
 291static int mcdx_requestmultidiskinfo(struct s_drive_stuff *,
 292                                     struct s_multi *, int);
 293static int mcdx_requesttocdata(struct s_drive_stuff *, struct s_diskinfo *,
 294                               int);
 295static int mcdx_getstatus(struct s_drive_stuff *, int);
 296static int mcdx_getval(struct s_drive_stuff *, int to, int delay, char *);
 297static int mcdx_talk(struct s_drive_stuff *,
 298                     const unsigned char *cmd, size_t,
 299                     void *buffer, size_t size, unsigned int timeout, int);
 300static int mcdx_readtoc(struct s_drive_stuff *);
 301static int mcdx_playtrk(struct s_drive_stuff *, const struct cdrom_ti *);
 302static int mcdx_playmsf(struct s_drive_stuff *, const struct cdrom_msf *);
 303static int mcdx_setattentuator(struct s_drive_stuff *,
 304                               struct cdrom_volctrl *, int);
 305
 306/* static variables ************************************************/
 307
 308static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
 309static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES];
 310static spinlock_t mcdx_lock = SPIN_LOCK_UNLOCKED;
 311static struct request_queue *mcdx_queue;
 312MODULE_PARM(mcdx, "1-4i");
 313
 314static struct cdrom_device_ops mcdx_dops = {
 315        .open           = mcdx_open,
 316        .release        = mcdx_close,
 317        .media_changed  = mcdx_media_changed,
 318        .tray_move      = mcdx_tray_move,
 319        .lock_door      = mcdx_lockdoor,
 320        .audio_ioctl    = mcdx_audio_ioctl,
 321        .capability     = CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED |
 322                          CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
 323};
 324
 325/* KERNEL INTERFACE FUNCTIONS **************************************/
 326
 327
 328static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
 329                            unsigned int cmd, void *arg)
 330{
 331        struct s_drive_stuff *stuffp = cdi->handle;
 332
 333        if (!stuffp->present)
 334                return -ENXIO;
 335
 336        if (stuffp->xxx) {
 337                if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
 338                        stuffp->lastsector = -1;
 339                } else {
 340                        stuffp->lastsector = (CD_FRAMESIZE / 512)
 341                            * msf2log(&stuffp->di.msf_leadout) - 1;
 342                }
 343
 344                if (stuffp->toc) {
 345                        kfree(stuffp->toc);
 346                        stuffp->toc = NULL;
 347                        if (-1 == mcdx_readtoc(stuffp))
 348                                return -1;
 349                }
 350
 351                stuffp->xxx = 0;
 352        }
 353
 354        switch (cmd) {
 355        case CDROMSTART:{
 356                        xtrace(IOCTL, "ioctl() START\n");
 357                        /* Spin up the drive.  Don't think we can do this.
 358                           * For now, ignore it.
 359                         */
 360                        return 0;
 361                }
 362
 363        case CDROMSTOP:{
 364                        xtrace(IOCTL, "ioctl() STOP\n");
 365                        stuffp->audiostatus = CDROM_AUDIO_INVALID;
 366                        if (-1 == mcdx_stop(stuffp, 1))
 367                                return -EIO;
 368                        return 0;
 369                }
 370
 371        case CDROMPLAYTRKIND:{
 372                        struct cdrom_ti *ti = (struct cdrom_ti *) arg;
 373
 374                        xtrace(IOCTL, "ioctl() PLAYTRKIND\n");
 375                        if ((ti->cdti_trk0 < stuffp->di.n_first)
 376                            || (ti->cdti_trk0 > stuffp->di.n_last)
 377                            || (ti->cdti_trk1 < stuffp->di.n_first))
 378                                return -EINVAL;
 379                        if (ti->cdti_trk1 > stuffp->di.n_last)
 380                                ti->cdti_trk1 = stuffp->di.n_last;
 381                        xtrace(PLAYTRK, "ioctl() track %d to %d\n",
 382                               ti->cdti_trk0, ti->cdti_trk1);
 383                        return mcdx_playtrk(stuffp, ti);
 384                }
 385
 386        case CDROMPLAYMSF:{
 387                        struct cdrom_msf *msf = (struct cdrom_msf *) arg;
 388
 389                        xtrace(IOCTL, "ioctl() PLAYMSF\n");
 390
 391                        if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)
 392                            && (-1 == mcdx_hold(stuffp, 1)))
 393                                return -EIO;
 394
 395                        msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0);
 396                        msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0);
 397                        msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0);
 398
 399                        msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1);
 400                        msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1);
 401                        msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1);
 402
 403                        stuffp->stop.dt.minute = msf->cdmsf_min1;
 404                        stuffp->stop.dt.second = msf->cdmsf_sec1;
 405                        stuffp->stop.dt.frame = msf->cdmsf_frame1;
 406
 407                        return mcdx_playmsf(stuffp, msf);
 408                }
 409
 410        case CDROMRESUME:{
 411                        xtrace(IOCTL, "ioctl() RESUME\n");
 412                        return mcdx_playtrk(stuffp, NULL);
 413                }
 414
 415        case CDROMREADTOCENTRY:{
 416                        struct cdrom_tocentry *entry =
 417                            (struct cdrom_tocentry *) arg;
 418                        struct s_subqcode *tp = NULL;
 419                        xtrace(IOCTL, "ioctl() READTOCENTRY\n");
 420
 421                        if (-1 == mcdx_readtoc(stuffp))
 422                                return -1;
 423                        if (entry->cdte_track == CDROM_LEADOUT)
 424                                tp = &stuffp->toc[stuffp->di.n_last -
 425                                                  stuffp->di.n_first + 1];
 426                        else if (entry->cdte_track > stuffp->di.n_last
 427                                 || entry->cdte_track < stuffp->di.n_first)
 428                                return -EINVAL;
 429                        else
 430                                tp = &stuffp->toc[entry->cdte_track -
 431                                                  stuffp->di.n_first];
 432
 433                        if (NULL == tp)
 434                                return -EIO;
 435                        entry->cdte_adr = tp->control;
 436                        entry->cdte_ctrl = tp->control >> 4;
 437                        /* Always return stuff in MSF, and let the Uniform cdrom driver
 438                           worry about what the user actually wants */
 439                        entry->cdte_addr.msf.minute =
 440                            bcd2uint(tp->dt.minute);
 441                        entry->cdte_addr.msf.second =
 442                            bcd2uint(tp->dt.second);
 443                        entry->cdte_addr.msf.frame =
 444                            bcd2uint(tp->dt.frame);
 445                        return 0;
 446                }
 447
 448        case CDROMSUBCHNL:{
 449                        struct cdrom_subchnl *sub =
 450                            (struct cdrom_subchnl *) arg;
 451                        struct s_subqcode q;
 452
 453                        xtrace(IOCTL, "ioctl() SUBCHNL\n");
 454
 455                        if (-1 == mcdx_requestsubqcode(stuffp, &q, 2))
 456                                return -EIO;
 457
 458                        xtrace(SUBCHNL, "audiostatus: %x\n",
 459                               stuffp->audiostatus);
 460                        sub->cdsc_audiostatus = stuffp->audiostatus;
 461                        sub->cdsc_adr = q.control;
 462                        sub->cdsc_ctrl = q.control >> 4;
 463                        sub->cdsc_trk = bcd2uint(q.tno);
 464                        sub->cdsc_ind = bcd2uint(q.index);
 465
 466                        xtrace(SUBCHNL, "trk %d, ind %d\n",
 467                               sub->cdsc_trk, sub->cdsc_ind);
 468                        /* Always return stuff in MSF, and let the Uniform cdrom driver
 469                           worry about what the user actually wants */
 470                        sub->cdsc_absaddr.msf.minute =
 471                            bcd2uint(q.dt.minute);
 472                        sub->cdsc_absaddr.msf.second =
 473                            bcd2uint(q.dt.second);
 474                        sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
 475                        sub->cdsc_reladdr.msf.minute =
 476                            bcd2uint(q.tt.minute);
 477                        sub->cdsc_reladdr.msf.second =
 478                            bcd2uint(q.tt.second);
 479                        sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
 480                        xtrace(SUBCHNL,
 481                               "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
 482                               sub->cdsc_absaddr.msf.minute,
 483                               sub->cdsc_absaddr.msf.second,
 484                               sub->cdsc_absaddr.msf.frame,
 485                               sub->cdsc_reladdr.msf.minute,
 486                               sub->cdsc_reladdr.msf.second,
 487                               sub->cdsc_reladdr.msf.frame);
 488
 489                        return 0;
 490                }
 491
 492        case CDROMREADTOCHDR:{
 493                        struct cdrom_tochdr *toc =
 494                            (struct cdrom_tochdr *) arg;
 495
 496                        xtrace(IOCTL, "ioctl() READTOCHDR\n");
 497                        toc->cdth_trk0 = stuffp->di.n_first;
 498                        toc->cdth_trk1 = stuffp->di.n_last;
 499                        xtrace(TOCHDR,
 500                               "ioctl() track0 = %d, track1 = %d\n",
 501                               stuffp->di.n_first, stuffp->di.n_last);
 502                        return 0;
 503                }
 504
 505        case CDROMPAUSE:{
 506                        xtrace(IOCTL, "ioctl() PAUSE\n");
 507                        if (stuffp->audiostatus != CDROM_AUDIO_PLAY)
 508                                return -EINVAL;
 509                        if (-1 == mcdx_stop(stuffp, 1))
 510                                return -EIO;
 511                        stuffp->audiostatus = CDROM_AUDIO_PAUSED;
 512                        if (-1 ==
 513                            mcdx_requestsubqcode(stuffp, &stuffp->start,
 514                                                 1))
 515                                return -EIO;
 516                        return 0;
 517                }
 518
 519        case CDROMMULTISESSION:{
 520                        struct cdrom_multisession *ms =
 521                            (struct cdrom_multisession *) arg;
 522                        xtrace(IOCTL, "ioctl() MULTISESSION\n");
 523                        /* Always return stuff in LBA, and let the Uniform cdrom driver
 524                           worry about what the user actually wants */
 525                        ms->addr.lba = msf2log(&stuffp->multi.msf_last);
 526                        ms->xa_flag = !!stuffp->multi.multi;
 527                        xtrace(MS,
 528                               "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
 529                               ms->xa_flag, ms->addr.lba,
 530                               stuffp->multi.msf_last.minute,
 531                               stuffp->multi.msf_last.second,
 532                               stuffp->multi.msf_last.frame);
 533
 534                        return 0;
 535                }
 536
 537        case CDROMEJECT:{
 538                        xtrace(IOCTL, "ioctl() EJECT\n");
 539                        if (stuffp->users > 1)
 540                                return -EBUSY;
 541                        return (mcdx_tray_move(cdi, 1));
 542                }
 543
 544        case CDROMCLOSETRAY:{
 545                        xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n");
 546                        return (mcdx_tray_move(cdi, 0));
 547                }
 548
 549        case CDROMVOLCTRL:{
 550                        struct cdrom_volctrl *volctrl =
 551                            (struct cdrom_volctrl *) arg;
 552                        xtrace(IOCTL, "ioctl() VOLCTRL\n");
 553
 554#if 0                           /* not tested! */
 555                        /* adjust for the weirdness of workman (md) */
 556                        /* can't test it (hs) */
 557                        volctrl.channel2 = volctrl.channel1;
 558                        volctrl.channel1 = volctrl.channel3 = 0x00;
 559#endif
 560                        return mcdx_setattentuator(stuffp, volctrl, 2);
 561                }
 562
 563        default:
 564                return -EINVAL;
 565        }
 566}
 567
 568void do_mcdx_request(request_queue_t * q)
 569{
 570        struct s_drive_stuff *stuffp;
 571        struct request *req;
 572
 573      again:
 574
 575        req = elv_next_request(q);
 576        if (!req)
 577                return;
 578
 579        stuffp = req->rq_disk->private_data;
 580
 581        if (!stuffp->present) {
 582                xwarn("do_request(): bad device: %s\n",req->rq_disk->disk_name);
 583                xtrace(REQUEST, "end_request(0): bad device\n");
 584                end_request(req, 0);
 585                return;
 586        }
 587
 588        if (stuffp->audio) {
 589                xwarn("do_request() attempt to read from audio cd\n");
 590                xtrace(REQUEST, "end_request(0): read from audio\n");
 591                end_request(req, 0);
 592                return;
 593        }
 594
 595        xtrace(REQUEST, "do_request() (%lu + %lu)\n",
 596               req->sector, req->nr_sectors);
 597
 598        if (req->cmd != READ) {
 599                xwarn("do_request(): non-read command to cd!!\n");
 600                xtrace(REQUEST, "end_request(0): write\n");
 601                end_request(req, 0);
 602                return;
 603        }
 604        else {
 605                stuffp->status = 0;
 606                while (req->nr_sectors) {
 607                        int i;
 608
 609                        i = mcdx_transfer(stuffp,
 610                                          req->buffer,
 611                                          req->sector,
 612                                          req->nr_sectors);
 613
 614                        if (i == -1) {
 615                                end_request(req, 0);
 616                                goto again;
 617                        }
 618                        req->sector += i;
 619                        req->nr_sectors -= i;
 620                        req->buffer += (i * 512);
 621                }
 622                end_request(req, 1);
 623                goto again;
 624
 625                xtrace(REQUEST, "end_request(1)\n");
 626                end_request(req, 1);
 627        }
 628
 629        goto again;
 630}
 631
 632static int mcdx_open(struct cdrom_device_info *cdi, int purpose)
 633{
 634        struct s_drive_stuff *stuffp;
 635        xtrace(OPENCLOSE, "open()\n");
 636        stuffp = cdi->handle;
 637        if (!stuffp->present)
 638                return -ENXIO;
 639
 640        /* Make the modules looking used ... (thanx bjorn).
 641         * But we shouldn't forget to decrement the module counter
 642         * on error return */
 643
 644        /* this is only done to test if the drive talks with us */
 645        if (-1 == mcdx_getstatus(stuffp, 1))
 646                return -EIO;
 647
 648        if (stuffp->xxx) {
 649
 650                xtrace(OPENCLOSE, "open() media changed\n");
 651                stuffp->audiostatus = CDROM_AUDIO_INVALID;
 652                stuffp->readcmd = 0;
 653                xtrace(OPENCLOSE, "open() Request multisession info\n");
 654                if (-1 ==
 655                    mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6))
 656                        xinfo("No multidiskinfo\n");
 657        } else {
 658                /* multisession ? */
 659                if (!stuffp->multi.multi)
 660                        stuffp->multi.msf_last.second = 2;
 661
 662                xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
 663                       stuffp->multi.multi,
 664                       stuffp->multi.msf_last.minute,
 665                       stuffp->multi.msf_last.second,
 666                       stuffp->multi.msf_last.frame);
 667
 668                {;
 669                }               /* got multisession information */
 670                /* request the disks table of contents (aka diskinfo) */
 671                if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
 672
 673                        stuffp->lastsector = -1;
 674
 675                } else {
 676
 677                        stuffp->lastsector = (CD_FRAMESIZE / 512)
 678                            * msf2log(&stuffp->di.msf_leadout) - 1;
 679
 680                        xtrace(OPENCLOSE,
 681                               "open() start %d (%02x:%02x.%02x) %d\n",
 682                               stuffp->di.n_first,
 683                               stuffp->di.msf_first.minute,
 684                               stuffp->di.msf_first.second,
 685                               stuffp->di.msf_first.frame,
 686                               msf2log(&stuffp->di.msf_first));
 687                        xtrace(OPENCLOSE,
 688                               "open() last %d (%02x:%02x.%02x) %d\n",
 689                               stuffp->di.n_last,
 690                               stuffp->di.msf_leadout.minute,
 691                               stuffp->di.msf_leadout.second,
 692                               stuffp->di.msf_leadout.frame,
 693                               msf2log(&stuffp->di.msf_leadout));
 694                }
 695
 696                if (stuffp->toc) {
 697                        xtrace(MALLOC, "open() free old toc @ %p\n",
 698                               stuffp->toc);
 699                        kfree(stuffp->toc);
 700
 701                        stuffp->toc = NULL;
 702                }
 703
 704                xtrace(OPENCLOSE, "open() init irq generation\n");
 705                if (-1 == mcdx_config(stuffp, 1))
 706                        return -EIO;
 707#if FALLBACK
 708                /* Set the read speed */
 709                xwarn("AAA %x AAA\n", stuffp->readcmd);
 710                if (stuffp->readerrs)
 711                        stuffp->readcmd = READ1X;
 712                else
 713                        stuffp->readcmd =
 714                            stuffp->present | SINGLE ? READ1X : READ2X;
 715                xwarn("XXX %x XXX\n", stuffp->readcmd);
 716#else
 717                stuffp->readcmd =
 718                    stuffp->present | SINGLE ? READ1X : READ2X;
 719#endif
 720
 721                /* try to get the first sector, iff any ... */
 722                if (stuffp->lastsector >= 0) {
 723                        char buf[512];
 724                        int ans;
 725                        int tries;
 726
 727                        stuffp->xa = 0;
 728                        stuffp->audio = 0;
 729
 730                        for (tries = 6; tries; tries--) {
 731
 732                                stuffp->introk = 1;
 733
 734                                xtrace(OPENCLOSE, "open() try as %s\n",
 735                                       stuffp->xa ? "XA" : "normal");
 736                                /* set data mode */
 737                                if (-1 == (ans = mcdx_setdatamode(stuffp,
 738                                                                  stuffp->
 739                                                                  xa ?
 740                                                                  MODE2 :
 741                                                                  MODE1,
 742                                                                  1))) {
 743                                        /* return -EIO; */
 744                                        stuffp->xa = 0;
 745                                        break;
 746                                }
 747
 748                                if ((stuffp->audio = e_audio(ans)))
 749                                        break;
 750
 751                                while (0 ==
 752                                       (ans =
 753                                        mcdx_transfer(stuffp, buf, 0, 1)));
 754
 755                                if (ans == 1)
 756                                        break;
 757                                stuffp->xa = !stuffp->xa;
 758                        }
 759                }
 760                /* xa disks will be read in raw mode, others not */
 761                if (-1 == mcdx_setdrivemode(stuffp,
 762                                            stuffp->xa ? RAW : COOKED,
 763                                            1))
 764                        return -EIO;
 765                if (stuffp->audio) {
 766                        xinfo("open() audio disk found\n");
 767                } else if (stuffp->lastsector >= 0) {
 768                        xinfo("open() %s%s disk found\n",
 769                              stuffp->xa ? "XA / " : "",
 770                              stuffp->multi.
 771                              multi ? "Multi Session" : "Single Session");
 772                }
 773        }
 774        stuffp->xxx = 0;
 775        stuffp->users++;
 776        return 0;
 777}
 778
 779static void mcdx_close(struct cdrom_device_info *cdi)
 780{
 781        struct s_drive_stuff *stuffp;
 782
 783        xtrace(OPENCLOSE, "close()\n");
 784
 785        stuffp = cdi->handle;
 786
 787        --stuffp->users;
 788}
 789
 790static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr)
 791/*      Return: 1 if media changed since last call to this function
 792                        0 otherwise */
 793{
 794        struct s_drive_stuff *stuffp;
 795
 796        xinfo("mcdx_media_changed called for device %s\n", cdi->name);
 797
 798        stuffp = cdi->handle;
 799        mcdx_getstatus(stuffp, 1);
 800
 801        if (stuffp->yyy == 0)
 802                return 0;
 803
 804        stuffp->yyy = 0;
 805        return 1;
 806}
 807
 808#ifndef MODULE
 809static int __init mcdx_setup(char *str)
 810{
 811        int pi[4];
 812        (void) get_options(str, ARRAY_SIZE(pi), pi);
 813
 814        if (pi[0] > 0)
 815                mcdx_drive_map[0][0] = pi[1];
 816        if (pi[0] > 1)
 817                mcdx_drive_map[0][1] = pi[2];
 818        return 1;
 819}
 820
 821__setup("mcdx=", mcdx_setup);
 822
 823#endif
 824
 825/* DIRTY PART ******************************************************/
 826
 827static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
 828/* This routine is used for sleeping.
 829 * A jifs value <0 means NO sleeping,
 830 *              =0 means minimal sleeping (let the kernel
 831 *                 run for other processes)
 832 *              >0 means at least sleep for that amount.
 833 *      May be we could use a simple count loop w/ jumps to itself, but
 834 *      I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
 835{
 836        if (jifs < 0)
 837                return;
 838
 839        xtrace(SLEEP, "*** delay: sleepq\n");
 840        interruptible_sleep_on_timeout(&stuff->sleepq, jifs);
 841        xtrace(SLEEP, "delay awoken\n");
 842        if (signal_pending(current)) {
 843                xtrace(SLEEP, "got signal\n");
 844        }
 845}
 846
 847static irqreturn_t mcdx_intr(int irq, void *dev_id, struct pt_regs *regs)
 848{
 849        struct s_drive_stuff *stuffp = dev_id;
 850        unsigned char b;
 851
 852        if (stuffp == NULL) {
 853                xwarn("mcdx: no device for intr %d\n", irq);
 854                return IRQ_NONE;
 855        }
 856#ifdef AK2
 857        if (!stuffp->busy && stuffp->pending)
 858                stuffp->int_err = 1;
 859
 860#endif                          /* AK2 */
 861        /* get the interrupt status */
 862        b = inb(stuffp->rreg_status);
 863        stuffp->introk = ~b & MCDX_RBIT_DTEN;
 864
 865        /* NOTE: We only should get interrupts if the data we
 866         * requested are ready to transfer.
 867         * But the drive seems to generate ``asynchronous'' interrupts
 868         * on several error conditions too.  (Despite the err int enable
 869         * setting during initialisation) */
 870
 871        /* if not ok, read the next byte as the drives status */
 872        if (!stuffp->introk) {
 873                xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b);
 874                if (~b & MCDX_RBIT_STEN) {
 875                        xinfo("intr() irq %d    status 0x%02x\n",
 876                              irq, inb(stuffp->rreg_data));
 877                } else {
 878                        xinfo("intr() irq %d ambiguous hw status\n", irq);
 879                }
 880        } else {
 881                xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b);
 882        }
 883
 884        stuffp->busy = 0;
 885        wake_up_interruptible(&stuffp->busyq);
 886        return IRQ_HANDLED;
 887}
 888
 889
 890static int mcdx_talk(struct s_drive_stuff *stuffp,
 891          const unsigned char *cmd, size_t cmdlen,
 892          void *buffer, size_t size, unsigned int timeout, int tries)
 893/* Send a command to the drive, wait for the result.
 894 * returns -1 on timeout, drive status otherwise
 895 * If buffer is not zero, the result (length size) is stored there.
 896 * If buffer is zero the size should be the number of bytes to read
 897 * from the drive.  These bytes are discarded.
 898 */
 899{
 900        int st;
 901        char c;
 902        int discard;
 903
 904        /* Somebody wants the data read? */
 905        if ((discard = (buffer == NULL)))
 906                buffer = &c;
 907
 908        while (stuffp->lock) {
 909                xtrace(SLEEP, "*** talk: lockq\n");
 910                interruptible_sleep_on(&stuffp->lockq);
 911                xtrace(SLEEP, "talk: awoken\n");
 912        }
 913
 914        stuffp->lock = 1;
 915
 916        /* An operation other then reading data destroys the
 917           * data already requested and remembered in stuffp->request, ... */
 918        stuffp->valid = 0;
 919
 920#if MCDX_DEBUG & TALK
 921        {
 922                unsigned char i;
 923                xtrace(TALK,
 924                       "talk() %d / %d tries, res.size %d, command 0x%02x",
 925                       tries, timeout, size, (unsigned char) cmd[0]);
 926                for (i = 1; i < cmdlen; i++)
 927                        xtrace(TALK, " 0x%02x", cmd[i]);
 928                xtrace(TALK, "\n");
 929        }
 930#endif
 931
 932        /*  give up if all tries are done (bad) or if the status
 933         *  st != -1 (good) */
 934        for (st = -1; st == -1 && tries; tries--) {
 935
 936                char *bp = (char *) buffer;
 937                size_t sz = size;
 938
 939                outsb(stuffp->wreg_data, cmd, cmdlen);
 940                xtrace(TALK, "talk() command sent\n");
 941
 942                /* get the status byte */
 943                if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
 944                        xinfo("talk() %02x timed out (status), %d tr%s left\n",
 945                             cmd[0], tries - 1, tries == 2 ? "y" : "ies");
 946                        continue;
 947                }
 948                st = *bp;
 949                sz--;
 950                if (!discard)
 951                        bp++;
 952
 953                xtrace(TALK, "talk() got status 0x%02x\n", st);
 954
 955                /* command error? */
 956                if (e_cmderr(st)) {
 957                        xwarn("command error cmd = %02x %s \n",
 958                              cmd[0], cmdlen > 1 ? "..." : "");
 959                        st = -1;
 960                        continue;
 961                }
 962
 963                /* audio status? */
 964                if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
 965                        stuffp->audiostatus =
 966                            e_audiobusy(st) ? CDROM_AUDIO_PLAY :
 967                            CDROM_AUDIO_NO_STATUS;
 968                else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
 969                         && e_audiobusy(st) == 0)
 970                        stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
 971
 972                /* media change? */
 973                if (e_changed(st)) {
 974                        xinfo("talk() media changed\n");
 975                        stuffp->xxx = stuffp->yyy = 1;
 976                }
 977
 978                /* now actually get the data */
 979                while (sz--) {
 980                        if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
 981                                xinfo("talk() %02x timed out (data), %d tr%s left\n",
 982                                     cmd[0], tries - 1,
 983                                     tries == 2 ? "y" : "ies");
 984                                st = -1;
 985                                break;
 986                        }
 987                        if (!discard)
 988                                bp++;
 989                        xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1));
 990                }
 991        }
 992
 993#if !MCDX_QUIET
 994        if (!tries && st == -1)
 995                xinfo("talk() giving up\n");
 996#endif
 997
 998        stuffp->lock = 0;
 999        wake_up_interruptible(&stuffp->lockq);
1000
1001        xtrace(TALK, "talk() done with 0x%02x\n", st);
1002        return st;
1003}
1004
1005/* MODULE STUFF ***********************************************************/
1006
1007int __mcdx_init(void)
1008{
1009        int i;
1010        int drives = 0;
1011
1012        mcdx_init();
1013        for (i = 0; i < MCDX_NDRIVES; i++) {
1014                if (mcdx_stuffp[i]) {
1015                        xtrace(INIT, "init_module() drive %d stuff @ %p\n",
1016                               i, mcdx_stuffp[i]);
1017                        drives++;
1018                }
1019        }
1020
1021        if (!drives)
1022                return -EIO;
1023
1024        return 0;
1025}
1026
1027void __exit mcdx_exit(void)
1028{
1029        int i;
1030
1031        xinfo("cleanup_module called\n");
1032
1033        for (i = 0; i < MCDX_NDRIVES; i++) {
1034                struct s_drive_stuff *stuffp = mcdx_stuffp[i];
1035                if (!stuffp)
1036                        continue;
1037                del_gendisk(stuffp->disk);
1038                if (unregister_cdrom(&stuffp->info)) {
1039                        printk(KERN_WARNING "Can't unregister cdrom mcdx\n");
1040                        continue;
1041                }
1042                put_disk(stuffp->disk);
1043                release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1044                free_irq(stuffp->irq, NULL);
1045                if (stuffp->toc) {
1046                        xtrace(MALLOC, "cleanup_module() free toc @ %p\n",
1047                               stuffp->toc);
1048                        kfree(stuffp->toc);
1049                }
1050                xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n",
1051                       stuffp);
1052                mcdx_stuffp[i] = NULL;
1053                kfree(stuffp);
1054        }
1055
1056        if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) {
1057                xwarn("cleanup() unregister_blkdev() failed\n");
1058        }
1059        blk_cleanup_queue(mcdx_queue);
1060#if !MCDX_QUIET
1061        else
1062        xinfo("cleanup() succeeded\n");
1063#endif
1064}
1065
1066#ifdef MODULE
1067module_init(__mcdx_init);
1068#endif
1069module_exit(mcdx_exit);
1070
1071
1072/* Support functions ************************************************/
1073
1074int __init mcdx_init_drive(int drive)
1075{
1076        struct s_version version;
1077        struct gendisk *disk;
1078        struct s_drive_stuff *stuffp;
1079        int size = sizeof(*stuffp);
1080        char msg[80];
1081
1082        xtrace(INIT, "init() try drive %d\n", drive);
1083
1084        xtrace(INIT, "kmalloc space for stuffpt's\n");
1085        xtrace(MALLOC, "init() malloc %d bytes\n", size);
1086        if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
1087                xwarn("init() malloc failed\n");
1088                return 1;
1089        }
1090
1091        disk = alloc_disk(1);
1092        if (!disk) {
1093                xwarn("init() malloc failed\n");
1094                kfree(stuffp);
1095                return 1;
1096        }
1097
1098        xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n",
1099               sizeof(*stuffp), stuffp);
1100
1101        /* set default values */
1102        memset(stuffp, 0, sizeof(*stuffp));
1103
1104        stuffp->present = 0;    /* this should be 0 already */
1105        stuffp->toc = NULL;     /* this should be NULL already */
1106
1107        /* setup our irq and i/o addresses */
1108        stuffp->irq = irq(mcdx_drive_map[drive]);
1109        stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]);
1110        stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;
1111        stuffp->wreg_hcon = stuffp->wreg_reset + 1;
1112        stuffp->wreg_chn = stuffp->wreg_hcon + 1;
1113
1114        init_waitqueue_head(&stuffp->busyq);
1115        init_waitqueue_head(&stuffp->lockq);
1116        init_waitqueue_head(&stuffp->sleepq);
1117
1118        /* check if i/o addresses are available */
1119        if (!request_region(stuffp->wreg_data, MCDX_IO_SIZE, "mcdx")) {
1120                xwarn("0x%03x,%d: Init failed. "
1121                      "I/O ports (0x%03x..0x%03x) already in use.\n",
1122                      stuffp->wreg_data, stuffp->irq,
1123                      stuffp->wreg_data,
1124                      stuffp->wreg_data + MCDX_IO_SIZE - 1);
1125                xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1126                kfree(stuffp);
1127                put_disk(disk);
1128                xtrace(INIT, "init() continue at next drive\n");
1129                return 0;       /* next drive */
1130        }
1131
1132        xtrace(INIT, "init() i/o port is available at 0x%03x\n"
1133               stuffp->wreg_data);
1134        xtrace(INIT, "init() hardware reset\n");
1135        mcdx_reset(stuffp, HARD, 1);
1136
1137        xtrace(INIT, "init() get version\n");
1138        if (-1 == mcdx_requestversion(stuffp, &version, 4)) {
1139                /* failed, next drive */
1140                release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1141                xwarn("%s=0x%03x,%d: Init failed. Can't get version.\n",
1142                      MCDX, stuffp->wreg_data, stuffp->irq);
1143                xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1144                kfree(stuffp);
1145                put_disk(disk);
1146                xtrace(INIT, "init() continue at next drive\n");
1147                return 0;
1148        }
1149
1150        switch (version.code) {
1151        case 'D':
1152                stuffp->readcmd = READ2X;
1153                stuffp->present = DOUBLE | DOOR | MULTI;
1154                break;
1155        case 'F':
1156                stuffp->readcmd = READ1X;
1157                stuffp->present = SINGLE | DOOR | MULTI;
1158                break;
1159        case 'M':
1160                stuffp->readcmd = READ1X;
1161                stuffp->present = SINGLE;
1162                break;
1163        default:
1164                stuffp->present = 0;
1165                break;
1166        }
1167
1168        stuffp->playcmd = READ1X;
1169
1170        if (!stuffp->present) {
1171                release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1172                xwarn("%s=0x%03x,%d: Init failed. No Mitsumi CD-ROM?.\n",
1173                      MCDX, stuffp->wreg_data, stuffp->irq);
1174                kfree(stuffp);
1175                put_disk(disk);
1176                return 0;       /* next drive */
1177        }
1178
1179        xtrace(INIT, "init() register blkdev\n");
1180        if (register_blkdev(MAJOR_NR, "mcdx")) {
1181                release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1182                kfree(stuffp);
1183                put_disk(disk);
1184                return 1;
1185        }
1186
1187        mcdx_queue = blk_init_queue(do_mcdx_request, &mcdx_lock);
1188        if (!mcdx_queue) {
1189                unregister_blkdev(MAJOR_NR, "mcdx");
1190                release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1191                kfree(stuffp);
1192                put_disk(disk);
1193                return 1;
1194        }
1195
1196        xtrace(INIT, "init() subscribe irq and i/o\n");
1197        if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, "mcdx", stuffp)) {
1198                release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1199                xwarn("%s=0x%03x,%d: Init failed. Can't get irq (%d).\n",
1200                      MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq);
1201                stuffp->irq = 0;
1202                blk_cleanup_queue(mcdx_queue);
1203                kfree(stuffp);
1204                put_disk(disk);
1205                return 0;
1206        }
1207
1208        xtrace(INIT, "init() get garbage\n");
1209        {
1210                int i;
1211                mcdx_delay(stuffp, HZ / 2);
1212                for (i = 100; i; i--)
1213                        (void) inb(stuffp->rreg_status);
1214        }
1215
1216
1217#if WE_KNOW_WHY
1218        /* irq 11 -> channel register */
1219        outb(0x50, stuffp->wreg_chn);
1220#endif
1221
1222        xtrace(INIT, "init() set non dma but irq mode\n");
1223        mcdx_config(stuffp, 1);
1224
1225        stuffp->info.ops = &mcdx_dops;
1226        stuffp->info.speed = 2;
1227        stuffp->info.capacity = 1;
1228        stuffp->info.handle = stuffp;
1229        sprintf(stuffp->info.name, "mcdx%d", drive);
1230        disk->major = MAJOR_NR;
1231        disk->first_minor = drive;
1232        strcpy(disk->disk_name, stuffp->info.name);
1233        disk->fops = &mcdx_bdops;
1234        disk->flags = GENHD_FL_CD;
1235        stuffp->disk = disk;
1236
1237        sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%03x, irq %d."
1238                " (Firmware version %c %x)\n",
1239                stuffp->wreg_data, stuffp->irq, version.code, version.ver);
1240        mcdx_stuffp[drive] = stuffp;
1241        xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp);
1242        if (register_cdrom(&stuffp->info) != 0) {
1243                printk("Cannot register Mitsumi CD-ROM!\n");
1244                free_irq(stuffp->irq, NULL);
1245                release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1246                kfree(stuffp);
1247                put_disk(disk);
1248                if (unregister_blkdev(MAJOR_NR, "mcdx") != 0)
1249                        xwarn("cleanup() unregister_blkdev() failed\n");
1250                blk_cleanup_queue(mcdx_queue);
1251                return 2;
1252        }
1253        disk->private_data = stuffp;
1254        disk->queue = mcdx_queue;
1255        add_disk(disk);
1256        printk(msg);
1257        return 0;
1258}
1259
1260int __init mcdx_init(void)
1261{
1262        int drive;
1263#ifdef MODULE
1264        xwarn("Version 2.14(hs) for " UTS_RELEASE "\n");
1265#else
1266        xwarn("Version 2.14(hs) \n");
1267#endif
1268
1269        xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");
1270
1271        /* zero the pointer array */
1272        for (drive = 0; drive < MCDX_NDRIVES; drive++)
1273                mcdx_stuffp[drive] = NULL;
1274
1275        /* do the initialisation */
1276        for (drive = 0; drive < MCDX_NDRIVES; drive++) {
1277                switch (mcdx_init_drive(drive)) {
1278                case 2:
1279                        return -EIO;
1280                case 1:
1281                        break;
1282                }
1283        }
1284        return 0;
1285}
1286
1287static int mcdx_transfer(struct s_drive_stuff *stuffp,
1288              char *p, int sector, int nr_sectors)
1289/*      This seems to do the actually transfer.  But it does more.  It
1290        keeps track of errors occurred and will (if possible) fall back
1291        to single speed on error.
1292        Return: -1 on timeout or other error
1293                        else status byte (as in stuff->st) */
1294{
1295        int ans;
1296
1297        ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
1298        return ans;
1299#if FALLBACK
1300        if (-1 == ans)
1301                stuffp->readerrs++;
1302        else
1303                return ans;
1304
1305        if (stuffp->readerrs && stuffp->readcmd == READ1X) {
1306                xwarn("XXX Already reading 1x -- no chance\n");
1307                return -1;
1308        }
1309
1310        xwarn("XXX Fallback to 1x\n");
1311
1312        stuffp->readcmd = READ1X;
1313        return mcdx_transfer(stuffp, p, sector, nr_sectors);
1314#endif
1315
1316}
1317
1318
1319static int mcdx_xfer(struct s_drive_stuff *stuffp,
1320                     char *p, int sector, int nr_sectors)
1321/*      This does actually the transfer from the drive.
1322        Return: -1 on timeout or other error
1323                        else status byte (as in stuff->st) */
1324{
1325        int border;
1326        int done = 0;
1327        long timeout;
1328
1329        if (stuffp->audio) {
1330                xwarn("Attempt to read from audio CD.\n");
1331                return -1;
1332        }
1333
1334        if (!stuffp->readcmd) {
1335                xinfo("Can't transfer from missing disk.\n");
1336                return -1;
1337        }
1338
1339        while (stuffp->lock) {
1340                interruptible_sleep_on(&stuffp->lockq);
1341        }
1342
1343        if (stuffp->valid && (sector >= stuffp->pending)
1344            && (sector < stuffp->low_border)) {
1345
1346                /* All (or at least a part of the sectors requested) seems
1347                   * to be already requested, so we don't need to bother the
1348                   * drive with new requests ...
1349                   * Wait for the drive become idle, but first
1350                   * check for possible occurred errors --- the drive
1351                   * seems to report them asynchronously */
1352
1353
1354                border = stuffp->high_border < (border =
1355                                                sector + nr_sectors)
1356                    ? stuffp->high_border : border;
1357
1358                stuffp->lock = current->pid;
1359
1360                do {
1361
1362                        while (stuffp->busy) {
1363
1364                                timeout =
1365                                    interruptible_sleep_on_timeout
1366                                    (&stuffp->busyq, 5 * HZ);
1367
1368                                if (!stuffp->introk) {
1369                                        xtrace(XFER,
1370                                               "error via interrupt\n");
1371                                } else if (!timeout) {
1372                                        xtrace(XFER, "timeout\n");
1373                                } else if (signal_pending(current)) {
1374                                        xtrace(XFER, "signal\n");
1375                                } else
1376                                        continue;
1377
1378                                stuffp->lock = 0;
1379                                stuffp->busy = 0;
1380                                stuffp->valid = 0;
1381
1382                                wake_up_interruptible(&stuffp->lockq);
1383                                xtrace(XFER, "transfer() done (-1)\n");
1384                                return -1;
1385                        }
1386
1387                        /* check if we need to set the busy flag (as we
1388                         * expect an interrupt */
1389                        stuffp->busy = (3 == (stuffp->pending & 3));
1390
1391                        /* Test if it's the first sector of a block,
1392                         * there we have to skip some bytes as we read raw data */
1393                        if (stuffp->xa && (0 == (stuffp->pending & 3))) {
1394                                const int HEAD =
1395                                    CD_FRAMESIZE_RAW - CD_XA_TAIL -
1396                                    CD_FRAMESIZE;
1397                                insb(stuffp->rreg_data, p, HEAD);
1398                        }
1399
1400                        /* now actually read the data */
1401                        insb(stuffp->rreg_data, p, 512);
1402
1403                        /* test if it's the last sector of a block,
1404                         * if so, we have to handle XA special */
1405                        if ((3 == (stuffp->pending & 3)) && stuffp->xa) {
1406                                char dummy[CD_XA_TAIL];
1407                                insb(stuffp->rreg_data, &dummy[0], CD_XA_TAIL);
1408                        }
1409
1410                        if (stuffp->pending == sector) {
1411                                p += 512;
1412                                done++;
1413                                sector++;
1414                        }
1415                } while (++(stuffp->pending) < border);
1416
1417                stuffp->lock = 0;
1418                wake_up_interruptible(&stuffp->lockq);
1419
1420        } else {
1421
1422                /* The requested sector(s) is/are out of the
1423                 * already requested range, so we have to bother the drive
1424                 * with a new request. */
1425
1426                static unsigned char cmd[] = {
1427                        0,
1428                        0, 0, 0,
1429                        0, 0, 0
1430                };
1431
1432                cmd[0] = stuffp->readcmd;
1433
1434                /* The numbers held in ->pending, ..., should be valid */
1435                stuffp->valid = 1;
1436                stuffp->pending = sector & ~3;
1437
1438                /* do some sanity checks */
1439                if (stuffp->pending > stuffp->lastsector) {
1440                        xwarn
1441                            ("transfer() sector %d from nirvana requested.\n",
1442                             stuffp->pending);
1443                        stuffp->status = MCDX_ST_EOM;
1444                        stuffp->valid = 0;
1445                        xtrace(XFER, "transfer() done (-1)\n");
1446                        return -1;
1447                }
1448
1449                if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE)
1450                    > stuffp->lastsector + 1) {
1451                        xtrace(XFER, "cut low_border\n");
1452                        stuffp->low_border = stuffp->lastsector + 1;
1453                }
1454                if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE)
1455                    > stuffp->lastsector + 1) {
1456                        xtrace(XFER, "cut high_border\n");
1457                        stuffp->high_border = stuffp->lastsector + 1;
1458                }
1459
1460                {               /* Convert the sector to be requested to MSF format */
1461                        struct cdrom_msf0 pending;
1462                        log2msf(stuffp->pending / 4, &pending);
1463                        cmd[1] = pending.minute;
1464                        cmd[2] = pending.second;
1465                        cmd[3] = pending.frame;
1466                }
1467
1468                cmd[6] =
1469                    (unsigned
1470                     char) ((stuffp->high_border - stuffp->pending) / 4);
1471                xtrace(XFER, "[%2d]\n", cmd[6]);
1472
1473                stuffp->busy = 1;
1474                /* Now really issue the request command */
1475                outsb(stuffp->wreg_data, cmd, sizeof cmd);
1476
1477        }
1478#ifdef AK2
1479        if (stuffp->int_err) {
1480                stuffp->valid = 0;
1481                stuffp->int_err = 0;
1482                return -1;
1483        }
1484#endif                          /* AK2 */
1485
1486        stuffp->low_border = (stuffp->low_border +=
1487                              done) <
1488            stuffp->high_border ? stuffp->low_border : stuffp->high_border;
1489
1490        return done;
1491}
1492
1493
1494/*      Access to elements of the mcdx_drive_map members */
1495
1496static unsigned port(int *ip)
1497{
1498        return ip[0];
1499}
1500static int irq(int *ip)
1501{
1502        return ip[1];
1503}
1504
1505/*      Misc number converters */
1506
1507static unsigned int bcd2uint(unsigned char c)
1508{
1509        return (c >> 4) * 10 + (c & 0x0f);
1510}
1511
1512static unsigned int uint2bcd(unsigned int ival)
1513{
1514        return ((ival / 10) << 4) | (ival % 10);
1515}
1516
1517static void log2msf(unsigned int l, struct cdrom_msf0 *pmsf)
1518{
1519        l += CD_MSF_OFFSET;
1520        pmsf->minute = uint2bcd(l / 4500), l %= 4500;
1521        pmsf->second = uint2bcd(l / 75);
1522        pmsf->frame = uint2bcd(l % 75);
1523}
1524
1525static unsigned int msf2log(const struct cdrom_msf0 *pmsf)
1526{
1527        return bcd2uint(pmsf->frame)
1528            + bcd2uint(pmsf->second) * 75
1529            + bcd2uint(pmsf->minute) * 4500 - CD_MSF_OFFSET;
1530}
1531
1532int mcdx_readtoc(struct s_drive_stuff *stuffp)
1533/*  Read the toc entries from the CD,
1534 *  Return: -1 on failure, else 0 */
1535{
1536
1537        if (stuffp->toc) {
1538                xtrace(READTOC, "ioctl() toc already read\n");
1539                return 0;
1540        }
1541
1542        xtrace(READTOC, "ioctl() readtoc for %d tracks\n",
1543               stuffp->di.n_last - stuffp->di.n_first + 1);
1544
1545        if (-1 == mcdx_hold(stuffp, 1))
1546                return -1;
1547
1548        xtrace(READTOC, "ioctl() tocmode\n");
1549        if (-1 == mcdx_setdrivemode(stuffp, TOC, 1))
1550                return -EIO;
1551
1552        /* all seems to be ok so far ... malloc */
1553        {
1554                int size;
1555                size =
1556                    sizeof(struct s_subqcode) * (stuffp->di.n_last -
1557                                                 stuffp->di.n_first + 2);
1558
1559                xtrace(MALLOC, "ioctl() malloc %d bytes\n", size);
1560                stuffp->toc = kmalloc(size, GFP_KERNEL);
1561                if (!stuffp->toc) {
1562                        xwarn("Cannot malloc %d bytes for toc\n", size);
1563                        mcdx_setdrivemode(stuffp, DATA, 1);
1564                        return -EIO;
1565                }
1566        }
1567
1568        /* now read actually the index */
1569        {
1570                int trk;
1571                int retries;
1572
1573                for (trk = 0;
1574                     trk < (stuffp->di.n_last - stuffp->di.n_first + 1);
1575                     trk++)
1576                        stuffp->toc[trk].index = 0;
1577
1578                for (retries = 300; retries; retries--) {       /* why 300? */
1579                        struct s_subqcode q;
1580                        unsigned int idx;
1581
1582                        if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
1583                                mcdx_setdrivemode(stuffp, DATA, 1);
1584                                return -EIO;
1585                        }
1586
1587                        idx = bcd2uint(q.index);
1588
1589                        if ((idx > 0)
1590                            && (idx <= stuffp->di.n_last)
1591                            && (q.tno == 0)
1592                            && (stuffp->toc[idx - stuffp->di.n_first].
1593                                index == 0)) {
1594                                stuffp->toc[idx - stuffp->di.n_first] = q;
1595                                xtrace(READTOC,
1596                                       "ioctl() toc idx %d (trk %d)\n",
1597                                       idx, trk);
1598                                trk--;
1599                        }
1600                        if (trk == 0)
1601                                break;
1602                }
1603                memset(&stuffp->
1604                       toc[stuffp->di.n_last - stuffp->di.n_first + 1], 0,
1605                       sizeof(stuffp->toc[0]));
1606                stuffp->toc[stuffp->di.n_last - stuffp->di.n_first +
1607                            1].dt = stuffp->di.msf_leadout;
1608        }
1609
1610        /* unset toc mode */
1611        xtrace(READTOC, "ioctl() undo toc mode\n");
1612        if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
1613                return -EIO;
1614
1615#if MCDX_DEBUG && READTOC
1616        {
1617                int trk;
1618                for (trk = 0;
1619                     trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
1620                     trk++)
1621                        xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x"
1622                               "  %02x:%02x.%02x  %02x:%02x.%02x\n",
1623                               trk + stuffp->di.n_first,
1624                               stuffp->toc[trk].control,
1625                               stuffp->toc[trk].tno,
1626                               stuffp->toc[trk].index,
1627                               stuffp->toc[trk].tt.minute,
1628                               stuffp->toc[trk].tt.second,
1629                               stuffp->toc[trk].tt.frame,
1630                               stuffp->toc[trk].dt.minute,
1631                               stuffp->toc[trk].dt.second,
1632                               stuffp->toc[trk].dt.frame);
1633        }
1634#endif
1635
1636        return 0;
1637}
1638
1639static int
1640mcdx_playmsf(struct s_drive_stuff *stuffp, const struct cdrom_msf *msf)
1641{
1642        unsigned char cmd[7] = {
1643                0, 0, 0, 0, 0, 0, 0
1644        };
1645
1646        if (!stuffp->readcmd) {
1647                xinfo("Can't play from missing disk.\n");
1648                return -1;
1649        }
1650
1651        cmd[0] = stuffp->playcmd;
1652
1653        cmd[1] = msf->cdmsf_min0;
1654        cmd[2] = msf->cdmsf_sec0;
1655        cmd[3] = msf->cdmsf_frame0;
1656        cmd[4] = msf->cdmsf_min1;
1657        cmd[5] = msf->cdmsf_sec1;
1658        cmd[6] = msf->cdmsf_frame1;
1659
1660        xtrace(PLAYMSF, "ioctl(): play %x "
1661               "%02x:%02x:%02x -- %02x:%02x:%02x\n",
1662               cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]);
1663
1664        outsb(stuffp->wreg_data, cmd, sizeof cmd);
1665
1666        if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
1667                xwarn("playmsf() timeout\n");
1668                return -1;
1669        }
1670
1671        stuffp->audiostatus = CDROM_AUDIO_PLAY;
1672        return 0;
1673}
1674
1675static int
1676mcdx_playtrk(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti)
1677{
1678        struct s_subqcode *p;
1679        struct cdrom_msf msf;
1680
1681        if (-1 == mcdx_readtoc(stuffp))
1682                return -1;
1683
1684        if (ti)
1685                p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
1686        else
1687                p = &stuffp->start;
1688
1689        msf.cdmsf_min0 = p->dt.minute;
1690        msf.cdmsf_sec0 = p->dt.second;
1691        msf.cdmsf_frame0 = p->dt.frame;
1692
1693        if (ti) {
1694                p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
1695                stuffp->stop = *p;
1696        } else
1697                p = &stuffp->stop;
1698
1699        msf.cdmsf_min1 = p->dt.minute;
1700        msf.cdmsf_sec1 = p->dt.second;
1701        msf.cdmsf_frame1 = p->dt.frame;
1702
1703        return mcdx_playmsf(stuffp, &msf);
1704}
1705
1706
1707/* Drive functions ************************************************/
1708
1709static int mcdx_tray_move(struct cdrom_device_info *cdi, int position)
1710{
1711        struct s_drive_stuff *stuffp = cdi->handle;
1712
1713        if (!stuffp->present)
1714                return -ENXIO;
1715        if (!(stuffp->present & DOOR))
1716                return -ENOSYS;
1717
1718        if (position)           /* 1: eject */
1719                return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, 3);
1720        else                    /* 0: close */
1721                return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, 3);
1722        return 1;
1723}
1724
1725static int mcdx_stop(struct s_drive_stuff *stuffp, int tries)
1726{
1727        return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries);
1728}
1729
1730static int mcdx_hold(struct s_drive_stuff *stuffp, int tries)
1731{
1732        return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries);
1733}
1734
1735static int mcdx_requestsubqcode(struct s_drive_stuff *stuffp,
1736                     struct s_subqcode *sub, int tries)
1737{
1738        char buf[11];
1739        int ans;
1740
1741        if (-1 == (ans = mcdx_talk(stuffp, "\x20", 1, buf, sizeof(buf),
1742                                   2 * HZ, tries)))
1743                return -1;
1744        sub->control = buf[1];
1745        sub->tno = buf[2];
1746        sub->index = buf[3];
1747        sub->tt.minute = buf[4];
1748        sub->tt.second = buf[5];
1749        sub->tt.frame = buf[6];
1750        sub->dt.minute = buf[8];
1751        sub->dt.second = buf[9];
1752        sub->dt.frame = buf[10];
1753
1754        return ans;
1755}
1756
1757static int mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp,
1758                          struct s_multi *multi, int tries)
1759{
1760        char buf[5];
1761        int ans;
1762
1763        if (stuffp->present & MULTI) {
1764                ans =
1765                    mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ,
1766                              tries);
1767                multi->multi = buf[1];
1768                multi->msf_last.minute = buf[2];
1769                multi->msf_last.second = buf[3];
1770                multi->msf_last.frame = buf[4];
1771                return ans;
1772        } else {
1773                multi->multi = 0;
1774                return 0;
1775        }
1776}
1777
1778static int mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info,
1779                    int tries)
1780{
1781        char buf[9];
1782        int ans;
1783        ans =
1784            mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries);
1785        if (ans == -1) {
1786                info->n_first = 0;
1787                info->n_last = 0;
1788        } else {
1789                info->n_first = bcd2uint(buf[1]);
1790                info->n_last = bcd2uint(buf[2]);
1791                info->msf_leadout.minute = buf[3];
1792                info->msf_leadout.second = buf[4];
1793                info->msf_leadout.frame = buf[5];
1794                info->msf_first.minute = buf[6];
1795                info->msf_first.second = buf[7];
1796                info->msf_first.frame = buf[8];
1797        }
1798        return ans;
1799}
1800
1801static int mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode,
1802                  int tries)
1803{
1804        char cmd[2];
1805        int ans;
1806
1807        xtrace(HW, "setdrivemode() %d\n", mode);
1808
1809        if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
1810                return -1;
1811
1812        switch (mode) {
1813        case TOC:
1814                cmd[1] |= 0x04;
1815                break;
1816        case DATA:
1817                cmd[1] &= ~0x04;
1818                break;
1819        case RAW:
1820                cmd[1] |= 0x40;
1821                break;
1822        case COOKED:
1823                cmd[1] &= ~0x40;
1824                break;
1825        default:
1826                break;
1827        }
1828        cmd[0] = 0x50;
1829        return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1830}
1831
1832static int mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode,
1833                 int tries)
1834{
1835        unsigned char cmd[2] = { 0xa0 };
1836        xtrace(HW, "setdatamode() %d\n", mode);
1837        switch (mode) {
1838        case MODE0:
1839                cmd[1] = 0x00;
1840                break;
1841        case MODE1:
1842                cmd[1] = 0x01;
1843                break;
1844        case MODE2:
1845                cmd[1] = 0x02;
1846                break;
1847        default:
1848                return -EINVAL;
1849        }
1850        return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1851}
1852
1853static int mcdx_config(struct s_drive_stuff *stuffp, int tries)
1854{
1855        char cmd[4];
1856
1857        xtrace(HW, "config()\n");
1858
1859        cmd[0] = 0x90;
1860
1861        cmd[1] = 0x10;          /* irq enable */
1862        cmd[2] = 0x05;          /* pre, err irq enable */
1863
1864        if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
1865                return -1;
1866
1867        cmd[1] = 0x02;          /* dma select */
1868        cmd[2] = 0x00;          /* no dma */
1869
1870        return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
1871}
1872
1873static int mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver,
1874                    int tries)
1875{
1876        char buf[3];
1877        int ans;
1878
1879        if (-1 == (ans = mcdx_talk(stuffp, "\xdc",
1880                                   1, buf, sizeof(buf), 2 * HZ, tries)))
1881                return ans;
1882
1883        ver->code = buf[1];
1884        ver->ver = buf[2];
1885
1886        return ans;
1887}
1888
1889static int mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
1890{
1891        if (mode == HARD) {
1892                outb(0, stuffp->wreg_chn);      /* no dma, no irq -> hardware */
1893                outb(0, stuffp->wreg_reset);    /* hw reset */
1894                return 0;
1895        } else
1896                return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
1897}
1898
1899static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock)
1900{
1901        struct s_drive_stuff *stuffp = cdi->handle;
1902        char cmd[2] = { 0xfe };
1903
1904        if (!(stuffp->present & DOOR))
1905                return -ENOSYS;
1906        if (stuffp->present & DOOR) {
1907                cmd[1] = lock ? 0x01 : 0x00;
1908                return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, 3);
1909        } else
1910                return 0;
1911}
1912
1913static int mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
1914{
1915        return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries);
1916}
1917
1918static int
1919mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char *buf)
1920{
1921        unsigned long timeout = to + jiffies;
1922        char c;
1923
1924        if (!buf)
1925                buf = &c;
1926
1927        while (inb(stuffp->rreg_status) & MCDX_RBIT_STEN) {
1928                if (time_after(jiffies, timeout))
1929                        return -1;
1930                mcdx_delay(stuffp, delay);
1931        }
1932
1933        *buf = (unsigned char) inb(stuffp->rreg_data) & 0xff;
1934
1935        return 0;
1936}
1937
1938static int mcdx_setattentuator(struct s_drive_stuff *stuffp,
1939                    struct cdrom_volctrl *vol, int tries)
1940{
1941        char cmd[5];
1942        cmd[0] = 0xae;
1943        cmd[1] = vol->channel0;
1944        cmd[2] = 0;
1945        cmd[3] = vol->channel1;
1946        cmd[4] = 0;
1947
1948        return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
1949}
1950
1951MODULE_LICENSE("GPL");
1952MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_X_CDROM_MAJOR);
1953
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.