root/drivers/cdrom/mcd.c

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

DEFINITIONS

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

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