root/drivers/block/mcd.c

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

DEFINITIONS

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

   1 /*
   2         linux/kernel/blk_drv/mcd.c - Mitsumi CDROM driver
   3 
   4         Copyright (C) 1992  Martin Harriss
   5 
   6         martin@bdsi.com (no longer valid - where are you now, Martin?)
   7 
   8         This program is free software; you can redistribute it and/or modify
   9         it under the terms of the GNU General Public License as published by
  10         the Free Software Foundation; either version 2, or (at your option)
  11         any later version.
  12 
  13         This program is distributed in the hope that it will be useful,
  14         but WITHOUT ANY WARRANTY; without even the implied warranty of
  15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16         GNU General Public License for more details.
  17 
  18         You should have received a copy of the GNU General Public License
  19         along with this program; if not, write to the Free Software
  20         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21 
  22         HISTORY
  23 
  24         0.1     First attempt - internal use only
  25         0.2     Cleaned up delays and use of timer - alpha release
  26         0.3     Audio support added
  27         0.3.1 Changes for mitsumi CRMC LU005S march version
  28                    (stud11@cc4.kuleuven.ac.be)
  29         0.3.2 bug fixes to the ioctls and merged with ALPHA0.99-pl12
  30                    (Jon Tombs <jon@robots.ox.ac.uk>)
  31         0.3.3 Added more #defines and mcd_setup()
  32                    (Jon Tombs <jon@gtex02.us.es>)
  33 
  34         October 1993 Bernd Huebner and Ruediger Helsch, Unifix Software GmbH,
  35         Braunschweig, Germany: rework to speed up data read operation.
  36         Also enabled definition of irq and address from bootstrap, using the
  37         environment.
  38         November 93 added code for FX001 S,D (single & double speed).
  39         February 94 added code for broken M 5/6 series of 16-bit single speed.
  40 
  41 
  42         0.4   
  43         Added support for loadable MODULEs, so mcd can now also be loaded by 
  44         insmod and removed by rmmod during runtime.
  45         Werner Zimmermann (zimmerma@rz.fht-esslingen.de), Mar. 26, 95
  46 
  47         0.5
  48         I added code for FX001 D to drop from double speed to single speed 
  49         when encountering errors... this helps with some "problematic" CD's
  50         that are supposedly "OUT OF TOLERANCE" (but are really shitty presses!)
  51         severly scratched, or possibly slightly warped! I have noticed that
  52         the Mitsumi 2x/4x drives are just less tolerant and the firmware is 
  53         not smart enough to drop speed, so let's just kludge it with software!
  54         ****** THE 4X SPEED MITSUMI DRIVES HAVE THE SAME PROBLEM!!!!!! ******
  55         Anyone want to "DONATE" one to me?! ;) I hear sometimes they are
  56         even WORSE! ;)
  57         ** HINT... HINT... TAKE NOTES MITSUMI This could save some hassels with
  58         certain "large" CD's that have data on the outside edge in your 
  59         DOS DRIVERS .... Accuracy counts... speed is secondary ;)
  60         17 June 95 Modifications By Andrew J. Kroll <ag784@freenet.buffalo.edu>
  61         07 July 1995 Modifications by Andrew J. Kroll
  62 
  63 */
  64 
  65 #include <linux/config.h>
  66 
  67 #ifdef MODULE
  68 # include <linux/module.h>
  69 # include <linux/version.h>
  70 # ifndef CONFIG_MODVERSIONS
  71     char kernel_version[]= UTS_RELEASE;
  72 # endif
  73 #else
  74 # define MOD_INC_USE_COUNT
  75 # define MOD_DEC_USE_COUNT
  76 #endif
  77 
  78 #include <linux/errno.h>
  79 #include <linux/signal.h>
  80 #include <linux/sched.h>
  81 #include <linux/mm.h>
  82 #include <linux/timer.h>
  83 #include <linux/fs.h>
  84 #include <linux/kernel.h>
  85 #include <linux/cdrom.h>
  86 #include <linux/ioport.h>
  87 #include <linux/string.h>
  88 #include <linux/delay.h>
  89 
  90 /* #define REALLY_SLOW_IO  */
  91 #include <asm/system.h>
  92 #include <asm/io.h>
  93 #include <asm/segment.h>
  94 
  95 #define MAJOR_NR MITSUMI_CDROM_MAJOR
  96 #include "blk.h"
  97 #define mcd_port mcd    /* for compatible parameter passing with "insmod" */
  98 #include <linux/mcd.h>
  99 
 100 #if 0
 101 static int mcd_sizes[] = { 0 };
 102 #endif
 103 
 104 /* I know putting defines in this file is probably stupid, but it should be */
 105 /* the only place that they are really needed... I HOPE! :) */
 106 
 107 /* How many sectors to read at 1x when an error at 2x speed occurs. */
 108 /* You can change this to anything from 2 to 32767, but 30 seems to */
 109 /* work best for me.  I have found that when the drive has problems */
 110 /* reading one sector, it will have troubles reading the next few.  */
 111 #define SINGLE_HOLD_SECTORS 30  
 112 
 113 #define MCMD_2X_READ 0xC1       /* Double Speed Read DON'T TOUCH! */
 114 
 115 /* I added A flag to drop to 1x speed if too many errors 0 = 1X ; 1 = 2X */
 116 static int mcdDouble = 0; 
 117 
 118 /* How many sectors to hold at 1x speed counter */
 119 static int mcd1xhold = 0;
 120 
 121 /* Is the drive connected properly and responding?? */
 122 static int mcdPresent = 0;
 123 
 124 #if 0
 125 #define TEST1 /* <int-..> */
 126 #define TEST2 /* do_mcd_req */
 127 #define TEST3 */ /* MCD_S_state */
 128 #define TEST4 /* QUICK_LOOP-counter */
 129 #define TEST5 */ /* port(1) state */
 130 #endif
 131 
 132 #if 1
 133 #define QUICK_LOOP_DELAY udelay(45)  /* use udelay */
 134 #define QUICK_LOOP_COUNT 20
 135 #else
 136 #define QUICK_LOOP_DELAY
 137 #define QUICK_LOOP_COUNT 140 /* better wait constant time */
 138 #endif
 139 /* #define DOUBLE_QUICK_ONLY */
 140 
 141 #define CURRENT_VALID \
 142   (CURRENT && MAJOR(CURRENT -> dev) == MAJOR_NR && CURRENT -> cmd == READ \
 143    && CURRENT -> sector != -1)
 144 #define MFL_STATUSorDATA (MFL_STATUS | MFL_DATA)
 145 #define MCD_BUF_SIZ 16
 146 static volatile int mcd_transfer_is_active;
 147 static char mcd_buf[2048*MCD_BUF_SIZ];  /* buffer for block size conversion */
 148 static volatile int mcd_buf_bn[MCD_BUF_SIZ], mcd_next_bn;
 149 static volatile int mcd_buf_in, mcd_buf_out = -1;
 150 static volatile int mcd_error;
 151 static int mcd_open_count;
 152 enum mcd_state_e {
 153   MCD_S_IDLE,   /* 0 */
 154   MCD_S_START,  /* 1 */
 155   MCD_S_MODE, /* 2 */
 156   MCD_S_READ,   /* 3 */
 157   MCD_S_DATA,   /* 4 */
 158   MCD_S_STOP,   /* 5 */
 159   MCD_S_STOPPING /* 6 */
 160 };
 161 static volatile enum mcd_state_e mcd_state = MCD_S_IDLE;
 162 static int mcd_mode = -1;
 163 static int MCMD_DATA_READ= MCMD_PLAY_READ;
 164 #define READ_TIMEOUT 3000
 165 #define WORK_AROUND_MITSUMI_BUG_92
 166 #define WORK_AROUND_MITSUMI_BUG_93
 167 #ifdef WORK_AROUND_MITSUMI_BUG_93
 168 int mitsumi_bug_93_wait = 0;
 169 #endif /* WORK_AROUND_MITSUMI_BUG_93 */
 170 
 171 static short mcd_port = MCD_BASE_ADDR; /* used as "mcd" by "insmod" */
 172 static int   mcd_irq  = MCD_INTR_NR; /* must directly follow mcd_port */
 173 
 174 static int McdTimeout, McdTries;
 175 static struct wait_queue *mcd_waitq = NULL;
 176 
 177 static struct mcd_DiskInfo DiskInfo;
 178 static struct mcd_Toc Toc[MAX_TRACKS];
 179 static struct mcd_Play_msf mcd_Play;
 180 
 181 static int audioStatus;
 182 static char mcdDiskChanged;
 183 static char tocUpToDate;
 184 static char mcdVersion;
 185 
 186 static void mcd_transfer(void);
 187 static void mcd_poll(void);
 188 static void mcd_invalidate_buffers(void);
 189 static void do_mcd_request(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(dev_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 #ifndef MODULE
1174 unsigned long
1175 mcd_init(unsigned long mem_start, unsigned long mem_end)
     /* [previous][next][first][last][top][bottom][index][help] */
1176 #else
1177 int init_module(void)
1178 #endif
1179 {
1180         int count;
1181         unsigned char result[3];
1182 
1183         if (mcd_port <= 0 || mcd_irq <= 0) {
1184           printk("skip mcd_init\n");
1185 #ifndef MODULE
1186           return mem_start;
1187 #else
1188           return -EIO;
1189 #endif
1190         }
1191 
1192         printk("mcd=0x%x,%d: ", mcd_port, mcd_irq);
1193 
1194         if (register_blkdev(MAJOR_NR, "mcd", &mcd_fops) != 0)
1195         {
1196                 printk("Unable to get major %d for Mitsumi CD-ROM\n",
1197                        MAJOR_NR);
1198 #ifndef MODULE
1199                 return mem_start;
1200 #else
1201                 return -EIO;
1202 #endif
1203               
1204         }
1205 
1206         if (check_region(mcd_port, 4)) {
1207           printk("Init failed, I/O port (%X) already in use\n",
1208                  mcd_port);
1209 #ifndef MODULE           
1210           return mem_start;
1211 #else
1212           return -EIO;
1213 #endif    
1214         }
1215           
1216         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
1217         read_ahead[MAJOR_NR] = 4;
1218 
1219         /* check for card */
1220 
1221         outb(0, MCDPORT(1));                    /* send reset */
1222         for (count = 0; count < 2000000; count++)
1223                 (void) inb(MCDPORT(1));         /* delay a bit */
1224 
1225         outb(0x40, MCDPORT(0));                 /* send get-stat cmd */
1226         for (count = 0; count < 2000000; count++)
1227                 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1228                         break;
1229 
1230         if (count >= 2000000) {
1231                 printk("Init failed. No mcd device at 0x%x irq %d\n",
1232                      mcd_port, mcd_irq);
1233 #ifndef MODULE
1234                 return mem_start;
1235 #else
1236                 return -EIO;
1237 #endif                
1238         }
1239         count = inb(MCDPORT(0));                /* pick up the status */
1240         
1241         outb(MCMD_GET_VERSION,MCDPORT(0));
1242         for(count=0;count<3;count++)
1243                 if(getValue(result+count)) {
1244                         printk("mitsumi get version failed at 0x%d\n",
1245                                mcd_port);
1246 #ifndef MODULE
1247                         return mem_start;
1248 #else
1249                         return -EIO;
1250 #endif
1251                 }       
1252 
1253         if (result[0] == result[1] && result[1] == result[2])
1254 #ifndef MODULE
1255                 return mem_start;
1256 #else
1257                 return -EIO;
1258 #endif
1259         printk("Mitsumi status, type and version : %02X %c %x ",
1260                result[0],result[1],result[2]);
1261 
1262      if (result[1] == 'D') 
1263         {
1264         printk("Double Speed CD ROM\n");
1265         MCMD_DATA_READ = MCMD_2X_READ;
1266         mcdDouble = 1; /* Added flag to drop to 1x speed if too many errors */
1267         }
1268        else printk("Single Speed CD ROM\n");
1269 
1270         mcdVersion=result[2];
1271 
1272         if (mcdVersion >=4)
1273                 outb(4,MCDPORT(2));     /* magic happens */
1274 
1275         /* don't get the IRQ until we know for sure the drive is there */
1276 
1277         if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD"))
1278         {
1279                 printk("Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
1280 #ifndef MODULE
1281                 return mem_start;
1282 #else
1283                 return -EIO;
1284 #endif
1285         }
1286         request_region(mcd_port, 4,"mcd");
1287 
1288         outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1289         outb(0x02,MCDPORT(0));
1290         outb(0x00,MCDPORT(0));
1291         getValue(result);
1292 
1293         outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1294         outb(0x10,MCDPORT(0));
1295         outb(0x04,MCDPORT(0));
1296         getValue(result);
1297 
1298         mcd_invalidate_buffers();
1299         mcdPresent = 1;
1300 #ifndef MODULE  
1301         return mem_start;
1302 #else
1303         return 0;
1304 #endif
1305 }
1306 
1307 
1308 static void
1309 hsg2msf(long hsg, struct msf *msf)
     /* [previous][next][first][last][top][bottom][index][help] */
1310 {
1311         hsg += 150;
1312         msf -> min = hsg / 4500;
1313         hsg %= 4500;
1314         msf -> sec = hsg / 75;
1315         msf -> frame = hsg % 75;
1316 
1317         bin2bcd(&msf -> min);           /* convert to BCD */
1318         bin2bcd(&msf -> sec);
1319         bin2bcd(&msf -> frame);
1320 }
1321 
1322 
1323 static void
1324 bin2bcd(unsigned char *p)
     /* [previous][next][first][last][top][bottom][index][help] */
1325 {
1326         int u, t;
1327 
1328         u = *p % 10;
1329         t = *p / 10;
1330         *p = u | (t << 4);
1331 }
1332 
1333 static int
1334 bcd2bin(unsigned char bcd)
     /* [previous][next][first][last][top][bottom][index][help] */
1335 {
1336         return (bcd >> 4) * 10 + (bcd & 0xF);
1337 }
1338 
1339 
1340 /*
1341  * See if a status is ready from the drive and return it
1342  * if it is ready.
1343  */
1344 
1345 static int
1346 mcdStatus(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1347 {
1348         int i;
1349         int st;
1350 
1351         st = inb(MCDPORT(1)) & MFL_STATUS;
1352         if (!st)
1353         {
1354                 i = inb(MCDPORT(0)) & 0xFF;
1355                 return i;
1356         }
1357         else
1358                 return -1;
1359 }
1360 
1361 
1362 /*
1363  * Send a play or read command to the drive
1364  */
1365 
1366 static void
1367 sendMcdCmd(int cmd, struct mcd_Play_msf *params)
     /* [previous][next][first][last][top][bottom][index][help] */
1368 {
1369         outb(cmd, MCDPORT(0));
1370         outb(params -> start.min, MCDPORT(0));
1371         outb(params -> start.sec, MCDPORT(0));
1372         outb(params -> start.frame, MCDPORT(0));
1373         outb(params -> end.min, MCDPORT(0));
1374         outb(params -> end.sec, MCDPORT(0));
1375         outb(params -> end.frame, MCDPORT(0));
1376 }
1377 
1378 
1379 /*
1380  * Timer interrupt routine to test for status ready from the drive.
1381  * (see the next routine)
1382  */
1383 
1384 static void
1385 mcdStatTimer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1386 {
1387         if (!(inb(MCDPORT(1)) & MFL_STATUS))
1388         {
1389                 wake_up(&mcd_waitq);
1390                 return;
1391         }
1392 
1393         McdTimeout--;
1394         if (McdTimeout <= 0)
1395         {
1396                 wake_up(&mcd_waitq);
1397                 return;
1398         }
1399 
1400         SET_TIMER(mcdStatTimer, 1);
1401 }
1402 
1403 
1404 /*
1405  * Wait for a status to be returned from the drive.  The actual test
1406  * (see routine above) is done by the timer interrupt to avoid
1407  * excessive rescheduling.
1408  */
1409 
1410 static int
1411 getMcdStatus(int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
1412 {
1413         int st;
1414 
1415         McdTimeout = timeout;
1416         SET_TIMER(mcdStatTimer, 1);
1417         sleep_on(&mcd_waitq);
1418         if (McdTimeout <= 0)
1419                 return -1;
1420 
1421         st = inb(MCDPORT(0)) & 0xFF;
1422         if (st == 0xFF)
1423                 return -1;
1424 
1425         if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
1426                 /* XXX might be an error? look at q-channel? */
1427                 audioStatus = CDROM_AUDIO_COMPLETED;
1428 
1429         if (st & MST_DSK_CHG)
1430         {
1431                 mcdDiskChanged = 1;
1432                 tocUpToDate = 0;
1433                 audioStatus = CDROM_AUDIO_NO_STATUS;
1434         }
1435 
1436         return st;
1437 }
1438 
1439 
1440 /*
1441  * Read a value from the drive.  Should return quickly, so a busy wait
1442  * is used to avoid excessive rescheduling.
1443  */
1444 
1445 static int
1446 getValue(unsigned char *result)
     /* [previous][next][first][last][top][bottom][index][help] */
1447 {
1448         int count;
1449         int s;
1450 
1451         for (count = 0; count < 2000; count++)
1452                 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1453                         break;
1454 
1455         if (count >= 2000)
1456         {
1457                 printk("mcd: getValue timeout\n");
1458                 return -1;
1459         }
1460 
1461         s = inb(MCDPORT(0)) & 0xFF;
1462         *result = (unsigned char) s;
1463         return 0;
1464 }
1465 
1466 
1467 /*
1468  * Read the current Q-channel info.  Also used for reading the
1469  * table of contents.
1470  */
1471 
1472 int
1473 GetQChannelInfo(struct mcd_Toc *qp)
     /* [previous][next][first][last][top][bottom][index][help] */
1474 {
1475         unsigned char notUsed;
1476         int retry;
1477 
1478         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1479         {
1480                 outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
1481                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1482                         break;
1483         }
1484 
1485         if (retry >= MCD_RETRY_ATTEMPTS)
1486                 return -1;
1487 
1488         if (getValue(&qp -> ctrl_addr) < 0) return -1;
1489         if (getValue(&qp -> track) < 0) return -1;
1490         if (getValue(&qp -> pointIndex) < 0) return -1;
1491         if (getValue(&qp -> trackTime.min) < 0) return -1;
1492         if (getValue(&qp -> trackTime.sec) < 0) return -1;
1493         if (getValue(&qp -> trackTime.frame) < 0) return -1;
1494         if (getValue(&notUsed) < 0) return -1;
1495         if (getValue(&qp -> diskTime.min) < 0) return -1;
1496         if (getValue(&qp -> diskTime.sec) < 0) return -1;
1497         if (getValue(&qp -> diskTime.frame) < 0) return -1;
1498 
1499         return 0;
1500 }
1501 
1502 
1503 /*
1504  * Read the table of contents (TOC) and TOC header if necessary
1505  */
1506 
1507 static int
1508 updateToc()
     /* [previous][next][first][last][top][bottom][index][help] */
1509 {
1510         if (tocUpToDate)
1511                 return 0;
1512 
1513         if (GetDiskInfo() < 0)
1514                 return -EIO;
1515 
1516         if (GetToc() < 0)
1517                 return -EIO;
1518 
1519         tocUpToDate = 1;
1520         return 0;
1521 }
1522 
1523 
1524 /*
1525  * Read the table of contents header
1526  */
1527 
1528 static int
1529 GetDiskInfo()
     /* [previous][next][first][last][top][bottom][index][help] */
1530 {
1531         int retry;
1532 
1533         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1534         {
1535                 outb(MCMD_GET_DISK_INFO, MCDPORT(0));
1536                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1537                         break;
1538         }
1539 
1540         if (retry >= MCD_RETRY_ATTEMPTS)
1541                 return -1;
1542 
1543         if (getValue(&DiskInfo.first) < 0) return -1;
1544         if (getValue(&DiskInfo.last) < 0) return -1;
1545 
1546         DiskInfo.first = bcd2bin(DiskInfo.first);
1547         DiskInfo.last = bcd2bin(DiskInfo.last);
1548 
1549         if (getValue(&DiskInfo.diskLength.min) < 0) return -1;
1550         if (getValue(&DiskInfo.diskLength.sec) < 0) return -1;
1551         if (getValue(&DiskInfo.diskLength.frame) < 0) return -1;
1552         if (getValue(&DiskInfo.firstTrack.min) < 0) return -1;
1553         if (getValue(&DiskInfo.firstTrack.sec) < 0) return -1;
1554         if (getValue(&DiskInfo.firstTrack.frame) < 0) return -1;
1555 
1556 #ifdef MCD_DEBUG
1557 printk("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",
1558         DiskInfo.first,
1559         DiskInfo.last,
1560         DiskInfo.diskLength.min,
1561         DiskInfo.diskLength.sec,
1562         DiskInfo.diskLength.frame,
1563         DiskInfo.firstTrack.min,
1564         DiskInfo.firstTrack.sec,
1565         DiskInfo.firstTrack.frame);
1566 #endif
1567 
1568         return 0;
1569 }
1570 
1571 
1572 /*
1573  * Read the table of contents (TOC)
1574  */
1575 
1576 static int
1577 GetToc()
     /* [previous][next][first][last][top][bottom][index][help] */
1578 {
1579         int i, px;
1580         int limit;
1581         int retry;
1582         struct mcd_Toc qInfo;
1583 
1584         for (i = 0; i < MAX_TRACKS; i++)
1585                 Toc[i].pointIndex = 0;
1586 
1587         i = DiskInfo.last + 3;
1588 
1589         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1590         {
1591                 outb(MCMD_STOP, MCDPORT(0));
1592                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1593                         break;
1594         }
1595 
1596         if (retry >= MCD_RETRY_ATTEMPTS)
1597                 return -1;
1598 
1599         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1600         {
1601                 outb(MCMD_SET_MODE, MCDPORT(0));
1602                 outb(0x05, MCDPORT(0));                 /* mode: toc */
1603                 mcd_mode = 0x05;
1604                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1605                         break;
1606         }
1607 
1608         if (retry >= MCD_RETRY_ATTEMPTS)
1609                 return -1;
1610 
1611         for (limit = 300; limit > 0; limit--)
1612         {
1613                 if (GetQChannelInfo(&qInfo) < 0)
1614                         break;
1615 
1616                 px = bcd2bin(qInfo.pointIndex);
1617                 if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
1618                         if (Toc[px].pointIndex == 0)
1619                         {
1620                                 Toc[px] = qInfo;
1621                                 i--;
1622                         }
1623 
1624                 if (i <= 0)
1625                         break;
1626         }
1627 
1628         Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
1629 
1630         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1631         {
1632                 outb(MCMD_SET_MODE, MCDPORT(0));
1633                 outb(0x01, MCDPORT(0));
1634                 mcd_mode = 1;
1635                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1636                         break;
1637         }
1638 
1639 #ifdef MCD_DEBUG
1640 for (i = 1; i <= DiskInfo.last; i++)
1641 printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
1642 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1643 Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
1644 Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1645 for (i = 100; i < 103; i++)
1646 printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
1647 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1648 Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
1649 Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1650 #endif
1651 
1652         return limit > 0 ? 0 : -1;
1653 }
1654 
1655 #ifdef MODULE
1656 void cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1657 { if (MOD_IN_USE)
1658      { printk("mcd module in use - can't remove it.\n");
1659        return;    
1660      }
1661   if ((unregister_blkdev(MAJOR_NR, "mcd") == -EINVAL))
1662      { printk("What's that: can't unregister mcd\n");
1663        return;    
1664      }
1665   release_region(mcd_port,4);
1666   printk("mcd module released.\n");
1667 }
1668 #endif MODULE

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