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

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