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

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