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

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