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

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