root/drivers/block/mcd.c

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

DEFINITIONS

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

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

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