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
  27. cleanup_module

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

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