root/drivers/block/mcd.c

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

DEFINITIONS

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

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

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