root/drivers/block/mcd.c

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

DEFINITIONS

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

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