root/drivers/cdrom/mcd.c

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

DEFINITIONS

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

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