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

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