root/drivers/block/mcd.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mcd_setup
  2. check_mcd_change
  3. statusCmd
  4. mcdPlay
  5. msf2hsg
  6. mcd_ioctl
  7. mcd_transfer
  8. mcd_interrupt
  9. do_mcd_request
  10. mcd_poll
  11. mcd_invalidate_buffers
  12. mcd_open
  13. mcd_release
  14. mcd_init
  15. hsg2msf
  16. bin2bcd
  17. bcd2bin
  18. mcdStatus
  19. sendMcdCmd
  20. mcdStatTimer
  21. getMcdStatus
  22. getValue
  23. GetQChannelInfo
  24. updateToc
  25. GetDiskInfo
  26. GetToc
  27. cleanup_module

   1 /*
   2         linux/kernel/blk_drv/mcd.c - Mitsumi CDROM driver
   3 
   4         Copyright (C) 1992  Martin Harriss
   5 
   6         martin@bdsi.com (no longer valid - where are you now, Martin?)
   7 
   8         This program is free software; you can redistribute it and/or modify
   9         it under the terms of the GNU General Public License as published by
  10         the Free Software Foundation; either version 2, or (at your option)
  11         any later version.
  12 
  13         This program is distributed in the hope that it will be useful,
  14         but WITHOUT ANY WARRANTY; without even the implied warranty of
  15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16         GNU General Public License for more details.
  17 
  18         You should have received a copy of the GNU General Public License
  19         along with this program; if not, write to the Free Software
  20         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21 
  22         HISTORY
  23 
  24         0.1     First attempt - internal use only
  25         0.2     Cleaned up delays and use of timer - alpha release
  26         0.3     Audio support added
  27         0.3.1 Changes for mitsumi CRMC LU005S march version
  28                    (stud11@cc4.kuleuven.ac.be)
  29         0.3.2 bug fixes to the ioctls and merged with ALPHA0.99-pl12
  30                    (Jon Tombs <jon@robots.ox.ac.uk>)
  31         0.3.3 Added more #defines and mcd_setup()
  32                    (Jon Tombs <jon@gtex02.us.es>)
  33 
  34         October 1993 Bernd Huebner and Ruediger Helsch, Unifix Software GmbH,
  35         Braunschweig, Germany: rework to speed up data read operation.
  36         Also enabled definition of irq and address from bootstrap, using the
  37         environment.
  38         November 93 added code for FX001 S,D (single & double speed).
  39         February 94 added code for broken M 5/6 series of 16-bit single speed.
  40 
  41 
  42         0.4   
  43         Added support for loadable MODULEs, so mcd can now also be loaded by 
  44         insmod and removed by rmmod during runtime.
  45         Werner Zimmermann (zimmerma@rz.fht-esslingen.de), Mar. 26, 95
  46 
  47         0.5
  48         I added code for FX001 D to drop from double speed to single speed 
  49         when encountering errors... this helps with some "problematic" CD's
  50         that are supposedly "OUT OF TOLERANCE" (but are really shitty presses!)
  51         severly scratched, or possibly slightly warped! I have noticed that
  52         the Mitsumi 2x/4x drives are just less tolerant and the firmware is 
  53         not smart enough to drop speed, so let's just kludge it with software!
  54         ****** THE 4X SPEED MITSUMI DRIVES HAVE THE SAME PROBLEM!!!!!! ******
  55         Anyone want to "DONATE" one to me?! ;) I hear sometimes they are
  56         even WORSE! ;)
  57         ** HINT... HINT... TAKE NOTES MITSUMI This could save some hassels with
  58         certain "large" CD's that have data on the outside edge in your 
  59         DOS DRIVERS .... Accuracy counts... speed is secondary ;)
  60         17 June 95 Modifications By Andrew J. Kroll <ag784@freenet.buffalo.edu>
  61         07 July 1995 Modifications by Andrew J. Kroll
  62 
  63 */
  64 
  65 #include <linux/config.h>
  66 
  67 #ifdef MODULE
  68 # include <linux/module.h>
  69 # include <linux/version.h>
  70 # ifndef CONFIG_MODVERSIONS
  71     char kernel_version[]= UTS_RELEASE;
  72 # endif
  73 #else
  74 # define MOD_INC_USE_COUNT
  75 # define MOD_DEC_USE_COUNT
  76 #endif
  77 
  78 #include <linux/errno.h>
  79 #include <linux/signal.h>
  80 #include <linux/sched.h>
  81 #include <linux/mm.h>
  82 #include <linux/timer.h>
  83 #include <linux/fs.h>
  84 #include <linux/kernel.h>
  85 #include <linux/cdrom.h>
  86 #include <linux/ioport.h>
  87 #include <linux/string.h>
  88 #include <linux/delay.h>
  89 
  90 /* #define REALLY_SLOW_IO  */
  91 #include <asm/system.h>
  92 #include <asm/io.h>
  93 #include <asm/segment.h>
  94 
  95 #define MAJOR_NR MITSUMI_CDROM_MAJOR
  96 #include "blk.h"
  97 #define mcd_port mcd    /* for compatible parameter passing with "insmod" */
  98 #include <linux/mcd.h>
  99 
 100 #if 0
 101 static int mcd_sizes[] = { 0 };
 102 #endif
 103 
 104 /* I know putting defines in this file is probably stupid, but it should be */
 105 /* the only place that they are really needed... I HOPE! :) */
 106 
 107 /* How many sectors to read at 1x when an error at 2x speed occurs. */
 108 /* You can change this to anything from 2 to 32767, but 30 seems to */
 109 /* work best for me.  I have found that when the drive has problems */
 110 /* reading one sector, it will have troubles reading the next few.  */
 111 #define SINGLE_HOLD_SECTORS 30  
 112 
 113 #define MCMD_2X_READ 0xC1       /* Double Speed Read DON'T TOUCH! */
 114 
 115 /* I added A flag to drop to 1x speed if too many errors 0 = 1X ; 1 = 2X */
 116 static int mcdDouble = 0; 
 117 
 118 /* How many sectors to hold at 1x speed counter */
 119 static int mcd1xhold = 0;
 120 
 121 /* Is the drive connected properly and responding?? */
 122 static int mcdPresent = 0;
 123 
 124 #if 0
 125 #define TEST1 /* <int-..> */
 126 #define TEST2 /* do_mcd_req */
 127 #define TEST3 */ /* MCD_S_state */
 128 #define TEST4 /* QUICK_LOOP-counter */
 129 #define TEST5 */ /* port(1) state */
 130 #endif
 131 
 132 #if 1
 133 #define QUICK_LOOP_DELAY udelay(45)  /* use udelay */
 134 #define QUICK_LOOP_COUNT 20
 135 #else
 136 #define QUICK_LOOP_DELAY
 137 #define QUICK_LOOP_COUNT 140 /* better wait constant time */
 138 #endif
 139 /* #define DOUBLE_QUICK_ONLY */
 140 
 141 #define CURRENT_VALID \
 142   (CURRENT && MAJOR(CURRENT -> dev) == MAJOR_NR && CURRENT -> cmd == READ \
 143    && CURRENT -> sector != -1)
 144 #define MFL_STATUSorDATA (MFL_STATUS | MFL_DATA)
 145 #define MCD_BUF_SIZ 16
 146 static volatile int mcd_transfer_is_active;
 147 static char mcd_buf[2048*MCD_BUF_SIZ];  /* buffer for block size conversion */
 148 static volatile int mcd_buf_bn[MCD_BUF_SIZ], mcd_next_bn;
 149 static volatile int mcd_buf_in, mcd_buf_out = -1;
 150 static volatile int mcd_error;
 151 static int mcd_open_count;
 152 enum mcd_state_e {
 153   MCD_S_IDLE,   /* 0 */
 154   MCD_S_START,  /* 1 */
 155   MCD_S_MODE, /* 2 */
 156   MCD_S_READ,   /* 3 */
 157   MCD_S_DATA,   /* 4 */
 158   MCD_S_STOP,   /* 5 */
 159   MCD_S_STOPPING /* 6 */
 160 };
 161 static volatile enum mcd_state_e mcd_state = MCD_S_IDLE;
 162 static int mcd_mode = -1;
 163 static int MCMD_DATA_READ= MCMD_PLAY_READ;
 164 #define READ_TIMEOUT 3000
 165 #define WORK_AROUND_MITSUMI_BUG_92
 166 #define WORK_AROUND_MITSUMI_BUG_93
 167 #ifdef WORK_AROUND_MITSUMI_BUG_93
 168 int mitsumi_bug_93_wait = 0;
 169 #endif /* WORK_AROUND_MITSUMI_BUG_93 */
 170 
 171 static short mcd_port = MCD_BASE_ADDR; /* used as "mcd" by "insmod" */
 172 static int   mcd_irq  = MCD_INTR_NR; /* must directly follow mcd_port */
 173 
 174 static int McdTimeout, McdTries;
 175 static struct wait_queue *mcd_waitq = NULL;
 176 
 177 static struct mcd_DiskInfo DiskInfo;
 178 static struct mcd_Toc Toc[MAX_TRACKS];
 179 static struct mcd_Play_msf mcd_Play;
 180 
 181 static int audioStatus;
 182 static char mcdDiskChanged;
 183 static char tocUpToDate;
 184 static char mcdVersion;
 185 
 186 static void mcd_transfer(void);
 187 static void mcd_poll(void);
 188 static void mcd_invalidate_buffers(void);
 189 static void hsg2msf(long hsg, struct msf *msf);
 190 static void bin2bcd(unsigned char *p);
 191 static int bcd2bin(unsigned char bcd);
 192 static int mcdStatus(void);
 193 static void sendMcdCmd(int cmd, struct mcd_Play_msf *params);
 194 static int getMcdStatus(int timeout);
 195 static int GetQChannelInfo(struct mcd_Toc *qp);
 196 static int updateToc(void);
 197 static int GetDiskInfo(void);
 198 static int GetToc(void);
 199 static int getValue(unsigned char *result);
 200 
 201 
 202 void mcd_setup(char *str, int *ints)
     /* [previous][next][first][last][top][bottom][index][help] */
 203 {
 204    if (ints[0] > 0)
 205       mcd_port = ints[1];
 206    if (ints[0] > 1)      
 207       mcd_irq  = ints[2];
 208 #ifdef WORK_AROUND_MITSUMI_BUG_93
 209    if (ints[0] > 2)
 210       mitsumi_bug_93_wait = ints[3];
 211 #endif /* WORK_AROUND_MITSUMI_BUG_93 */
 212 }
 213 
 214  
 215 static int
 216 check_mcd_change(dev_t full_dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 217 {
 218    int retval, target;
 219 
 220 
 221 #if 1    /* the below is not reliable */
 222    return 0;
 223 #endif  
 224    target = MINOR(full_dev);
 225 
 226    if (target > 0) {
 227       printk("mcd: Mitsumi CD-ROM request error: invalid device.\n");
 228       return 0;
 229    }
 230 
 231    retval = mcdDiskChanged;
 232    mcdDiskChanged = 0;
 233 
 234    return retval;
 235 }
 236 
 237 
 238 /*
 239  * Do a 'get status' command and get the result.  Only use from the top half
 240  * because it calls 'getMcdStatus' which sleeps.
 241  */
 242 
 243 static int
 244 statusCmd(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 245 {
 246         int st, retry;
 247 
 248         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
 249         {
 250 
 251                 outb(MCMD_GET_STATUS, MCDPORT(0));      /* send get-status cmd */
 252                 st = getMcdStatus(MCD_STATUS_DELAY);
 253                 if (st != -1)
 254                         break;
 255         }
 256 
 257         return st;
 258 }
 259 
 260 
 261 /*
 262  * Send a 'Play' command and get the status.  Use only from the top half.
 263  */
 264 
 265 static int
 266 mcdPlay(struct mcd_Play_msf *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 267 {
 268         int retry, st;
 269 
 270         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
 271         {
 272                 sendMcdCmd(MCMD_PLAY_READ, arg);
 273                 st = getMcdStatus(2 * MCD_STATUS_DELAY);
 274                 if (st != -1)
 275                         break;
 276         }
 277 
 278         return st;
 279 }
 280 
 281 
 282 long
 283 msf2hsg(struct msf *mp)
     /* [previous][next][first][last][top][bottom][index][help] */
 284 {
 285         return bcd2bin(mp -> frame)
 286                 + bcd2bin(mp -> sec) * 75
 287                 + bcd2bin(mp -> min) * 4500
 288                 - 150;
 289 }
 290 
 291 
 292 static int
 293 mcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
     /* [previous][next][first][last][top][bottom][index][help] */
 294                                                 unsigned long arg)
 295 {
 296         int i, st;
 297         struct mcd_Toc qInfo;
 298         struct cdrom_ti ti;
 299         struct cdrom_tochdr tocHdr;
 300         struct cdrom_msf msf;
 301         struct cdrom_tocentry entry;
 302         struct mcd_Toc *tocPtr;
 303         struct cdrom_subchnl subchnl;
 304         struct cdrom_volctrl volctrl;
 305 
 306         if (!ip)
 307                 return -EINVAL;
 308 
 309         st = statusCmd();
 310         if (st < 0)
 311                 return -EIO;
 312 
 313         if (!tocUpToDate)
 314         {
 315                 i = updateToc();
 316                 if (i < 0)
 317                         return i;       /* error reading TOC */
 318         }
 319 
 320         switch (cmd)
 321         {
 322         case CDROMSTART:     /* Spin up the drive */
 323                 /* Don't think we can do this.  Even if we could,
 324                  * I think the drive times out and stops after a while
 325                  * anyway.  For now, ignore it.
 326                  */
 327 
 328                 return 0;
 329 
 330         case CDROMSTOP:      /* Spin down the drive */
 331                 outb(MCMD_STOP, MCDPORT(0));
 332                 i = getMcdStatus(MCD_STATUS_DELAY);
 333 
 334                 /* should we do anything if it fails? */
 335 
 336                 audioStatus = CDROM_AUDIO_NO_STATUS;
 337                 return 0;
 338 
 339         case CDROMPAUSE:     /* Pause the drive */
 340                 if (audioStatus != CDROM_AUDIO_PLAY)
 341                         return -EINVAL;
 342 
 343                 outb(MCMD_STOP, MCDPORT(0));
 344                 i = getMcdStatus(MCD_STATUS_DELAY);
 345 
 346                 if (GetQChannelInfo(&qInfo) < 0)
 347                 {
 348                         /* didn't get q channel info */
 349 
 350                         audioStatus = CDROM_AUDIO_NO_STATUS;
 351                         return 0;
 352                 }
 353 
 354                 mcd_Play.start = qInfo.diskTime;        /* remember restart point */
 355 
 356                 audioStatus = CDROM_AUDIO_PAUSED;
 357                 return 0;
 358 
 359         case CDROMRESUME:    /* Play it again, Sam */
 360                 if (audioStatus != CDROM_AUDIO_PAUSED)
 361                         return -EINVAL;
 362 
 363                 /* restart the drive at the saved position. */
 364 
 365                 i = mcdPlay(&mcd_Play);
 366                 if (i < 0)
 367                 {
 368                         audioStatus = CDROM_AUDIO_ERROR;
 369                         return -EIO;
 370                 }
 371 
 372                 audioStatus = CDROM_AUDIO_PLAY;
 373                 return 0;
 374 
 375         case CDROMPLAYTRKIND:     /* Play a track.  This currently ignores index. */
 376 
 377                 st = verify_area(VERIFY_READ, (void *) arg, sizeof ti);
 378                 if (st)
 379                         return st;
 380 
 381                 memcpy_fromfs(&ti, (void *) arg, sizeof ti);
 382 
 383                 if (ti.cdti_trk0 < DiskInfo.first
 384                         || ti.cdti_trk0 > DiskInfo.last
 385                         || ti.cdti_trk1 < ti.cdti_trk0)
 386                 {
 387                         return -EINVAL;
 388                 }
 389 
 390                 if (ti.cdti_trk1 > DiskInfo.last)
 391                         ti. cdti_trk1 = DiskInfo.last;
 392 
 393                 mcd_Play.start = Toc[ti.cdti_trk0].diskTime;
 394                 mcd_Play.end = Toc[ti.cdti_trk1 + 1].diskTime;
 395 
 396 #ifdef MCD_DEBUG
 397 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
 398         mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
 399         mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
 400 #endif
 401 
 402                 i = mcdPlay(&mcd_Play);
 403                 if (i < 0)
 404                 {
 405                         audioStatus = CDROM_AUDIO_ERROR;
 406                         return -EIO;
 407                 }
 408 
 409                 audioStatus = CDROM_AUDIO_PLAY;
 410                 return 0;
 411 
 412         case CDROMPLAYMSF:   /* Play starting at the given MSF address. */
 413 
 414                 if (audioStatus == CDROM_AUDIO_PLAY) {
 415                   outb(MCMD_STOP, MCDPORT(0));
 416                   i = getMcdStatus(MCD_STATUS_DELAY);
 417                   audioStatus = CDROM_AUDIO_NO_STATUS;
 418                 }
 419 
 420                 st = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
 421                 if (st)
 422                         return st;
 423 
 424                 memcpy_fromfs(&msf, (void *) arg, sizeof msf);
 425 
 426                 /* convert to bcd */
 427 
 428                 bin2bcd(&msf.cdmsf_min0);
 429                 bin2bcd(&msf.cdmsf_sec0);
 430                 bin2bcd(&msf.cdmsf_frame0);
 431                 bin2bcd(&msf.cdmsf_min1);
 432                 bin2bcd(&msf.cdmsf_sec1);
 433                 bin2bcd(&msf.cdmsf_frame1);
 434 
 435                 mcd_Play.start.min = msf.cdmsf_min0;
 436                 mcd_Play.start.sec = msf.cdmsf_sec0;
 437                 mcd_Play.start.frame = msf.cdmsf_frame0;
 438                 mcd_Play.end.min = msf.cdmsf_min1;
 439                 mcd_Play.end.sec = msf.cdmsf_sec1;
 440                 mcd_Play.end.frame = msf.cdmsf_frame1;
 441 
 442 #ifdef MCD_DEBUG
 443 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
 444 mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
 445 mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
 446 #endif
 447 
 448                 i = mcdPlay(&mcd_Play);
 449                 if (i < 0)
 450                 {
 451                         audioStatus = CDROM_AUDIO_ERROR;
 452                         return -EIO;
 453                 }
 454 
 455                 audioStatus = CDROM_AUDIO_PLAY;
 456                 return 0;
 457 
 458         case CDROMREADTOCHDR:        /* Read the table of contents header */
 459                 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof tocHdr);
 460                 if (st)
 461                         return st;
 462 
 463                 tocHdr.cdth_trk0 = DiskInfo.first;
 464                 tocHdr.cdth_trk1 = DiskInfo.last;
 465                 memcpy_tofs((void *) arg, &tocHdr, sizeof tocHdr);
 466                 return 0;
 467 
 468         case CDROMREADTOCENTRY:      /* Read an entry in the table of contents */
 469 
 470                 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
 471                 if (st)
 472                         return st;
 473 
 474                 memcpy_fromfs(&entry, (void *) arg, sizeof entry);
 475                 if (entry.cdte_track == CDROM_LEADOUT)
 476                         /* XXX */
 477                         tocPtr = &Toc[DiskInfo.last + 1];
 478 
 479                 else if (entry.cdte_track > DiskInfo.last
 480                                 || entry.cdte_track < DiskInfo.first)
 481                         return -EINVAL;
 482 
 483                 else
 484                         tocPtr = &Toc[entry.cdte_track];
 485 
 486                 entry.cdte_adr = tocPtr -> ctrl_addr;
 487                 entry.cdte_ctrl = tocPtr -> ctrl_addr >> 4;
 488 
 489                 if (entry.cdte_format == CDROM_LBA)
 490                         entry.cdte_addr.lba = msf2hsg(&tocPtr -> diskTime);
 491 
 492                 else if (entry.cdte_format == CDROM_MSF)
 493                 {
 494                         entry.cdte_addr.msf.minute = bcd2bin(tocPtr -> diskTime.min);
 495                         entry.cdte_addr.msf.second = bcd2bin(tocPtr -> diskTime.sec);
 496                         entry.cdte_addr.msf.frame = bcd2bin(tocPtr -> diskTime.frame);
 497                 }
 498 
 499                 else
 500                         return -EINVAL;
 501 
 502                 memcpy_tofs((void *) arg, &entry, sizeof entry);
 503                 return 0;
 504 
 505         case CDROMSUBCHNL:   /* Get subchannel info */
 506 
 507                 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl);
 508                 if (st)
 509                         return st;
 510 
 511                 memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl);
 512 
 513                 if (GetQChannelInfo(&qInfo) < 0)
 514                         return -EIO;
 515 
 516                 subchnl.cdsc_audiostatus = audioStatus;
 517                 subchnl.cdsc_adr = qInfo.ctrl_addr;
 518                 subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4;
 519                 subchnl.cdsc_trk = bcd2bin(qInfo.track);
 520                 subchnl.cdsc_ind = bcd2bin(qInfo.pointIndex);
 521 
 522                 if (subchnl.cdsc_format == CDROM_LBA)
 523                 {
 524                         subchnl.cdsc_absaddr.lba = msf2hsg(&qInfo.diskTime);
 525                         subchnl.cdsc_reladdr.lba = msf2hsg(&qInfo.trackTime);
 526                 }
 527 
 528                 else if (subchnl.cdsc_format == CDROM_MSF)
 529                 {
 530                         subchnl.cdsc_absaddr.msf.minute = bcd2bin(qInfo.diskTime.min);
 531                         subchnl.cdsc_absaddr.msf.second = bcd2bin(qInfo.diskTime.sec);
 532                         subchnl.cdsc_absaddr.msf.frame = bcd2bin(qInfo.diskTime.frame);
 533 
 534                         subchnl.cdsc_reladdr.msf.minute = bcd2bin(qInfo.trackTime.min);
 535                         subchnl.cdsc_reladdr.msf.second = bcd2bin(qInfo.trackTime.sec);
 536                         subchnl.cdsc_reladdr.msf.frame = bcd2bin(qInfo.trackTime.frame);
 537                 }
 538 
 539                 else
 540                         return -EINVAL;
 541 
 542                 memcpy_tofs((void *) arg, &subchnl, sizeof subchnl);
 543                 return 0;
 544 
 545         case CDROMVOLCTRL:   /* Volume control */
 546                 st = verify_area(VERIFY_READ, (void *) arg, sizeof(volctrl));
 547                 if (st)
 548                         return st;
 549 
 550                 memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
 551                 outb(MCMD_SET_VOLUME, MCDPORT(0));
 552                 outb(volctrl.channel0, MCDPORT(0));
 553                 outb(255, MCDPORT(0));
 554                 outb(volctrl.channel1, MCDPORT(0));
 555                 outb(255, MCDPORT(0));
 556 
 557                 i = getMcdStatus(MCD_STATUS_DELAY);
 558                 if (i < 0)
 559                         return -EIO;
 560 
 561                 {
 562                         char a, b, c, d;
 563 
 564                         getValue(&a);
 565                         getValue(&b);
 566                         getValue(&c);
 567                         getValue(&d);
 568                 }
 569 
 570                 return 0;
 571 
 572         case CDROMEJECT:
 573                /* all drives can at least stop! */
 574                 if (audioStatus == CDROM_AUDIO_PLAY) {
 575                   outb(MCMD_STOP, MCDPORT(0));
 576                   i = getMcdStatus(MCD_STATUS_DELAY);
 577                 }
 578  
 579                 audioStatus = CDROM_AUDIO_NO_STATUS;
 580  
 581                 outb(MCMD_EJECT, MCDPORT(0));
 582                 /*
 583                  * the status (i) shows failure on all but the FX drives.
 584                  * But nothing we can do about that in software!
 585                  * So just read the status and forget it. - Jon.
 586                  */
 587                 i = getMcdStatus(MCD_STATUS_DELAY);
 588                 return 0;
 589         default:
 590                 return -EINVAL;
 591         }
 592 }
 593 
 594 
 595 /*
 596  * Take care of the different block sizes between cdrom and Linux.
 597  * When Linux gets variable block sizes this will probably go away.
 598  */
 599 
 600 static void
 601 mcd_transfer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 602 {
 603   if (CURRENT_VALID) {
 604     while (CURRENT -> nr_sectors) {
 605       int bn = CURRENT -> sector / 4;
 606       int i;
 607       for (i = 0; i < MCD_BUF_SIZ && mcd_buf_bn[i] != bn; ++i)
 608         ;
 609       if (i < MCD_BUF_SIZ) {
 610         int offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
 611         int nr_sectors = 4 - (CURRENT -> sector & 3);
 612         if (mcd_buf_out != i) {
 613           mcd_buf_out = i;
 614           if (mcd_buf_bn[i] != bn) {
 615             mcd_buf_out = -1;
 616             continue;
 617           }
 618         }
 619         if (nr_sectors > CURRENT -> nr_sectors)
 620           nr_sectors = CURRENT -> nr_sectors;
 621         memcpy(CURRENT -> buffer, mcd_buf + offs, nr_sectors * 512);
 622         CURRENT -> nr_sectors -= nr_sectors;
 623         CURRENT -> sector += nr_sectors;
 624         CURRENT -> buffer += nr_sectors * 512;
 625       } else {
 626         mcd_buf_out = -1;
 627         break;
 628       }
 629     }
 630   }
 631 }
 632 
 633 
 634 /*
 635  * We only seem to get interrupts after an error.
 636  * Just take the interrupt and clear out the status reg.
 637  */
 638 
 639 static void
 640 mcd_interrupt(int irq, struct pt_regs * regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 641 {
 642         int st;
 643 
 644         st = inb(MCDPORT(1)) & 0xFF;
 645 #ifdef TEST1
 646                 printk("<int1-%02X>", st);
 647 #endif
 648         if (!(st & MFL_STATUS))
 649         {
 650                 st = inb(MCDPORT(0)) & 0xFF;
 651 #ifdef TEST1
 652                 printk("<int0-%02X>", st);
 653 #endif
 654                 if ((st & 0xFF) != 0xFF)
 655                   mcd_error = st ? st & 0xFF : -1;
 656         }
 657 }
 658 
 659 
 660 static void
 661 do_mcd_request(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 662 {
 663 #ifdef TEST2
 664   printk(" do_mcd_request(%ld+%ld)\n", CURRENT -> sector, CURRENT -> nr_sectors);
 665 #endif
 666   mcd_transfer_is_active = 1;
 667   while (CURRENT_VALID) {
 668     if (CURRENT->bh) {
 669       if (!CURRENT->bh->b_lock)
 670         panic(DEVICE_NAME ": block not locked");
 671     }
 672     mcd_transfer();
 673     if (CURRENT -> nr_sectors == 0) {
 674       end_request(1);
 675     } else {
 676       mcd_buf_out = -1;         /* Want to read a block not in buffer */
 677       if (mcd_state == MCD_S_IDLE) {
 678         if (!tocUpToDate) {
 679           if (updateToc() < 0) {
 680             while (CURRENT_VALID)
 681               end_request(0);
 682             break;
 683           }
 684         }
 685         mcd_state = MCD_S_START;
 686         McdTries = 5;
 687         SET_TIMER(mcd_poll, 1);
 688       }
 689       break;
 690     }
 691   }
 692   mcd_transfer_is_active = 0;
 693 #ifdef TEST2
 694   printk(" do_mcd_request ends\n");
 695 #endif
 696 }
 697 
 698 
 699 
 700 static void
 701 mcd_poll(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 702 {
 703   int st;
 704 
 705 
 706   if (mcd_error) 
 707   {
 708     if (mcd_error & 0xA5) 
 709     {
 710       printk("mcd: I/O error 0x%02x", mcd_error);
 711       if (mcd_error & 0x80)
 712         printk(" (Door open)");
 713       if (mcd_error & 0x20)
 714         printk(" (Disk changed)");
 715       if (mcd_error & 0x04)
 716         {
 717         printk(" (Read error)"); /* Bitch about the problem. */
 718         
 719         /* Time to get fancy! If at 2x speed and 1 error, drop to 1x speed! */
 720         /* Interesting how it STAYS at MCD_RETRY_ATTEMPTS on first error! */
 721         /* But I find that rather HANDY!!! */
 722         /* Neat! it REALLY WORKS on those LOW QUALITY CD's!!! Smile! :) */
 723         /* AJK [06/17/95] */
 724         
 725         /* Slap the CD down to single speed! */
 726         if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS && MCMD_DATA_READ == MCMD_2X_READ) 
 727                 {
 728                 MCMD_DATA_READ = MCMD_PLAY_READ; /* Uhhh, Ummmm, muhuh-huh! */
 729                 mcd1xhold = SINGLE_HOLD_SECTORS; /* Hey Bevis! */
 730                 printk(" Speed now 1x");         /* Pull my finger! */
 731                 }
 732         }
 733       printk("\n");
 734       mcd_invalidate_buffers();
 735 #ifdef WARN_IF_READ_FAILURE
 736       if (McdTries == MCD_RETRY_ATTEMPTS)
 737         printk("mcd: read of block %d failed\n", mcd_next_bn);
 738 #endif
 739       if (!McdTries--) 
 740         {
 741         /* Nuts! This cd is ready for recycling! */
 742         /* When WAS the last time YOU cleaned it CORRECTLY?! */
 743         printk("mcd: read of block %d failed, giving up\n", mcd_next_bn);
 744         if (mcd_transfer_is_active) 
 745         {
 746           McdTries = 0;
 747           goto ret;
 748         }
 749         if (CURRENT_VALID)
 750           end_request(0);
 751         McdTries = MCD_RETRY_ATTEMPTS;
 752       }
 753     }
 754     mcd_error = 0;
 755     mcd_state = MCD_S_STOP;
 756   }
 757         /* Switch back to Double speed if enough GOOD sectors were read! */
 758         
 759         /* Are we a double speed with a crappy CD?! */
 760     if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS && MCMD_DATA_READ == MCMD_PLAY_READ)
 761         {
 762         /* We ARE a double speed and we ARE bitching! */
 763         if (mcd1xhold == 0) /* Okay, Like are we STILL at single speed? */
 764                 { /* We need to switch back to double speed now... */
 765                 MCMD_DATA_READ = MCMD_2X_READ; /* Uhhh... BACK You GO! */
 766                 printk("mcd: Switching back to 2X speed!\n"); /* Tell 'em! */
 767                 }
 768         else mcd1xhold--; /* No?! Count down the good reads some more... */
 769                                 /* and try, try again! */
 770         }
 771 
 772 
 773 
 774  immediately:
 775   switch (mcd_state) {
 776 
 777 
 778 
 779   case MCD_S_IDLE:
 780 #ifdef TEST3
 781     printk("MCD_S_IDLE\n");
 782 #endif
 783     return;
 784 
 785 
 786 
 787   case MCD_S_START:
 788 #ifdef TEST3
 789     printk("MCD_S_START\n");
 790 #endif
 791 
 792     outb(MCMD_GET_STATUS, MCDPORT(0));
 793     mcd_state = mcd_mode == 1 ? MCD_S_READ : MCD_S_MODE;
 794     McdTimeout = 3000;
 795     break;
 796 
 797 
 798 
 799   case MCD_S_MODE:
 800 #ifdef TEST3
 801     printk("MCD_S_MODE\n");
 802 #endif
 803 
 804     if ((st = mcdStatus()) != -1) {
 805 
 806       if (st & MST_DSK_CHG) {
 807         mcdDiskChanged = 1;
 808         tocUpToDate = 0;
 809         mcd_invalidate_buffers();
 810       }
 811 
 812     set_mode_immediately:
 813 
 814       if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
 815         mcdDiskChanged = 1;
 816         tocUpToDate = 0;
 817         if (mcd_transfer_is_active) {
 818           mcd_state = MCD_S_START;
 819           goto immediately;
 820         }
 821         printk((st & MST_DOOR_OPEN) ? "mcd: door open\n" : "mcd: disk removed\n");
 822         mcd_state = MCD_S_IDLE;
 823         while (CURRENT_VALID)
 824           end_request(0);
 825         return;
 826       }
 827 
 828       outb(MCMD_SET_MODE, MCDPORT(0));
 829       outb(1, MCDPORT(0));
 830       mcd_mode = 1;
 831       mcd_state = MCD_S_READ;
 832       McdTimeout = 3000;
 833 
 834     }
 835     break;
 836 
 837 
 838 
 839   case MCD_S_READ:
 840 #ifdef TEST3
 841     printk("MCD_S_READ\n");
 842 #endif
 843 
 844     if ((st = mcdStatus()) != -1) {
 845 
 846       if (st & MST_DSK_CHG) {
 847         mcdDiskChanged = 1;
 848         tocUpToDate = 0;
 849         mcd_invalidate_buffers();
 850       }
 851 
 852     read_immediately:
 853 
 854       if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
 855         mcdDiskChanged = 1;
 856         tocUpToDate = 0;
 857         if (mcd_transfer_is_active) {
 858           mcd_state = MCD_S_START;
 859           goto immediately;
 860         }
 861         printk((st & MST_DOOR_OPEN) ? "mcd: door open\n" : "mcd: disk removed\n");
 862         mcd_state = MCD_S_IDLE;
 863         while (CURRENT_VALID)
 864           end_request(0);
 865         return;
 866       }
 867 
 868       if (CURRENT_VALID) {
 869         struct mcd_Play_msf msf;
 870         mcd_next_bn = CURRENT -> sector / 4;
 871         hsg2msf(mcd_next_bn, &msf.start);
 872         msf.end.min = ~0;
 873         msf.end.sec = ~0;
 874         msf.end.frame = ~0;
 875         sendMcdCmd(MCMD_DATA_READ, &msf);
 876         mcd_state = MCD_S_DATA;
 877         McdTimeout = READ_TIMEOUT;
 878       } else {
 879         mcd_state = MCD_S_STOP;
 880         goto immediately;
 881       }
 882 
 883     }
 884     break;
 885 
 886 
 887   case MCD_S_DATA:
 888 #ifdef TEST3
 889     printk("MCD_S_DATA\n");
 890 #endif
 891 
 892     st = inb(MCDPORT(1)) & (MFL_STATUSorDATA);
 893   data_immediately:
 894 #ifdef TEST5
 895     printk("Status %02x\n",st);
 896 #endif
 897     switch (st) {
 898 
 899     case MFL_DATA:
 900 #ifdef WARN_IF_READ_FAILURE
 901       if (McdTries == 5)
 902         printk("mcd: read of block %d failed\n", mcd_next_bn);
 903 #endif
 904       if (!McdTries--) {
 905         printk("mcd: read of block %d failed, giving up\n", mcd_next_bn);
 906         if (mcd_transfer_is_active) {
 907           McdTries = 0;
 908           break;
 909         }
 910         if (CURRENT_VALID)
 911           end_request(0);
 912         McdTries = 5;
 913       }
 914       mcd_state = MCD_S_START;
 915       McdTimeout = READ_TIMEOUT;
 916       goto immediately;
 917 
 918     case MFL_STATUSorDATA:
 919       break;
 920 
 921     default:
 922       McdTries = 5;
 923       if (!CURRENT_VALID && mcd_buf_in == mcd_buf_out) {
 924         mcd_state = MCD_S_STOP;
 925         goto immediately;
 926       }
 927       mcd_buf_bn[mcd_buf_in] = -1;
 928       READ_DATA(MCDPORT(0), mcd_buf + 2048 * mcd_buf_in, 2048);
 929       mcd_buf_bn[mcd_buf_in] = mcd_next_bn++;
 930       if (mcd_buf_out == -1)
 931         mcd_buf_out = mcd_buf_in;
 932       mcd_buf_in = mcd_buf_in + 1 == MCD_BUF_SIZ ? 0 : mcd_buf_in + 1;
 933       if (!mcd_transfer_is_active) {
 934         while (CURRENT_VALID) {
 935           mcd_transfer();
 936           if (CURRENT -> nr_sectors == 0)
 937             end_request(1);
 938           else
 939             break;
 940         }
 941       }
 942 
 943       if (CURRENT_VALID
 944           && (CURRENT -> sector / 4 < mcd_next_bn || 
 945               CURRENT -> sector / 4 > mcd_next_bn + 16)) {
 946         mcd_state = MCD_S_STOP;
 947         goto immediately;
 948       }
 949       McdTimeout = READ_TIMEOUT;
 950 #ifdef DOUBLE_QUICK_ONLY
 951       if (MCMD_DATA_READ != MCMD_PLAY_READ)
 952 #endif
 953       {
 954         int count= QUICK_LOOP_COUNT;
 955         while (count--) {
 956           QUICK_LOOP_DELAY;
 957           if ((st = (inb(MCDPORT(1))) & (MFL_STATUSorDATA)) != (MFL_STATUSorDATA)) {
 958 #   ifdef TEST4
 959 /*          printk("Quickloop success at %d\n",QUICK_LOOP_COUNT-count); */
 960             printk(" %d ",QUICK_LOOP_COUNT-count);
 961 #   endif
 962             goto data_immediately;
 963           }
 964         }
 965 #   ifdef TEST4
 966 /*      printk("Quickloop ended at %d\n",QUICK_LOOP_COUNT); */
 967         printk("ended ");
 968 #   endif
 969       }
 970       break;
 971     }
 972     break;
 973 
 974 
 975 
 976   case MCD_S_STOP:
 977 #ifdef TEST3
 978     printk("MCD_S_STOP\n");
 979 #endif
 980 
 981 #ifdef WORK_AROUND_MITSUMI_BUG_93
 982     if (!mitsumi_bug_93_wait)
 983       goto do_not_work_around_mitsumi_bug_93_1;
 984 
 985     McdTimeout = mitsumi_bug_93_wait;
 986     mcd_state = 9+3+1;
 987     break;
 988 
 989   case 9+3+1:
 990     if (McdTimeout)
 991       break;
 992 
 993   do_not_work_around_mitsumi_bug_93_1:
 994 #endif /* WORK_AROUND_MITSUMI_BUG_93 */
 995 
 996     outb(MCMD_STOP, MCDPORT(0));
 997 
 998 #ifdef WORK_AROUND_MITSUMI_BUG_92
 999     if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
1000       int i = 4096;
1001       do {
1002         inb(MCDPORT(0));
1003       } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
1004       outb(MCMD_STOP, MCDPORT(0));
1005       if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
1006         i = 4096;
1007         do {
1008           inb(MCDPORT(0));
1009         } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
1010         outb(MCMD_STOP, MCDPORT(0));
1011       }
1012     }
1013 #endif /* WORK_AROUND_MITSUMI_BUG_92 */
1014 
1015     mcd_state = MCD_S_STOPPING;
1016     McdTimeout = 1000;
1017     break;
1018 
1019   case MCD_S_STOPPING:
1020 #ifdef TEST3
1021     printk("MCD_S_STOPPING\n");
1022 #endif
1023 
1024     if ((st = mcdStatus()) == -1 && McdTimeout)
1025       break;
1026 
1027     if ((st != -1) && (st & MST_DSK_CHG)) {
1028       mcdDiskChanged = 1;
1029       tocUpToDate = 0;
1030       mcd_invalidate_buffers();
1031     }
1032 
1033 #ifdef WORK_AROUND_MITSUMI_BUG_93
1034     if (!mitsumi_bug_93_wait)
1035       goto do_not_work_around_mitsumi_bug_93_2;
1036 
1037     McdTimeout = mitsumi_bug_93_wait;
1038     mcd_state = 9+3+2;
1039     break;
1040 
1041   case 9+3+2:
1042     if (McdTimeout)
1043       break;
1044 
1045     st = -1;
1046 
1047   do_not_work_around_mitsumi_bug_93_2:
1048 #endif /* WORK_AROUND_MITSUMI_BUG_93 */
1049 
1050 #ifdef TEST3
1051     printk("CURRENT_VALID %d mcd_mode %d\n",
1052            CURRENT_VALID, mcd_mode);
1053 #endif
1054 
1055     if (CURRENT_VALID) {
1056       if (st != -1) {
1057         if (mcd_mode == 1)
1058           goto read_immediately;
1059         else
1060           goto set_mode_immediately;
1061       } else {
1062         mcd_state = MCD_S_START;
1063         McdTimeout = 1;
1064       }
1065     } else {
1066       mcd_state = MCD_S_IDLE;
1067       return;
1068     }
1069     break;
1070 
1071   default:
1072     printk("mcd: invalid state %d\n", mcd_state);
1073     return;
1074   }
1075 
1076  ret:
1077   if (!McdTimeout--) {
1078     printk("mcd: timeout in state %d\n", mcd_state);
1079     mcd_state = MCD_S_STOP;
1080   }
1081 
1082   SET_TIMER(mcd_poll, 1);
1083 }
1084 
1085 
1086 
1087 static void
1088 mcd_invalidate_buffers(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1089 {
1090   int i;
1091   for (i = 0; i < MCD_BUF_SIZ; ++i)
1092     mcd_buf_bn[i] = -1;
1093   mcd_buf_out = -1;
1094 }
1095 
1096 
1097 /*
1098  * Open the device special file.  Check that a disk is in.
1099  */
1100 
1101 int
1102 mcd_open(struct inode *ip, struct file *fp)
     /* [previous][next][first][last][top][bottom][index][help] */
1103 {
1104         int st;
1105 
1106         if (mcdPresent == 0)
1107                 return -ENXIO;                  /* no hardware */
1108         
1109         if (fp->f_mode & 2)                     /* write access? */
1110                 return -EROFS;
1111 
1112         if (!mcd_open_count && mcd_state == MCD_S_IDLE) {
1113 
1114         mcd_invalidate_buffers();
1115 
1116         st = statusCmd();                       /* check drive status */
1117         if (st == -1)
1118                 return -EIO;                    /* drive doesn't respond */
1119 
1120         if ((st & MST_READY) == 0)              /* no disk in drive */
1121         {
1122                 printk("mcd: no disk in drive\n");
1123                 return -EIO;
1124         }
1125 
1126         if (updateToc() < 0)
1127                 return -EIO;
1128 
1129         }
1130         ++mcd_open_count;
1131         MOD_INC_USE_COUNT;
1132         return 0;
1133 }
1134 
1135 
1136 /*
1137  * On close, we flush all mcd blocks from the buffer cache.
1138  */
1139 
1140 static void
1141 mcd_release(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
1142 { MOD_DEC_USE_COUNT;
1143   if (!--mcd_open_count) {
1144         mcd_invalidate_buffers();
1145         sync_dev(inode->i_rdev);
1146         invalidate_buffers(inode -> i_rdev);
1147   }
1148 }
1149 
1150 
1151 static struct file_operations mcd_fops = {
1152         NULL,                   /* lseek - default */
1153         block_read,             /* read - general block-dev read */
1154         block_write,            /* write - general block-dev write */
1155         NULL,                   /* readdir - bad */
1156         NULL,                   /* select */
1157         mcd_ioctl,              /* ioctl */
1158         NULL,                   /* mmap */
1159         mcd_open,               /* open */
1160         mcd_release,            /* release */
1161         NULL,                   /* fsync */
1162         NULL,                   /* fasync */
1163         check_mcd_change,       /* media change */
1164         NULL                    /* revalidate */
1165 };
1166 
1167 
1168 /*
1169  * Test for presence of drive and initialize it.  Called at boot time.
1170  */
1171 
1172 #ifndef MODULE
1173 unsigned long
1174 mcd_init(unsigned long mem_start, unsigned long mem_end)
     /* [previous][next][first][last][top][bottom][index][help] */
1175 #else
1176 int init_module(void)
1177 #endif
1178 {
1179         int count;
1180         unsigned char result[3];
1181 
1182         if (mcd_port <= 0 || mcd_irq <= 0) {
1183           printk("skip mcd_init\n");
1184 #ifndef MODULE
1185           return mem_start;
1186 #else
1187           return -EIO;
1188 #endif
1189         }
1190 
1191         printk("mcd=0x%x,%d: ", mcd_port, mcd_irq);
1192 
1193         if (register_blkdev(MAJOR_NR, "mcd", &mcd_fops) != 0)
1194         {
1195                 printk("Unable to get major %d for Mitsumi CD-ROM\n",
1196                        MAJOR_NR);
1197 #ifndef MODULE
1198                 return mem_start;
1199 #else
1200                 return -EIO;
1201 #endif
1202               
1203         }
1204 
1205         if (check_region(mcd_port, 4)) {
1206           printk("Init failed, I/O port (%X) already in use\n",
1207                  mcd_port);
1208 #ifndef MODULE           
1209           return mem_start;
1210 #else
1211           return -EIO;
1212 #endif    
1213         }
1214           
1215         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
1216         read_ahead[MAJOR_NR] = 4;
1217 
1218         /* check for card */
1219 
1220         outb(0, MCDPORT(1));                    /* send reset */
1221         for (count = 0; count < 2000000; count++)
1222                 (void) inb(MCDPORT(1));         /* delay a bit */
1223 
1224         outb(0x40, MCDPORT(0));                 /* send get-stat cmd */
1225         for (count = 0; count < 2000000; count++)
1226                 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1227                         break;
1228 
1229         if (count >= 2000000) {
1230                 printk("Init failed. No mcd device at 0x%x irq %d\n",
1231                      mcd_port, mcd_irq);
1232 #ifndef MODULE
1233                 return mem_start;
1234 #else
1235                 return -EIO;
1236 #endif                
1237         }
1238         count = inb(MCDPORT(0));                /* pick up the status */
1239         
1240         outb(MCMD_GET_VERSION,MCDPORT(0));
1241         for(count=0;count<3;count++)
1242                 if(getValue(result+count)) {
1243                         printk("mitsumi get version failed at 0x%d\n",
1244                                mcd_port);
1245 #ifndef MODULE
1246                         return mem_start;
1247 #else
1248                         return -EIO;
1249 #endif
1250                 }       
1251 
1252         if (result[0] == result[1] && result[1] == result[2])
1253 #ifndef MODULE
1254                 return mem_start;
1255 #else
1256                 return -EIO;
1257 #endif
1258         printk("Mitsumi status, type and version : %02X %c %x ",
1259                result[0],result[1],result[2]);
1260 
1261      if (result[1] == 'D') 
1262         {
1263         printk("Double Speed CD ROM\n");
1264         MCMD_DATA_READ = MCMD_2X_READ;
1265         mcdDouble = 1; /* Added flag to drop to 1x speed if too many errors */
1266         }
1267        else printk("Single Speed CD ROM\n");
1268 
1269         mcdVersion=result[2];
1270 
1271         if (mcdVersion >=4)
1272                 outb(4,MCDPORT(2));     /* magic happens */
1273 
1274         /* don't get the IRQ until we know for sure the drive is there */
1275 
1276         if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD"))
1277         {
1278                 printk("Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
1279 #ifndef MODULE
1280                 return mem_start;
1281 #else
1282                 return -EIO;
1283 #endif
1284         }
1285         request_region(mcd_port, 4,"mcd");
1286 
1287         outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1288         outb(0x02,MCDPORT(0));
1289         outb(0x00,MCDPORT(0));
1290         getValue(result);
1291 
1292         outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1293         outb(0x10,MCDPORT(0));
1294         outb(0x04,MCDPORT(0));
1295         getValue(result);
1296 
1297         mcd_invalidate_buffers();
1298         mcdPresent = 1;
1299 #ifndef MODULE  
1300         return mem_start;
1301 #else
1302         return 0;
1303 #endif
1304 }
1305 
1306 
1307 static void
1308 hsg2msf(long hsg, struct msf *msf)
     /* [previous][next][first][last][top][bottom][index][help] */
1309 {
1310         hsg += 150;
1311         msf -> min = hsg / 4500;
1312         hsg %= 4500;
1313         msf -> sec = hsg / 75;
1314         msf -> frame = hsg % 75;
1315 
1316         bin2bcd(&msf -> min);           /* convert to BCD */
1317         bin2bcd(&msf -> sec);
1318         bin2bcd(&msf -> frame);
1319 }
1320 
1321 
1322 static void
1323 bin2bcd(unsigned char *p)
     /* [previous][next][first][last][top][bottom][index][help] */
1324 {
1325         int u, t;
1326 
1327         u = *p % 10;
1328         t = *p / 10;
1329         *p = u | (t << 4);
1330 }
1331 
1332 static int
1333 bcd2bin(unsigned char bcd)
     /* [previous][next][first][last][top][bottom][index][help] */
1334 {
1335         return (bcd >> 4) * 10 + (bcd & 0xF);
1336 }
1337 
1338 
1339 /*
1340  * See if a status is ready from the drive and return it
1341  * if it is ready.
1342  */
1343 
1344 static int
1345 mcdStatus(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1346 {
1347         int i;
1348         int st;
1349 
1350         st = inb(MCDPORT(1)) & MFL_STATUS;
1351         if (!st)
1352         {
1353                 i = inb(MCDPORT(0)) & 0xFF;
1354                 return i;
1355         }
1356         else
1357                 return -1;
1358 }
1359 
1360 
1361 /*
1362  * Send a play or read command to the drive
1363  */
1364 
1365 static void
1366 sendMcdCmd(int cmd, struct mcd_Play_msf *params)
     /* [previous][next][first][last][top][bottom][index][help] */
1367 {
1368         outb(cmd, MCDPORT(0));
1369         outb(params -> start.min, MCDPORT(0));
1370         outb(params -> start.sec, MCDPORT(0));
1371         outb(params -> start.frame, MCDPORT(0));
1372         outb(params -> end.min, MCDPORT(0));
1373         outb(params -> end.sec, MCDPORT(0));
1374         outb(params -> end.frame, MCDPORT(0));
1375 }
1376 
1377 
1378 /*
1379  * Timer interrupt routine to test for status ready from the drive.
1380  * (see the next routine)
1381  */
1382 
1383 static void
1384 mcdStatTimer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1385 {
1386         if (!(inb(MCDPORT(1)) & MFL_STATUS))
1387         {
1388                 wake_up(&mcd_waitq);
1389                 return;
1390         }
1391 
1392         McdTimeout--;
1393         if (McdTimeout <= 0)
1394         {
1395                 wake_up(&mcd_waitq);
1396                 return;
1397         }
1398 
1399         SET_TIMER(mcdStatTimer, 1);
1400 }
1401 
1402 
1403 /*
1404  * Wait for a status to be returned from the drive.  The actual test
1405  * (see routine above) is done by the timer interrupt to avoid
1406  * excessive rescheduling.
1407  */
1408 
1409 static int
1410 getMcdStatus(int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
1411 {
1412         int st;
1413 
1414         McdTimeout = timeout;
1415         SET_TIMER(mcdStatTimer, 1);
1416         sleep_on(&mcd_waitq);
1417         if (McdTimeout <= 0)
1418                 return -1;
1419 
1420         st = inb(MCDPORT(0)) & 0xFF;
1421         if (st == 0xFF)
1422                 return -1;
1423 
1424         if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
1425                 /* XXX might be an error? look at q-channel? */
1426                 audioStatus = CDROM_AUDIO_COMPLETED;
1427 
1428         if (st & MST_DSK_CHG)
1429         {
1430                 mcdDiskChanged = 1;
1431                 tocUpToDate = 0;
1432                 audioStatus = CDROM_AUDIO_NO_STATUS;
1433         }
1434 
1435         return st;
1436 }
1437 
1438 
1439 /*
1440  * Read a value from the drive.  Should return quickly, so a busy wait
1441  * is used to avoid excessive rescheduling.
1442  */
1443 
1444 static int
1445 getValue(unsigned char *result)
     /* [previous][next][first][last][top][bottom][index][help] */
1446 {
1447         int count;
1448         int s;
1449 
1450         for (count = 0; count < 2000; count++)
1451                 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1452                         break;
1453 
1454         if (count >= 2000)
1455         {
1456                 printk("mcd: getValue timeout\n");
1457                 return -1;
1458         }
1459 
1460         s = inb(MCDPORT(0)) & 0xFF;
1461         *result = (unsigned char) s;
1462         return 0;
1463 }
1464 
1465 
1466 /*
1467  * Read the current Q-channel info.  Also used for reading the
1468  * table of contents.
1469  */
1470 
1471 int
1472 GetQChannelInfo(struct mcd_Toc *qp)
     /* [previous][next][first][last][top][bottom][index][help] */
1473 {
1474         unsigned char notUsed;
1475         int retry;
1476 
1477         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1478         {
1479                 outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
1480                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1481                         break;
1482         }
1483 
1484         if (retry >= MCD_RETRY_ATTEMPTS)
1485                 return -1;
1486 
1487         if (getValue(&qp -> ctrl_addr) < 0) return -1;
1488         if (getValue(&qp -> track) < 0) return -1;
1489         if (getValue(&qp -> pointIndex) < 0) return -1;
1490         if (getValue(&qp -> trackTime.min) < 0) return -1;
1491         if (getValue(&qp -> trackTime.sec) < 0) return -1;
1492         if (getValue(&qp -> trackTime.frame) < 0) return -1;
1493         if (getValue(&notUsed) < 0) return -1;
1494         if (getValue(&qp -> diskTime.min) < 0) return -1;
1495         if (getValue(&qp -> diskTime.sec) < 0) return -1;
1496         if (getValue(&qp -> diskTime.frame) < 0) return -1;
1497 
1498         return 0;
1499 }
1500 
1501 
1502 /*
1503  * Read the table of contents (TOC) and TOC header if necessary
1504  */
1505 
1506 static int
1507 updateToc()
     /* [previous][next][first][last][top][bottom][index][help] */
1508 {
1509         if (tocUpToDate)
1510                 return 0;
1511 
1512         if (GetDiskInfo() < 0)
1513                 return -EIO;
1514 
1515         if (GetToc() < 0)
1516                 return -EIO;
1517 
1518         tocUpToDate = 1;
1519         return 0;
1520 }
1521 
1522 
1523 /*
1524  * Read the table of contents header
1525  */
1526 
1527 static int
1528 GetDiskInfo()
     /* [previous][next][first][last][top][bottom][index][help] */
1529 {
1530         int retry;
1531 
1532         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1533         {
1534                 outb(MCMD_GET_DISK_INFO, MCDPORT(0));
1535                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1536                         break;
1537         }
1538 
1539         if (retry >= MCD_RETRY_ATTEMPTS)
1540                 return -1;
1541 
1542         if (getValue(&DiskInfo.first) < 0) return -1;
1543         if (getValue(&DiskInfo.last) < 0) return -1;
1544 
1545         DiskInfo.first = bcd2bin(DiskInfo.first);
1546         DiskInfo.last = bcd2bin(DiskInfo.last);
1547 
1548         if (getValue(&DiskInfo.diskLength.min) < 0) return -1;
1549         if (getValue(&DiskInfo.diskLength.sec) < 0) return -1;
1550         if (getValue(&DiskInfo.diskLength.frame) < 0) return -1;
1551         if (getValue(&DiskInfo.firstTrack.min) < 0) return -1;
1552         if (getValue(&DiskInfo.firstTrack.sec) < 0) return -1;
1553         if (getValue(&DiskInfo.firstTrack.frame) < 0) return -1;
1554 
1555 #ifdef MCD_DEBUG
1556 printk("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",
1557         DiskInfo.first,
1558         DiskInfo.last,
1559         DiskInfo.diskLength.min,
1560         DiskInfo.diskLength.sec,
1561         DiskInfo.diskLength.frame,
1562         DiskInfo.firstTrack.min,
1563         DiskInfo.firstTrack.sec,
1564         DiskInfo.firstTrack.frame);
1565 #endif
1566 
1567         return 0;
1568 }
1569 
1570 
1571 /*
1572  * Read the table of contents (TOC)
1573  */
1574 
1575 static int
1576 GetToc()
     /* [previous][next][first][last][top][bottom][index][help] */
1577 {
1578         int i, px;
1579         int limit;
1580         int retry;
1581         struct mcd_Toc qInfo;
1582 
1583         for (i = 0; i < MAX_TRACKS; i++)
1584                 Toc[i].pointIndex = 0;
1585 
1586         i = DiskInfo.last + 3;
1587 
1588         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1589         {
1590                 outb(MCMD_STOP, MCDPORT(0));
1591                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1592                         break;
1593         }
1594 
1595         if (retry >= MCD_RETRY_ATTEMPTS)
1596                 return -1;
1597 
1598         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1599         {
1600                 outb(MCMD_SET_MODE, MCDPORT(0));
1601                 outb(0x05, MCDPORT(0));                 /* mode: toc */
1602                 mcd_mode = 0x05;
1603                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1604                         break;
1605         }
1606 
1607         if (retry >= MCD_RETRY_ATTEMPTS)
1608                 return -1;
1609 
1610         for (limit = 300; limit > 0; limit--)
1611         {
1612                 if (GetQChannelInfo(&qInfo) < 0)
1613                         break;
1614 
1615                 px = bcd2bin(qInfo.pointIndex);
1616                 if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
1617                         if (Toc[px].pointIndex == 0)
1618                         {
1619                                 Toc[px] = qInfo;
1620                                 i--;
1621                         }
1622 
1623                 if (i <= 0)
1624                         break;
1625         }
1626 
1627         Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
1628 
1629         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1630         {
1631                 outb(MCMD_SET_MODE, MCDPORT(0));
1632                 outb(0x01, MCDPORT(0));
1633                 mcd_mode = 1;
1634                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1635                         break;
1636         }
1637 
1638 #ifdef MCD_DEBUG
1639 for (i = 1; i <= DiskInfo.last; i++)
1640 printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
1641 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1642 Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
1643 Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1644 for (i = 100; i < 103; i++)
1645 printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
1646 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1647 Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
1648 Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1649 #endif
1650 
1651         return limit > 0 ? 0 : -1;
1652 }
1653 
1654 #ifdef MODULE
1655 void cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1656 { if (MOD_IN_USE)
1657      { printk("mcd module in use - can't remove it.\n");
1658        return;    
1659      }
1660   if ((unregister_blkdev(MAJOR_NR, "mcd") == -EINVAL))
1661      { printk("What's that: can't unregister mcd\n");
1662        return;    
1663      }
1664   release_region(mcd_port,4);
1665   free_irq(mcd_irq);
1666   printk("mcd module released.\n");
1667 }
1668 #endif MODULE

/* [previous][next][first][last][top][bottom][index][help] */