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_media_change
  3. statusCmd
  4. mcdPlay
  5. msf2hsg
  6. mcd_ioctl
  7. mcd_transfer
  8. mcd_interrupt
  9. do_mcd_request
  10. mcd_start
  11. mcd_status
  12. mcd_read_cmd
  13. mcd_data
  14. mcd_open
  15. mcd_release
  16. mcd_init
  17. hsg2msf
  18. bin2bcd
  19. bcd2bin
  20. mcdStatus
  21. sendMcdCmd
  22. mcdStatTimer
  23. getMcdStatus
  24. getValue
  25. GetQChannelInfo
  26. updateToc
  27. GetDiskInfo
  28. GetToc

   1 /*
   2         linux/kernel/blk_drv/mcd.c - Mitsumi CDROM driver
   3 
   4         Copyright (C) 1992  Martin Harriss
   5 
   6         martin@bdsi.com
   7 
   8         This program is free software; you can redistribute it and/or modify
   9         it under the terms of the GNU General Public License as published by
  10         the Free Software Foundation; either version 2, or (at your option)
  11         any later version.
  12 
  13         This program is distributed in the hope that it will be useful,
  14         but WITHOUT ANY WARRANTY; without even the implied warranty of
  15         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16         GNU General Public License for more details.
  17 
  18         You should have received a copy of the GNU General Public License
  19         along with this program; if not, write to the Free Software
  20         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21 
  22         HISTORY
  23 
  24         0.1     First attempt - internal use only
  25         0.2     Cleaned up delays and use of timer - alpha release
  26         0.3     Audio support added
  27         0.3.1 Changes for mitsumi CRMC LU005S march version
  28                    (stud11@cc4.kuleuven.ac.be)
  29         0.3.2 bug fixes to the ioclts and merged with ALPHA0.99-pl12
  30                    (Jon Tombs <jon@robots.ox.ac.uk>)
  31         0.3.3 Added more #defines and mcd_setup()
  32                    (Jon Tombs <jon@gtex02.us.es>)
  33 */
  34 
  35 
  36 #include <linux/errno.h>
  37 #include <linux/signal.h>
  38 #include <linux/sched.h>
  39 #include <linux/timer.h>
  40 #include <linux/fs.h>
  41 #include <linux/kernel.h>
  42 #include <linux/cdrom.h>
  43 #include <linux/ioport.h>
  44 
  45 /* #define REALLY_SLOW_IO  */
  46 #include <asm/system.h>
  47 #include <asm/io.h>
  48 #include <asm/segment.h>
  49 
  50 #define MAJOR_NR MITSUMI_CDROM_MAJOR
  51 #include "blk.h"
  52 #include <linux/mcd.h>
  53 
  54 #if 0
  55 static int mcd_sizes[] = { 0 };
  56 #endif
  57 
  58 static int mcdPresent = 0;
  59 
  60 static char mcd_buf[2048];      /* buffer for block size conversion */
  61 static int   mcd_bn   = -1;
  62 static short mcd_port = MCD_BASE_ADDR;
  63 static int   mcd_irq  = MCD_INTR_NR;
  64 
  65 static int McdTimeout, McdTries;
  66 static struct wait_queue *mcd_waitq = NULL;
  67 
  68 static struct mcd_DiskInfo DiskInfo;
  69 static struct mcd_Toc Toc[MAX_TRACKS];
  70 static struct mcd_Play_msf mcd_Play;
  71 
  72 static int audioStatus;
  73 static char mcdDiskChanged;
  74 static char tocUpToDate;
  75 static char mcdVersion;
  76 
  77 static void mcd_transfer(void);
  78 static void mcd_start(void);
  79 static void mcd_status(void);
  80 static void mcd_read_cmd(void);
  81 static void mcd_data(void);
  82 static void do_mcd_request(void);
  83 static void hsg2msf(long hsg, struct msf *msf);
  84 static void bin2bcd(unsigned char *p);
  85 static int bcd2bin(unsigned char bcd);
  86 static int mcdStatus(void);
  87 static void sendMcdCmd(int cmd, struct mcd_Play_msf *params);
  88 static int getMcdStatus(int timeout);
  89 static int GetQChannelInfo(struct mcd_Toc *qp);
  90 static int updateToc(void);
  91 static int GetDiskInfo(void);
  92 static int GetToc(void);
  93 static int getValue(unsigned char *result);
  94 
  95 
  96 void mcd_setup(char *str, int *ints)
     /* [previous][next][first][last][top][bottom][index][help] */
  97 {
  98    if (ints[0] > 0)
  99       mcd_port = ints[1];
 100    if (ints[0] > 1)      
 101       mcd_irq  = ints[2];
 102 }
 103 
 104  
 105 int
 106 check_mcd_media_change(int full_dev, int flag)
     /* [previous][next][first][last][top][bottom][index][help] */
 107 {
 108    int retval, target;
 109 
 110 
 111 #if 1    /* the below is not reliable */
 112    return 0;
 113 #endif  
 114    target = MINOR(full_dev);
 115 
 116    if (target > 0) {
 117       printk("mcd: Mitsumi CD-ROM request error: invalid device.\n");
 118       return 0;
 119    }
 120 
 121    retval = mcdDiskChanged;
 122    if (!flag)
 123    {
 124       mcdDiskChanged = 0;
 125    }
 126 
 127    return retval;
 128 }
 129 
 130 
 131 /*
 132  * Do a 'get status' command and get the result.  Only use from the top half
 133  * because it calls 'getMcdStatus' which sleeps.
 134  */
 135 
 136 static int
 137 statusCmd(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 138 {
 139         int st, retry;
 140 
 141         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
 142         {
 143 
 144                 outb(MCMD_GET_STATUS, MCDPORT(0));      /* send get-status cmd */
 145                 st = getMcdStatus(MCD_STATUS_DELAY);
 146                 if (st != -1)
 147                         break;
 148         }
 149 
 150         return st;
 151 }
 152 
 153 
 154 /*
 155  * Send a 'Play' command and get the status.  Use only from the top half.
 156  */
 157 
 158 static int
 159 mcdPlay(struct mcd_Play_msf *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 160 {
 161         int retry, st;
 162 
 163         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
 164         {
 165                 sendMcdCmd(MCMD_PLAY_READ, arg);
 166                 st = getMcdStatus(2 * MCD_STATUS_DELAY);
 167                 if (st != -1)
 168                         break;
 169         }
 170 
 171         return st;
 172 }
 173 
 174 
 175 long
 176 msf2hsg(struct msf *mp)
     /* [previous][next][first][last][top][bottom][index][help] */
 177 {
 178         return bcd2bin(mp -> frame)
 179                 + bcd2bin(mp -> sec) * 75
 180                 + bcd2bin(mp -> min) * 4500
 181                 - 150;
 182 }
 183 
 184 
 185 static int
 186 mcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
     /* [previous][next][first][last][top][bottom][index][help] */
 187                                                 unsigned long arg)
 188 {
 189         int i, st;
 190         struct mcd_Toc qInfo;
 191         struct cdrom_ti ti;
 192         struct cdrom_tochdr tocHdr;
 193         struct cdrom_msf msf;
 194         struct cdrom_tocentry entry;
 195         struct mcd_Toc *tocPtr;
 196         struct cdrom_subchnl subchnl;
 197 #if 0
 198         struct cdrom_volctrl volctrl;
 199 #endif
 200 
 201         if (!ip)
 202                 return -EINVAL;
 203 
 204         st = statusCmd();
 205         if (st < 0)
 206                 return -EIO;
 207 
 208         if (!tocUpToDate)
 209         {
 210                 i = updateToc();
 211                 if (i < 0)
 212                         return i;       /* error reading TOC */
 213         }
 214 
 215         switch (cmd)
 216         {
 217         case CDROMSTART:     /* Spin up the drive */
 218                 /* Don't think we can do this.  Even if we could,
 219                  * I think the drive times out and stops after a while
 220                  * anyway.  For now, ignore it.
 221                  */
 222 
 223                 return 0;
 224 
 225         case CDROMSTOP:      /* Spin down the drive */
 226                 outb(MCMD_STOP, MCDPORT(0));
 227                 i = getMcdStatus(MCD_STATUS_DELAY);
 228 
 229                 /* should we do anything if it fails? */
 230 
 231                 audioStatus = CDROM_AUDIO_NO_STATUS;
 232                 return 0;
 233 
 234         case CDROMPAUSE:     /* Pause the drive */
 235                 if (audioStatus != CDROM_AUDIO_PLAY)
 236                         return -EINVAL;
 237 
 238                 outb(MCMD_STOP, MCDPORT(0));
 239                 i = getMcdStatus(MCD_STATUS_DELAY);
 240 
 241                 if (GetQChannelInfo(&qInfo) < 0)
 242                 {
 243                         /* didn't get q channel info */
 244 
 245                         audioStatus = CDROM_AUDIO_NO_STATUS;
 246                         return 0;
 247                 }
 248 
 249                 mcd_Play.start = qInfo.diskTime;        /* remember restart point */
 250 
 251                 audioStatus = CDROM_AUDIO_PAUSED;
 252                 return 0;
 253 
 254         case CDROMRESUME:    /* Play it again, Sam */
 255                 if (audioStatus != CDROM_AUDIO_PAUSED)
 256                         return -EINVAL;
 257 
 258                 /* restart the drive at the saved position. */
 259 
 260                 i = mcdPlay(&mcd_Play);
 261                 if (i < 0)
 262                 {
 263                         audioStatus = CDROM_AUDIO_ERROR;
 264                         return -EIO;
 265                 }
 266 
 267                 audioStatus = CDROM_AUDIO_PLAY;
 268                 return 0;
 269 
 270         case CDROMPLAYTRKIND:     /* Play a track.  This currently ignores index. */
 271 
 272                 st = verify_area(VERIFY_READ, (void *) arg, sizeof ti);
 273                 if (st)
 274                         return st;
 275 
 276                 memcpy_fromfs(&ti, (void *) arg, sizeof ti);
 277 
 278                 if (ti.cdti_trk0 < DiskInfo.first
 279                         || ti.cdti_trk0 > DiskInfo.last
 280                         || ti.cdti_trk1 < ti.cdti_trk0)
 281                 {
 282                         return -EINVAL;
 283                 }
 284 
 285                 if (ti.cdti_trk1 > DiskInfo.last)
 286                         ti. cdti_trk1 = DiskInfo.last;
 287 
 288                 mcd_Play.start = Toc[ti.cdti_trk0].diskTime;
 289                 mcd_Play.end = Toc[ti.cdti_trk1 + 1].diskTime;
 290 
 291 #ifdef MCD_DEBUG
 292 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
 293         mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
 294         mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
 295 #endif
 296 
 297                 i = mcdPlay(&mcd_Play);
 298                 if (i < 0)
 299                 {
 300                         audioStatus = CDROM_AUDIO_ERROR;
 301                         return -EIO;
 302                 }
 303 
 304                 audioStatus = CDROM_AUDIO_PLAY;
 305                 return 0;
 306 
 307         case CDROMPLAYMSF:   /* Play starting at the given MSF address. */
 308 
 309                 if (audioStatus == CDROM_AUDIO_PLAY) {
 310                   outb(MCMD_STOP, MCDPORT(0));
 311                   i = getMcdStatus(MCD_STATUS_DELAY);
 312                   audioStatus = CDROM_AUDIO_NO_STATUS;
 313                 }
 314 
 315                 st = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
 316                 if (st)
 317                         return st;
 318 
 319                 memcpy_fromfs(&msf, (void *) arg, sizeof msf);
 320 
 321                 /* convert to bcd */
 322 
 323                 bin2bcd(&msf.cdmsf_min0);
 324                 bin2bcd(&msf.cdmsf_sec0);
 325                 bin2bcd(&msf.cdmsf_frame0);
 326                 bin2bcd(&msf.cdmsf_min1);
 327                 bin2bcd(&msf.cdmsf_sec1);
 328                 bin2bcd(&msf.cdmsf_frame1);
 329 
 330                 mcd_Play.start.min = msf.cdmsf_min0;
 331                 mcd_Play.start.sec = msf.cdmsf_sec0;
 332                 mcd_Play.start.frame = msf.cdmsf_frame0;
 333                 mcd_Play.end.min = msf.cdmsf_min1;
 334                 mcd_Play.end.sec = msf.cdmsf_sec1;
 335                 mcd_Play.end.frame = msf.cdmsf_frame1;
 336 
 337 #ifdef MCD_DEBUG
 338 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
 339 mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame,
 340 mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame);
 341 #endif
 342 
 343                 i = mcdPlay(&mcd_Play);
 344                 if (i < 0)
 345                 {
 346                         audioStatus = CDROM_AUDIO_ERROR;
 347                         return -EIO;
 348                 }
 349 
 350                 audioStatus = CDROM_AUDIO_PLAY;
 351                 return 0;
 352 
 353         case CDROMREADTOCHDR:        /* Read the table of contents header */
 354                 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof tocHdr);
 355                 if (st)
 356                         return st;
 357 
 358                 tocHdr.cdth_trk0 = DiskInfo.first;
 359                 tocHdr.cdth_trk1 = DiskInfo.last;
 360                 memcpy_tofs((void *) arg, &tocHdr, sizeof tocHdr);
 361                 return 0;
 362 
 363         case CDROMREADTOCENTRY:      /* Read an entry in the table of contents */
 364 
 365                 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
 366                 if (st)
 367                         return st;
 368 
 369                 memcpy_fromfs(&entry, (void *) arg, sizeof entry);
 370                 if (entry.cdte_track == CDROM_LEADOUT)
 371                         /* XXX */
 372                         tocPtr = &Toc[DiskInfo.last + 1];
 373 
 374                 else if (entry.cdte_track > DiskInfo.last
 375                                 || entry.cdte_track < DiskInfo.first)
 376                         return -EINVAL;
 377 
 378                 else
 379                         tocPtr = &Toc[entry.cdte_track];
 380 
 381                 entry.cdte_adr = tocPtr -> ctrl_addr;
 382                 entry.cdte_ctrl = tocPtr -> ctrl_addr >> 4;
 383 
 384                 if (entry.cdte_format == CDROM_LBA)
 385                         entry.cdte_addr.lba = msf2hsg(&tocPtr -> diskTime);
 386 
 387                 else if (entry.cdte_format == CDROM_MSF)
 388                 {
 389                         entry.cdte_addr.msf.minute = bcd2bin(tocPtr -> diskTime.min);
 390                         entry.cdte_addr.msf.second = bcd2bin(tocPtr -> diskTime.sec);
 391                         entry.cdte_addr.msf.frame = bcd2bin(tocPtr -> diskTime.frame);
 392                 }
 393 
 394                 else
 395                         return -EINVAL;
 396 
 397                 memcpy_tofs((void *) arg, &entry, sizeof entry);
 398                 return 0;
 399 
 400         case CDROMSUBCHNL:   /* Get subchannel info */
 401 
 402                 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl);
 403                 if (st)
 404                         return st;
 405 
 406                 memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl);
 407 
 408                 if (GetQChannelInfo(&qInfo) < 0)
 409                         return -EIO;
 410 
 411                 subchnl.cdsc_audiostatus = audioStatus;
 412                 subchnl.cdsc_adr = qInfo.ctrl_addr;
 413                 subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4;
 414                 subchnl.cdsc_trk = bcd2bin(qInfo.track);
 415                 subchnl.cdsc_ind = bcd2bin(qInfo.pointIndex);
 416 
 417                 if (subchnl.cdsc_format == CDROM_LBA)
 418                 {
 419                         subchnl.cdsc_absaddr.lba = msf2hsg(&qInfo.diskTime);
 420                         subchnl.cdsc_reladdr.lba = msf2hsg(&qInfo.trackTime);
 421                 }
 422 
 423                 else if (subchnl.cdsc_format == CDROM_MSF)
 424                 {
 425                         subchnl.cdsc_absaddr.msf.minute = bcd2bin(qInfo.diskTime.min);
 426                         subchnl.cdsc_absaddr.msf.second = bcd2bin(qInfo.diskTime.sec);
 427                         subchnl.cdsc_absaddr.msf.frame = bcd2bin(qInfo.diskTime.frame);
 428 
 429                         subchnl.cdsc_reladdr.msf.minute = bcd2bin(qInfo.trackTime.min);
 430                         subchnl.cdsc_reladdr.msf.second = bcd2bin(qInfo.trackTime.sec);
 431                         subchnl.cdsc_reladdr.msf.frame = bcd2bin(qInfo.trackTime.frame);
 432                 }
 433 
 434                 else
 435                         return -EINVAL;
 436 
 437                 memcpy_tofs((void *) arg, &subchnl, sizeof subchnl);
 438                 return 0;
 439 
 440         case CDROMVOLCTRL:   /* Volume control */
 441         /*
 442          * This is not working yet.  Setting the volume by itself does
 443          * nothing.  Following the 'set' by a 'play' results in zero
 444          * volume.  Something to work on for the next release.
 445          */
 446 #if 0
 447                 st = verify_area(VERIFY_READ, (void *) arg, sizeof(volctrl));
 448                 if (st)
 449                         return st;
 450 
 451                 memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
 452 printk("VOL %d %d\n", volctrl.channel0 & 0xFF, volctrl.channel1 & 0xFF);
 453                 outb(MCMD_SET_VOLUME, MCDPORT(0));
 454                 outb(volctrl.channel0, MCDPORT(0));
 455                 outb(0, MCDPORT(0));
 456                 outb(volctrl.channel1, MCDPORT(0));
 457                 outb(1, MCDPORT(0));
 458 
 459                 i = getMcdStatus(MCD_STATUS_DELAY);
 460                 if (i < 0)
 461                         return -EIO;
 462 
 463                 {
 464                         int a, b, c, d;
 465 
 466                         getValue(&a);
 467                         getValue(&b);
 468                         getValue(&c);
 469                         getValue(&d);
 470                         printk("%02X %02X %02X %02X\n", a, b, c, d);
 471                 }
 472 
 473                 outb(0xF8, MCDPORT(0));
 474                 i = getMcdStatus(MCD_STATUS_DELAY);
 475                 printk("F8 -> %02X\n", i & 0xFF);
 476 #endif
 477                 return 0;
 478 
 479         case CDROMEJECT:
 480                /* all drives can atleast stop! */
 481                 if (audioStatus == CDROM_AUDIO_PLAY) {
 482                   outb(MCMD_STOP, MCDPORT(0));
 483                   i = getMcdStatus(MCD_STATUS_DELAY);
 484                 }
 485  
 486                 audioStatus = CDROM_AUDIO_NO_STATUS;
 487  
 488                 outb(MCMD_EJECT, MCDPORT(0));
 489                 /*
 490                  * the status (i) shows failure on all but the FX drives.
 491                  * But nothing we can do about that in software!
 492                  * So just read the status and forget it. - Jon.
 493                  */
 494                 i = getMcdStatus(MCD_STATUS_DELAY);
 495                 return 0;
 496         default:
 497                 return -EINVAL;
 498         }
 499 }
 500 
 501 
 502 /*
 503  * Take care of the different block sizes between cdrom and Linux.
 504  * When Linux gets variable block sizes this will probably go away.
 505  */
 506 
 507 static void
 508 mcd_transfer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 509 {
 510         long offs;
 511 
 512         while (CURRENT -> nr_sectors > 0 && mcd_bn == CURRENT -> sector / 4)
 513         {
 514                 offs = (CURRENT -> sector & 3) * 512;
 515                 memcpy(CURRENT -> buffer, mcd_buf + offs, 512);
 516                 CURRENT -> nr_sectors--;
 517                 CURRENT -> sector++;
 518                 CURRENT -> buffer += 512;
 519         }
 520 }
 521 
 522 
 523 /*
 524  * We only seem to get interrupts after an error.
 525  * Just take the interrupt and clear out the status reg.
 526  */
 527 
 528 static void
 529 mcd_interrupt(int unused)
     /* [previous][next][first][last][top][bottom][index][help] */
 530 {
 531         int st;
 532 
 533         st = inb(MCDPORT(1)) & 0xFF;
 534         if (st != 0xFF)
 535         {
 536                 st = inb(MCDPORT(0)) & 0xFF;
 537 #if 0
 538                 printk("<int-%02X>", st);
 539 #endif
 540         }
 541 }
 542 
 543 
 544 /*
 545  * I/O request routine called from Linux kernel.
 546  */
 547 
 548 static void
 549 do_mcd_request(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 550 {
 551         unsigned int block,dev;
 552         unsigned int nsect;
 553 
 554 repeat:
 555         if (!(CURRENT) || CURRENT->dev < 0) return;
 556         INIT_REQUEST;
 557         dev = MINOR(CURRENT->dev);
 558         block = CURRENT->sector;
 559         nsect = CURRENT->nr_sectors;
 560 
 561         if (CURRENT == NULL || CURRENT -> sector == -1)
 562                 return;
 563 
 564         if (CURRENT -> cmd != READ)
 565         {
 566                 printk("mcd: bad cmd %d\n", CURRENT -> cmd);
 567                 end_request(0);
 568                 goto repeat;
 569         }
 570 
 571         mcd_transfer();
 572 
 573         /* if we satisfied the request from the buffer, we're done. */
 574 
 575         if (CURRENT -> nr_sectors == 0)
 576         {
 577                 end_request(1);
 578                 goto repeat;
 579         }
 580 
 581         McdTries = MCD_RETRY_ATTEMPTS;
 582         mcd_start();
 583 }
 584 
 585 
 586 /*
 587  * Start the I/O for the cdrom. Handle retry count.
 588  */
 589 
 590 static void
 591 mcd_start()
     /* [previous][next][first][last][top][bottom][index][help] */
 592 {
 593         if (McdTries == 0)
 594         {
 595                 printk("mcd: read failed after %d tries\n", MCD_RETRY_ATTEMPTS);
 596                 end_request(0);
 597                 SET_TIMER(do_mcd_request, 1);   /* wait a bit, try again */
 598                 return;
 599         }
 600 
 601         McdTries--;
 602         outb(0x40, MCDPORT(0));         /* get status */
 603         McdTimeout = MCD_STATUS_DELAY;
 604         SET_TIMER(mcd_status, 1);
 605 }
 606 
 607 
 608 /*
 609  * Called from the timer to check the results of the get-status cmd.
 610  * On success, send the set-mode command.
 611  */
 612 
 613 static void
 614 mcd_status()
     /* [previous][next][first][last][top][bottom][index][help] */
 615 {
 616         int st;
 617 
 618         McdTimeout--;
 619         st = mcdStatus();
 620         if (st == -1)
 621         {
 622                 if (McdTimeout == 0)
 623                 {
 624                         printk("mcd: status timed out\n");
 625                         SET_TIMER(mcd_start, 1);        /* wait a bit, try again */
 626                         return;
 627                 }
 628 
 629                 SET_TIMER(mcd_status, 1);
 630                 return;
 631         }
 632 
 633         if (st & MST_DSK_CHG)
 634         {
 635                 mcdDiskChanged = 1;
 636         }
 637         
 638         if ((st & MST_READY) == 0)
 639         {
 640                 printk("mcd: disk removed\n");
 641                 mcdDiskChanged = 1;             
 642                 end_request(0);
 643                 do_mcd_request();
 644                 return;
 645         }
 646 
 647         outb(0x50, MCDPORT(0)); /* set mode */
 648         outb(0x01, MCDPORT(0)); /* mode = cooked data */
 649         McdTimeout = 100;
 650         SET_TIMER(mcd_read_cmd, 1);
 651 }
 652 
 653 
 654 /*
 655  * Check the result of the set-mode command.  On success, send the
 656  * read-data command.
 657  */
 658 
 659 static void
 660 mcd_read_cmd()
     /* [previous][next][first][last][top][bottom][index][help] */
 661 {
 662         int st;
 663         long block;
 664         struct mcd_Play_msf mcdcmd;
 665 
 666         McdTimeout--;
 667         st = mcdStatus();
 668 
 669         if (st & MST_DSK_CHG)
 670         {
 671                 mcdDiskChanged = 1;
 672         }
 673         
 674         if (st == -1)
 675         {
 676                 if (McdTimeout == 0)
 677                 {
 678                         printk("mcd: set mode timed out\n");
 679                         SET_TIMER(mcd_start, 1);        /* wait a bit, try again */
 680                         return;
 681                 }
 682 
 683                 SET_TIMER(mcd_read_cmd, 1);
 684                 return;
 685         }
 686 
 687         mcd_bn = -1;                    /* purge our buffer */
 688         block = CURRENT -> sector / 4;
 689         hsg2msf(block, &mcdcmd.start);  /* cvt to msf format */
 690 
 691         mcdcmd.end.min = 0;
 692         mcdcmd.end.sec = 0;
 693         mcdcmd.end.frame = 1;
 694 
 695         sendMcdCmd(MCMD_PLAY_READ, &mcdcmd);    /* read command */
 696         McdTimeout = 200;
 697         SET_TIMER(mcd_data, 1);
 698 }
 699 
 700 
 701 /*
 702  * Check the completion of the read-data command.  On success, read
 703  * the 2048 bytes of data from the disk into our buffer.
 704  */
 705 
 706 static void
 707 mcd_data()
     /* [previous][next][first][last][top][bottom][index][help] */
 708 {
 709         int i;
 710 
 711         McdTimeout--;
 712         cli();
 713         i =inb(MCDPORT(1)) & (MFL_STATUS | MFL_DATA);
 714         if (i == MFL_DATA)
 715         {
 716                 printk("mcd: read failed\n");
 717 #ifdef MCD_DEBUG
 718                 printk("got 0xB %02X\n", inb(MCDPORT(0)) & 0xFF);
 719 #endif
 720                 SET_TIMER(mcd_start, 1);
 721                 sti();
 722                 return;
 723         }
 724         
 725         if (i == (MFL_STATUS | MFL_DATA))
 726         {
 727                 if (McdTimeout == 0)
 728                 {
 729                         printk("mcd: data timeout, retrying\n");
 730                         SET_TIMER(mcd_start, 1);
 731                 }
 732                 
 733                 else
 734                         SET_TIMER(mcd_data, 1);
 735                 
 736                 sti();
 737                 return;
 738         }
 739 
 740         CLEAR_TIMER;
 741         READ_DATA(MCDPORT(0), &mcd_buf[0], 2048);
 742         sti();
 743 
 744         mcd_bn = CURRENT -> sector / 4;
 745         mcd_transfer();
 746         end_request(1);
 747         SET_TIMER(do_mcd_request, 1);
 748 }
 749 
 750 
 751 /*
 752  * Open the device special file.  Check that a disk is in.
 753  */
 754 
 755 int
 756 mcd_open(struct inode *ip, struct file *fp)
     /* [previous][next][first][last][top][bottom][index][help] */
 757 {
 758         int st;
 759 
 760         if (mcdPresent == 0)
 761                 return -ENXIO;                  /* no hardware */
 762 
 763         st = statusCmd();                       /* check drive status */
 764         if (st == -1)
 765                 return -EIO;                    /* drive doesn't respond */
 766 
 767         if ((st & MST_READY) == 0)              /* no disk in drive */
 768         {
 769                 printk("mcd: no disk in drive\n");
 770                 return -EIO;
 771         }
 772 
 773         if (updateToc() < 0)
 774                 return -EIO;
 775 
 776         return 0;
 777 }
 778 
 779 
 780 /*
 781  * On close, we flush all mcd blocks from the buffer cache.
 782  */
 783 
 784 static void
 785 mcd_release(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 786 {
 787         mcd_bn = -1;
 788         sync_dev(inode->i_rdev);
 789         invalidate_buffers(inode -> i_rdev);
 790 }
 791 
 792 
 793 static struct file_operations mcd_fops = {
 794         NULL,                   /* lseek - default */
 795         block_read,             /* read - general block-dev read */
 796         block_write,            /* write - general block-dev write */
 797         NULL,                   /* readdir - bad */
 798         NULL,                   /* select */
 799         mcd_ioctl,              /* ioctl */
 800         NULL,                   /* mmap */
 801         mcd_open,               /* open */
 802         mcd_release             /* release */
 803 };
 804 
 805 
 806 /*
 807  * MCD interrupt descriptor
 808  */
 809 
 810 static struct sigaction mcd_sigaction = {
 811         mcd_interrupt,
 812         0,
 813         SA_INTERRUPT,
 814         NULL
 815 };
 816 
 817 
 818 /*
 819  * Test for presence of drive and initialize it.  Called at boot time.
 820  */
 821 
 822 unsigned long
 823 mcd_init(unsigned long mem_start, unsigned long mem_end)
     /* [previous][next][first][last][top][bottom][index][help] */
 824 {
 825         int count;
 826         unsigned char result[3];
 827 
 828         if (register_blkdev(MAJOR_NR, "mcd", &mcd_fops) != 0)
 829         {
 830                 printk("mcd: Unable to get major %d for Mitsumi CD-ROM\n",
 831                        MAJOR_NR);
 832                 return mem_start;
 833         }
 834 
 835         if (check_region(mcd_port, 4)) {
 836           printk("mcd: Init failed, I/O port (%X) already in use\n",
 837                  mcd_port);
 838           return mem_start;
 839         }
 840           
 841         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 842         read_ahead[MAJOR_NR] = 4;
 843 
 844         /* check for card */
 845 
 846         outb(0, MCDPORT(1));                    /* send reset */
 847         for (count = 0; count < 1000000; count++)
 848                 (void) inb(MCDPORT(1));         /* delay a bit */
 849 
 850         outb(0x40, MCDPORT(0));                 /* send get-stat cmd */
 851         for (count = 0; count < 1000000; count++)
 852                 if (!(inb(MCDPORT(1)) & MFL_STATUS))
 853                         break;
 854 
 855         if (count >= 1000000) {
 856                 printk("mcd: Init failed. No mcd device at 0x%x irq %d\n",
 857                      mcd_port, mcd_irq);
 858                 return mem_start;
 859         }
 860         count = inb(MCDPORT(0));                /* pick up the status */
 861         
 862         outb(MCMD_GET_VERSION,MCDPORT(0));
 863         for(count=0;count<3;count++)
 864                 if(getValue(result+count)) {
 865                         printk("mcd: mitsumi get version failed at 0x%d\n",
 866                                mcd_port);
 867                         return mem_start;
 868                 }       
 869 
 870         if (result[0] == result[1] && result[1] == result[2])
 871                 return mem_start;
 872 
 873         printk("mcd: Mitsumi version : %02X %c %x\n",
 874                result[0],result[1],result[2]);
 875 
 876 
 877         mcdVersion=result[2];
 878 
 879         if (mcdVersion >=4)
 880                 outb(4,MCDPORT(2));     /* magic happens */
 881 
 882         /* don't get the IRQ until we know for sure the drive is there */
 883 
 884         if (irqaction(mcd_irq,  &mcd_sigaction))
 885         {
 886                 printk("mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
 887                 return mem_start;
 888         }
 889         snarf_region(mcd_port, 4);
 890         mcdPresent = 1;
 891         printk("mcd: Mitsumi CD-ROM Drive present at addr %x, irq %d\n",
 892                mcd_port, mcd_irq);
 893         return mem_start;
 894 }
 895 
 896 
 897 static void
 898 hsg2msf(long hsg, struct msf *msf)
     /* [previous][next][first][last][top][bottom][index][help] */
 899 {
 900         hsg += 150;
 901         msf -> min = hsg / 4500;
 902         hsg %= 4500;
 903         msf -> sec = hsg / 75;
 904         msf -> frame = hsg % 75;
 905 
 906         bin2bcd(&msf -> min);           /* convert to BCD */
 907         bin2bcd(&msf -> sec);
 908         bin2bcd(&msf -> frame);
 909 }
 910 
 911 
 912 static void
 913 bin2bcd(unsigned char *p)
     /* [previous][next][first][last][top][bottom][index][help] */
 914 {
 915         int u, t;
 916 
 917         u = *p % 10;
 918         t = *p / 10;
 919         *p = u | (t << 4);
 920 }
 921 
 922 static int
 923 bcd2bin(unsigned char bcd)
     /* [previous][next][first][last][top][bottom][index][help] */
 924 {
 925         return (bcd >> 4) * 10 + (bcd & 0xF);
 926 }
 927 
 928 
 929 /*
 930  * See if a status is ready from the drive and return it
 931  * if it is ready.
 932  */
 933 
 934 static int
 935 mcdStatus(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 936 {
 937         int i;
 938         int st;
 939 
 940         st = inb(MCDPORT(1)) & MFL_STATUS;
 941         if (!st)
 942         {
 943                 i = inb(MCDPORT(0)) & 0xFF;
 944                 return i;
 945         }
 946         else
 947                 return -1;
 948 }
 949 
 950 
 951 /*
 952  * Send a play or read command to the drive
 953  */
 954 
 955 static void
 956 sendMcdCmd(int cmd, struct mcd_Play_msf *params)
     /* [previous][next][first][last][top][bottom][index][help] */
 957 {
 958         outb(cmd, MCDPORT(0));
 959         outb(params -> start.min, MCDPORT(0));
 960         outb(params -> start.sec, MCDPORT(0));
 961         outb(params -> start.frame, MCDPORT(0));
 962         outb(params -> end.min, MCDPORT(0));
 963         outb(params -> end.sec, MCDPORT(0));
 964         outb(params -> end.frame, MCDPORT(0));
 965 }
 966 
 967 
 968 /*
 969  * Timer interrupt routine to test for status ready from the drive.
 970  * (see the next routine)
 971  */
 972 
 973 static void
 974 mcdStatTimer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 975 {
 976         if (!(inb(MCDPORT(1)) & MFL_STATUS))
 977         {
 978                 wake_up(&mcd_waitq);
 979                 return;
 980         }
 981 
 982         McdTimeout--;
 983         if (McdTimeout <= 0)
 984         {
 985                 wake_up(&mcd_waitq);
 986                 return;
 987         }
 988 
 989         SET_TIMER(mcdStatTimer, 1);
 990 }
 991 
 992 
 993 /*
 994  * Wait for a status to be returned from the drive.  The actual test
 995  * (see routine above) is done by the timer interrupt to avoid
 996  * excessive rescheduling.
 997  */
 998 
 999 static int
1000 getMcdStatus(int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
1001 {
1002         int st;
1003 
1004         McdTimeout = timeout;
1005         SET_TIMER(mcdStatTimer, 1);
1006         sleep_on(&mcd_waitq);
1007         if (McdTimeout <= 0)
1008                 return -1;
1009 
1010         st = inb(MCDPORT(0)) & 0xFF;
1011         if (st == 0xFF)
1012                 return -1;
1013 
1014         if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
1015                 /* XXX might be an error? look at q-channel? */
1016                 audioStatus = CDROM_AUDIO_COMPLETED;
1017 
1018         if (st & MST_DSK_CHG)
1019         {
1020                 mcdDiskChanged = 1;
1021                 tocUpToDate = 0;
1022                 audioStatus = CDROM_AUDIO_NO_STATUS;
1023         }
1024 
1025         return st;
1026 }
1027 
1028 
1029 /*
1030  * Read a value from the drive.  Should return quickly, so a busy wait
1031  * is used to avoid excessive rescheduling.
1032  */
1033 
1034 static int
1035 getValue(unsigned char *result)
     /* [previous][next][first][last][top][bottom][index][help] */
1036 {
1037         int count;
1038         int s;
1039 
1040         for (count = 0; count < 2000; count++)
1041                 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1042                         break;
1043 
1044         if (count >= 2000)
1045         {
1046                 printk("mcd: getValue timeout\n");
1047                 return -1;
1048         }
1049 
1050         s = inb(MCDPORT(0)) & 0xFF;
1051         *result = (unsigned char) s;
1052         return 0;
1053 }
1054 
1055 
1056 /*
1057  * Read the current Q-channel info.  Also used for reading the
1058  * table of contents.
1059  */
1060 
1061 int
1062 GetQChannelInfo(struct mcd_Toc *qp)
     /* [previous][next][first][last][top][bottom][index][help] */
1063 {
1064         unsigned char notUsed;
1065         int retry;
1066 
1067         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1068         {
1069                 outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
1070                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1071                         break;
1072         }
1073 
1074         if (retry >= MCD_RETRY_ATTEMPTS)
1075                 return -1;
1076 
1077         if (getValue(&qp -> ctrl_addr) < 0) return -1;
1078         if (getValue(&qp -> track) < 0) return -1;
1079         if (getValue(&qp -> pointIndex) < 0) return -1;
1080         if (getValue(&qp -> trackTime.min) < 0) return -1;
1081         if (getValue(&qp -> trackTime.sec) < 0) return -1;
1082         if (getValue(&qp -> trackTime.frame) < 0) return -1;
1083         if (getValue(&notUsed) < 0) return -1;
1084         if (getValue(&qp -> diskTime.min) < 0) return -1;
1085         if (getValue(&qp -> diskTime.sec) < 0) return -1;
1086         if (getValue(&qp -> diskTime.frame) < 0) return -1;
1087 
1088         return 0;
1089 }
1090 
1091 
1092 /*
1093  * Read the table of contents (TOC) and TOC header if neccessary
1094  */
1095 
1096 static int
1097 updateToc()
     /* [previous][next][first][last][top][bottom][index][help] */
1098 {
1099         if (tocUpToDate)
1100                 return 0;
1101 
1102         if (GetDiskInfo() < 0)
1103                 return -EIO;
1104 
1105         if (GetToc() < 0)
1106                 return -EIO;
1107 
1108         tocUpToDate = 1;
1109         return 0;
1110 }
1111 
1112 
1113 /*
1114  * Read the table of contents header
1115  */
1116 
1117 static int
1118 GetDiskInfo()
     /* [previous][next][first][last][top][bottom][index][help] */
1119 {
1120         int retry;
1121 
1122         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1123         {
1124                 outb(MCMD_GET_DISK_INFO, MCDPORT(0));
1125                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1126                         break;
1127         }
1128 
1129         if (retry >= MCD_RETRY_ATTEMPTS)
1130                 return -1;
1131 
1132         if (getValue(&DiskInfo.first) < 0) return -1;
1133         if (getValue(&DiskInfo.last) < 0) return -1;
1134 
1135         DiskInfo.first = bcd2bin(DiskInfo.first);
1136         DiskInfo.last = bcd2bin(DiskInfo.last);
1137 
1138         if (getValue(&DiskInfo.diskLength.min) < 0) return -1;
1139         if (getValue(&DiskInfo.diskLength.sec) < 0) return -1;
1140         if (getValue(&DiskInfo.diskLength.frame) < 0) return -1;
1141         if (getValue(&DiskInfo.firstTrack.min) < 0) return -1;
1142         if (getValue(&DiskInfo.firstTrack.sec) < 0) return -1;
1143         if (getValue(&DiskInfo.firstTrack.frame) < 0) return -1;
1144 
1145 #ifdef MCD_DEBUG
1146 printk("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",
1147         DiskInfo.first,
1148         DiskInfo.last,
1149         DiskInfo.diskLength.min,
1150         DiskInfo.diskLength.sec,
1151         DiskInfo.diskLength.frame,
1152         DiskInfo.firstTrack.min,
1153         DiskInfo.firstTrack.sec,
1154         DiskInfo.firstTrack.frame);
1155 #endif
1156 
1157         return 0;
1158 }
1159 
1160 
1161 /*
1162  * Read the table of contents (TOC)
1163  */
1164 
1165 static int
1166 GetToc()
     /* [previous][next][first][last][top][bottom][index][help] */
1167 {
1168         int i, px;
1169         int limit;
1170         int retry;
1171         struct mcd_Toc qInfo;
1172 
1173         for (i = 0; i < MAX_TRACKS; i++)
1174                 Toc[i].pointIndex = 0;
1175 
1176         i = DiskInfo.last + 3;
1177 
1178         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1179         {
1180                 outb(MCMD_STOP, MCDPORT(0));
1181                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1182                         break;
1183         }
1184 
1185         if (retry >= MCD_RETRY_ATTEMPTS)
1186                 return -1;
1187 
1188         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1189         {
1190                 outb(MCMD_SET_MODE, MCDPORT(0));
1191                 outb(0x05, MCDPORT(0));                 /* mode: toc */
1192                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1193                         break;
1194         }
1195 
1196         if (retry >= MCD_RETRY_ATTEMPTS)
1197                 return -1;
1198 
1199         for (limit = 300; limit > 0; limit--)
1200         {
1201                 if (GetQChannelInfo(&qInfo) < 0)
1202                         break;
1203 
1204                 px = bcd2bin(qInfo.pointIndex);
1205                 if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
1206                         if (Toc[px].pointIndex == 0)
1207                         {
1208                                 Toc[px] = qInfo;
1209                                 i--;
1210                         }
1211 
1212                 if (i <= 0)
1213                         break;
1214         }
1215 
1216         Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
1217 
1218         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1219         {
1220                 outb(MCMD_SET_MODE, MCDPORT(0));
1221                 outb(0x01, MCDPORT(0));
1222                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1223                         break;
1224         }
1225 
1226 #ifdef MCD_DEBUG
1227 for (i = 1; i <= DiskInfo.last; i++)
1228 printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
1229 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1230 Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
1231 Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1232 for (i = 100; i < 103; i++)
1233 printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
1234 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1235 Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
1236 Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1237 #endif
1238 
1239         return limit > 0 ? 0 : -1;
1240 }
1241 

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