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 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: 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 at least 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  immediately:
 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_immediately:
 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 immediately;
 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_immediately:
 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 immediately;
 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 immediately;
 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_immediately:
 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 immediately;
 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 immediately;
 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 immediately;
 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_immediately;
 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_immediately;
 983         else
 984           goto set_mode_immediately;
 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 (fp->f_mode & 2)                     /* write access? */
1034                 return -EROFS;
1035 
1036         if (!mcd_open_count && mcd_state == MCD_S_IDLE) {
1037 
1038         mcd_invalidate_buffers();
1039 
1040         st = statusCmd();                       /* check drive status */
1041         if (st == -1)
1042                 return -EIO;                    /* drive doesn't respond */
1043 
1044         if ((st & MST_READY) == 0)              /* no disk in drive */
1045         {
1046                 printk("mcd: no disk in drive\n");
1047                 return -EIO;
1048         }
1049 
1050         if (updateToc() < 0)
1051                 return -EIO;
1052 
1053         }
1054         ++mcd_open_count;
1055 
1056         return 0;
1057 }
1058 
1059 
1060 /*
1061  * On close, we flush all mcd blocks from the buffer cache.
1062  */
1063 
1064 static void
1065 mcd_release(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
1066 {
1067   if (!--mcd_open_count) {
1068         mcd_invalidate_buffers();
1069         sync_dev(inode->i_rdev);
1070         invalidate_buffers(inode -> i_rdev);
1071   }
1072 }
1073 
1074 
1075 static struct file_operations mcd_fops = {
1076         NULL,                   /* lseek - default */
1077         block_read,             /* read - general block-dev read */
1078         block_write,            /* write - general block-dev write */
1079         NULL,                   /* readdir - bad */
1080         NULL,                   /* select */
1081         mcd_ioctl,              /* ioctl */
1082         NULL,                   /* mmap */
1083         mcd_open,               /* open */
1084         mcd_release,            /* release */
1085         NULL,                   /* fsync */
1086         NULL,                   /* fasync */
1087         check_mcd_change,       /* media change */
1088         NULL                    /* revalidate */
1089 };
1090 
1091 
1092 /*
1093  * Test for presence of drive and initialize it.  Called at boot time.
1094  */
1095 
1096 unsigned long
1097 mcd_init(unsigned long mem_start, unsigned long mem_end)
     /* [previous][next][first][last][top][bottom][index][help] */
1098 {
1099         int count;
1100         unsigned char result[3];
1101 
1102         if (mcd_port <= 0 || mcd_irq <= 0) {
1103           printk("skip mcd_init\n");
1104           return mem_start;
1105         }
1106 
1107         printk("mcd=0x%x,%d: ", mcd_port, mcd_irq);
1108 
1109         if (register_blkdev(MAJOR_NR, "mcd", &mcd_fops) != 0)
1110         {
1111                 printk("Unable to get major %d for Mitsumi CD-ROM\n",
1112                        MAJOR_NR);
1113                 return mem_start;
1114         }
1115 
1116         if (check_region(mcd_port, 4)) {
1117           printk("Init failed, I/O port (%X) already in use\n",
1118                  mcd_port);
1119           return mem_start;
1120         }
1121           
1122         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
1123         read_ahead[MAJOR_NR] = 4;
1124 
1125         /* check for card */
1126 
1127         outb(0, MCDPORT(1));                    /* send reset */
1128         for (count = 0; count < 2000000; count++)
1129                 (void) inb(MCDPORT(1));         /* delay a bit */
1130 
1131         outb(0x40, MCDPORT(0));                 /* send get-stat cmd */
1132         for (count = 0; count < 2000000; count++)
1133                 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1134                         break;
1135 
1136         if (count >= 2000000) {
1137                 printk("Init failed. No mcd device at 0x%x irq %d\n",
1138                      mcd_port, mcd_irq);
1139                 return mem_start;
1140         }
1141         count = inb(MCDPORT(0));                /* pick up the status */
1142         
1143         outb(MCMD_GET_VERSION,MCDPORT(0));
1144         for(count=0;count<3;count++)
1145                 if(getValue(result+count)) {
1146                         printk("mitsumi get version failed at 0x%d\n",
1147                                mcd_port);
1148                         return mem_start;
1149                 }       
1150 
1151         if (result[0] == result[1] && result[1] == result[2])
1152                 return mem_start;
1153 
1154         printk("Mitsumi status, type and version : %02X %c %x\n",
1155                result[0],result[1],result[2]);
1156 
1157         if (result[1] == 'D') MCMD_DATA_READ= 0xC1;
1158 
1159         mcdVersion=result[2];
1160 
1161         if (mcdVersion >=4)
1162                 outb(4,MCDPORT(2));     /* magic happens */
1163 
1164         /* don't get the IRQ until we know for sure the drive is there */
1165 
1166         if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD"))
1167         {
1168                 printk("Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
1169                 return mem_start;
1170         }
1171         snarf_region(mcd_port, 4);
1172 
1173         outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1174         outb(0x02,MCDPORT(0));
1175         outb(0x00,MCDPORT(0));
1176         getValue(result);
1177 
1178         outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1179         outb(0x10,MCDPORT(0));
1180         outb(0x04,MCDPORT(0));
1181         getValue(result);
1182 
1183         mcd_invalidate_buffers();
1184         mcdPresent = 1;
1185         return mem_start;
1186 }
1187 
1188 
1189 static void
1190 hsg2msf(long hsg, struct msf *msf)
     /* [previous][next][first][last][top][bottom][index][help] */
1191 {
1192         hsg += 150;
1193         msf -> min = hsg / 4500;
1194         hsg %= 4500;
1195         msf -> sec = hsg / 75;
1196         msf -> frame = hsg % 75;
1197 
1198         bin2bcd(&msf -> min);           /* convert to BCD */
1199         bin2bcd(&msf -> sec);
1200         bin2bcd(&msf -> frame);
1201 }
1202 
1203 
1204 static void
1205 bin2bcd(unsigned char *p)
     /* [previous][next][first][last][top][bottom][index][help] */
1206 {
1207         int u, t;
1208 
1209         u = *p % 10;
1210         t = *p / 10;
1211         *p = u | (t << 4);
1212 }
1213 
1214 static int
1215 bcd2bin(unsigned char bcd)
     /* [previous][next][first][last][top][bottom][index][help] */
1216 {
1217         return (bcd >> 4) * 10 + (bcd & 0xF);
1218 }
1219 
1220 
1221 /*
1222  * See if a status is ready from the drive and return it
1223  * if it is ready.
1224  */
1225 
1226 static int
1227 mcdStatus(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1228 {
1229         int i;
1230         int st;
1231 
1232         st = inb(MCDPORT(1)) & MFL_STATUS;
1233         if (!st)
1234         {
1235                 i = inb(MCDPORT(0)) & 0xFF;
1236                 return i;
1237         }
1238         else
1239                 return -1;
1240 }
1241 
1242 
1243 /*
1244  * Send a play or read command to the drive
1245  */
1246 
1247 static void
1248 sendMcdCmd(int cmd, struct mcd_Play_msf *params)
     /* [previous][next][first][last][top][bottom][index][help] */
1249 {
1250         outb(cmd, MCDPORT(0));
1251         outb(params -> start.min, MCDPORT(0));
1252         outb(params -> start.sec, MCDPORT(0));
1253         outb(params -> start.frame, MCDPORT(0));
1254         outb(params -> end.min, MCDPORT(0));
1255         outb(params -> end.sec, MCDPORT(0));
1256         outb(params -> end.frame, MCDPORT(0));
1257 }
1258 
1259 
1260 /*
1261  * Timer interrupt routine to test for status ready from the drive.
1262  * (see the next routine)
1263  */
1264 
1265 static void
1266 mcdStatTimer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1267 {
1268         if (!(inb(MCDPORT(1)) & MFL_STATUS))
1269         {
1270                 wake_up(&mcd_waitq);
1271                 return;
1272         }
1273 
1274         McdTimeout--;
1275         if (McdTimeout <= 0)
1276         {
1277                 wake_up(&mcd_waitq);
1278                 return;
1279         }
1280 
1281         SET_TIMER(mcdStatTimer, 1);
1282 }
1283 
1284 
1285 /*
1286  * Wait for a status to be returned from the drive.  The actual test
1287  * (see routine above) is done by the timer interrupt to avoid
1288  * excessive rescheduling.
1289  */
1290 
1291 static int
1292 getMcdStatus(int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
1293 {
1294         int st;
1295 
1296         McdTimeout = timeout;
1297         SET_TIMER(mcdStatTimer, 1);
1298         sleep_on(&mcd_waitq);
1299         if (McdTimeout <= 0)
1300                 return -1;
1301 
1302         st = inb(MCDPORT(0)) & 0xFF;
1303         if (st == 0xFF)
1304                 return -1;
1305 
1306         if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
1307                 /* XXX might be an error? look at q-channel? */
1308                 audioStatus = CDROM_AUDIO_COMPLETED;
1309 
1310         if (st & MST_DSK_CHG)
1311         {
1312                 mcdDiskChanged = 1;
1313                 tocUpToDate = 0;
1314                 audioStatus = CDROM_AUDIO_NO_STATUS;
1315         }
1316 
1317         return st;
1318 }
1319 
1320 
1321 /*
1322  * Read a value from the drive.  Should return quickly, so a busy wait
1323  * is used to avoid excessive rescheduling.
1324  */
1325 
1326 static int
1327 getValue(unsigned char *result)
     /* [previous][next][first][last][top][bottom][index][help] */
1328 {
1329         int count;
1330         int s;
1331 
1332         for (count = 0; count < 2000; count++)
1333                 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1334                         break;
1335 
1336         if (count >= 2000)
1337         {
1338                 printk("mcd: getValue timeout\n");
1339                 return -1;
1340         }
1341 
1342         s = inb(MCDPORT(0)) & 0xFF;
1343         *result = (unsigned char) s;
1344         return 0;
1345 }
1346 
1347 
1348 /*
1349  * Read the current Q-channel info.  Also used for reading the
1350  * table of contents.
1351  */
1352 
1353 int
1354 GetQChannelInfo(struct mcd_Toc *qp)
     /* [previous][next][first][last][top][bottom][index][help] */
1355 {
1356         unsigned char notUsed;
1357         int retry;
1358 
1359         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1360         {
1361                 outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
1362                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1363                         break;
1364         }
1365 
1366         if (retry >= MCD_RETRY_ATTEMPTS)
1367                 return -1;
1368 
1369         if (getValue(&qp -> ctrl_addr) < 0) return -1;
1370         if (getValue(&qp -> track) < 0) return -1;
1371         if (getValue(&qp -> pointIndex) < 0) return -1;
1372         if (getValue(&qp -> trackTime.min) < 0) return -1;
1373         if (getValue(&qp -> trackTime.sec) < 0) return -1;
1374         if (getValue(&qp -> trackTime.frame) < 0) return -1;
1375         if (getValue(&notUsed) < 0) return -1;
1376         if (getValue(&qp -> diskTime.min) < 0) return -1;
1377         if (getValue(&qp -> diskTime.sec) < 0) return -1;
1378         if (getValue(&qp -> diskTime.frame) < 0) return -1;
1379 
1380         return 0;
1381 }
1382 
1383 
1384 /*
1385  * Read the table of contents (TOC) and TOC header if necessary
1386  */
1387 
1388 static int
1389 updateToc()
     /* [previous][next][first][last][top][bottom][index][help] */
1390 {
1391         if (tocUpToDate)
1392                 return 0;
1393 
1394         if (GetDiskInfo() < 0)
1395                 return -EIO;
1396 
1397         if (GetToc() < 0)
1398                 return -EIO;
1399 
1400         tocUpToDate = 1;
1401         return 0;
1402 }
1403 
1404 
1405 /*
1406  * Read the table of contents header
1407  */
1408 
1409 static int
1410 GetDiskInfo()
     /* [previous][next][first][last][top][bottom][index][help] */
1411 {
1412         int retry;
1413 
1414         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1415         {
1416                 outb(MCMD_GET_DISK_INFO, MCDPORT(0));
1417                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1418                         break;
1419         }
1420 
1421         if (retry >= MCD_RETRY_ATTEMPTS)
1422                 return -1;
1423 
1424         if (getValue(&DiskInfo.first) < 0) return -1;
1425         if (getValue(&DiskInfo.last) < 0) return -1;
1426 
1427         DiskInfo.first = bcd2bin(DiskInfo.first);
1428         DiskInfo.last = bcd2bin(DiskInfo.last);
1429 
1430         if (getValue(&DiskInfo.diskLength.min) < 0) return -1;
1431         if (getValue(&DiskInfo.diskLength.sec) < 0) return -1;
1432         if (getValue(&DiskInfo.diskLength.frame) < 0) return -1;
1433         if (getValue(&DiskInfo.firstTrack.min) < 0) return -1;
1434         if (getValue(&DiskInfo.firstTrack.sec) < 0) return -1;
1435         if (getValue(&DiskInfo.firstTrack.frame) < 0) return -1;
1436 
1437 #ifdef MCD_DEBUG
1438 printk("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",
1439         DiskInfo.first,
1440         DiskInfo.last,
1441         DiskInfo.diskLength.min,
1442         DiskInfo.diskLength.sec,
1443         DiskInfo.diskLength.frame,
1444         DiskInfo.firstTrack.min,
1445         DiskInfo.firstTrack.sec,
1446         DiskInfo.firstTrack.frame);
1447 #endif
1448 
1449         return 0;
1450 }
1451 
1452 
1453 /*
1454  * Read the table of contents (TOC)
1455  */
1456 
1457 static int
1458 GetToc()
     /* [previous][next][first][last][top][bottom][index][help] */
1459 {
1460         int i, px;
1461         int limit;
1462         int retry;
1463         struct mcd_Toc qInfo;
1464 
1465         for (i = 0; i < MAX_TRACKS; i++)
1466                 Toc[i].pointIndex = 0;
1467 
1468         i = DiskInfo.last + 3;
1469 
1470         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1471         {
1472                 outb(MCMD_STOP, MCDPORT(0));
1473                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1474                         break;
1475         }
1476 
1477         if (retry >= MCD_RETRY_ATTEMPTS)
1478                 return -1;
1479 
1480         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1481         {
1482                 outb(MCMD_SET_MODE, MCDPORT(0));
1483                 outb(0x05, MCDPORT(0));                 /* mode: toc */
1484                 mcd_mode = 0x05;
1485                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1486                         break;
1487         }
1488 
1489         if (retry >= MCD_RETRY_ATTEMPTS)
1490                 return -1;
1491 
1492         for (limit = 300; limit > 0; limit--)
1493         {
1494                 if (GetQChannelInfo(&qInfo) < 0)
1495                         break;
1496 
1497                 px = bcd2bin(qInfo.pointIndex);
1498                 if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
1499                         if (Toc[px].pointIndex == 0)
1500                         {
1501                                 Toc[px] = qInfo;
1502                                 i--;
1503                         }
1504 
1505                 if (i <= 0)
1506                         break;
1507         }
1508 
1509         Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
1510 
1511         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1512         {
1513                 outb(MCMD_SET_MODE, MCDPORT(0));
1514                 outb(0x01, MCDPORT(0));
1515                 mcd_mode = 1;
1516                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1517                         break;
1518         }
1519 
1520 #ifdef MCD_DEBUG
1521 for (i = 1; i <= DiskInfo.last; i++)
1522 printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
1523 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1524 Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
1525 Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1526 for (i = 100; i < 103; i++)
1527 printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
1528 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1529 Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
1530 Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1531 #endif
1532 
1533         return limit > 0 ? 0 : -1;
1534 }
1535 

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