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:     /* Eject the drive - N/A */
 480                 return 0;
 481 
 482         default:
 483                 return -EINVAL;
 484         }
 485 }
 486 
 487 
 488 /*
 489  * Take care of the different block sizes between cdrom and Linux.
 490  * When Linux gets variable block sizes this will probably go away.
 491  */
 492 
 493 static void
 494 mcd_transfer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 495 {
 496         long offs;
 497 
 498         while (CURRENT -> nr_sectors > 0 && mcd_bn == CURRENT -> sector / 4)
 499         {
 500                 offs = (CURRENT -> sector & 3) * 512;
 501                 memcpy(CURRENT -> buffer, mcd_buf + offs, 512);
 502                 CURRENT -> nr_sectors--;
 503                 CURRENT -> sector++;
 504                 CURRENT -> buffer += 512;
 505         }
 506 }
 507 
 508 
 509 /*
 510  * We only seem to get interrupts after an error.
 511  * Just take the interrupt and clear out the status reg.
 512  */
 513 
 514 static void
 515 mcd_interrupt(int unused)
     /* [previous][next][first][last][top][bottom][index][help] */
 516 {
 517         int st;
 518 
 519         st = inb(MCDPORT(1)) & 0xFF;
 520         if (st != 0xFF)
 521         {
 522                 st = inb(MCDPORT(0)) & 0xFF;
 523 #if 0
 524                 printk("<int-%02X>", st);
 525 #endif
 526         }
 527 }
 528 
 529 
 530 /*
 531  * I/O request routine called from Linux kernel.
 532  */
 533 
 534 static void
 535 do_mcd_request(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 536 {
 537         unsigned int block,dev;
 538         unsigned int nsect;
 539 
 540 repeat:
 541         if (!(CURRENT) || CURRENT->dev < 0) return;
 542         INIT_REQUEST;
 543         dev = MINOR(CURRENT->dev);
 544         block = CURRENT->sector;
 545         nsect = CURRENT->nr_sectors;
 546 
 547         if (CURRENT == NULL || CURRENT -> sector == -1)
 548                 return;
 549 
 550         if (CURRENT -> cmd != READ)
 551         {
 552                 printk("mcd: bad cmd %d\n", CURRENT -> cmd);
 553                 end_request(0);
 554                 goto repeat;
 555         }
 556 
 557         mcd_transfer();
 558 
 559         /* if we satisfied the request from the buffer, we're done. */
 560 
 561         if (CURRENT -> nr_sectors == 0)
 562         {
 563                 end_request(1);
 564                 goto repeat;
 565         }
 566 
 567         McdTries = MCD_RETRY_ATTEMPTS;
 568         mcd_start();
 569 }
 570 
 571 
 572 /*
 573  * Start the I/O for the cdrom. Handle retry count.
 574  */
 575 
 576 static void
 577 mcd_start()
     /* [previous][next][first][last][top][bottom][index][help] */
 578 {
 579         if (McdTries == 0)
 580         {
 581                 printk("mcd: read failed after %d tries\n", MCD_RETRY_ATTEMPTS);
 582                 end_request(0);
 583                 SET_TIMER(do_mcd_request, 1);   /* wait a bit, try again */
 584                 return;
 585         }
 586 
 587         McdTries--;
 588         outb(0x40, MCDPORT(0));         /* get status */
 589         McdTimeout = MCD_STATUS_DELAY;
 590         SET_TIMER(mcd_status, 1);
 591 }
 592 
 593 
 594 /*
 595  * Called from the timer to check the results of the get-status cmd.
 596  * On success, send the set-mode command.
 597  */
 598 
 599 static void
 600 mcd_status()
     /* [previous][next][first][last][top][bottom][index][help] */
 601 {
 602         int st;
 603 
 604         McdTimeout--;
 605         st = mcdStatus();
 606         if (st == -1)
 607         {
 608                 if (McdTimeout == 0)
 609                 {
 610                         printk("mcd: status timed out\n");
 611                         SET_TIMER(mcd_start, 1);        /* wait a bit, try again */
 612                         return;
 613                 }
 614 
 615                 SET_TIMER(mcd_status, 1);
 616                 return;
 617         }
 618 
 619         if (st & MST_DSK_CHG)
 620         {
 621                 mcdDiskChanged = 1;
 622         }
 623         
 624         if ((st & MST_READY) == 0)
 625         {
 626                 printk("mcd: disk removed\n");
 627                 mcdDiskChanged = 1;             
 628                 end_request(0);
 629                 do_mcd_request();
 630                 return;
 631         }
 632 
 633         outb(0x50, MCDPORT(0)); /* set mode */
 634         outb(0x01, MCDPORT(0)); /* mode = cooked data */
 635         McdTimeout = 100;
 636         SET_TIMER(mcd_read_cmd, 1);
 637 }
 638 
 639 
 640 /*
 641  * Check the result of the set-mode command.  On success, send the
 642  * read-data command.
 643  */
 644 
 645 static void
 646 mcd_read_cmd()
     /* [previous][next][first][last][top][bottom][index][help] */
 647 {
 648         int st;
 649         long block;
 650         struct mcd_Play_msf mcdcmd;
 651 
 652         McdTimeout--;
 653         st = mcdStatus();
 654 
 655         if (st & MST_DSK_CHG)
 656         {
 657                 mcdDiskChanged = 1;
 658         }
 659         
 660         if (st == -1)
 661         {
 662                 if (McdTimeout == 0)
 663                 {
 664                         printk("mcd: set mode timed out\n");
 665                         SET_TIMER(mcd_start, 1);        /* wait a bit, try again */
 666                         return;
 667                 }
 668 
 669                 SET_TIMER(mcd_read_cmd, 1);
 670                 return;
 671         }
 672 
 673         mcd_bn = -1;                    /* purge our buffer */
 674         block = CURRENT -> sector / 4;
 675         hsg2msf(block, &mcdcmd.start);  /* cvt to msf format */
 676 
 677         mcdcmd.end.min = 0;
 678         mcdcmd.end.sec = 0;
 679         mcdcmd.end.frame = 1;
 680 
 681         sendMcdCmd(MCMD_PLAY_READ, &mcdcmd);    /* read command */
 682         McdTimeout = 200;
 683         SET_TIMER(mcd_data, 1);
 684 }
 685 
 686 
 687 /*
 688  * Check the completion of the read-data command.  On success, read
 689  * the 2048 bytes of data from the disk into our buffer.
 690  */
 691 
 692 static void
 693 mcd_data()
     /* [previous][next][first][last][top][bottom][index][help] */
 694 {
 695         int i;
 696 
 697         McdTimeout--;
 698         cli();
 699         i =inb(MCDPORT(1)) & (MFL_STATUS | MFL_DATA);
 700         if (i == MFL_DATA)
 701         {
 702                 printk("mcd: read failed\n");
 703 #ifdef MCD_DEBUG
 704                 printk("got 0xB %02X\n", inb(MCDPORT(0)) & 0xFF);
 705 #endif
 706                 SET_TIMER(mcd_start, 1);
 707                 sti();
 708                 return;
 709         }
 710         
 711         if (i == (MFL_STATUS | MFL_DATA))
 712         {
 713                 if (McdTimeout == 0)
 714                 {
 715                         printk("mcd: data timeout, retrying\n");
 716                         SET_TIMER(mcd_start, 1);
 717                 }
 718                 
 719                 else
 720                         SET_TIMER(mcd_data, 1);
 721                 
 722                 sti();
 723                 return;
 724         }
 725 
 726         CLEAR_TIMER;
 727         READ_DATA(MCDPORT(0), &mcd_buf[0], 2048);
 728         sti();
 729 
 730         mcd_bn = CURRENT -> sector / 4;
 731         mcd_transfer();
 732         end_request(1);
 733         SET_TIMER(do_mcd_request, 1);
 734 }
 735 
 736 
 737 /*
 738  * Open the device special file.  Check that a disk is in.
 739  */
 740 
 741 int
 742 mcd_open(struct inode *ip, struct file *fp)
     /* [previous][next][first][last][top][bottom][index][help] */
 743 {
 744         int st;
 745 
 746         if (mcdPresent == 0)
 747                 return -ENXIO;                  /* no hardware */
 748 
 749         st = statusCmd();                       /* check drive status */
 750         if (st == -1)
 751                 return -EIO;                    /* drive doesn't respond */
 752 
 753         if ((st & MST_READY) == 0)              /* no disk in drive */
 754         {
 755                 printk("mcd: no disk in drive\n");
 756                 return -EIO;
 757         }
 758 
 759         if (updateToc() < 0)
 760                 return -EIO;
 761 
 762         return 0;
 763 }
 764 
 765 
 766 /*
 767  * On close, we flush all mcd blocks from the buffer cache.
 768  */
 769 
 770 static void
 771 mcd_release(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 772 {
 773         mcd_bn = -1;
 774         sync_dev(inode->i_rdev);
 775         invalidate_buffers(inode -> i_rdev);
 776 }
 777 
 778 
 779 static struct file_operations mcd_fops = {
 780         NULL,                   /* lseek - default */
 781         block_read,             /* read - general block-dev read */
 782         block_write,            /* write - general block-dev write */
 783         NULL,                   /* readdir - bad */
 784         NULL,                   /* select */
 785         mcd_ioctl,              /* ioctl */
 786         NULL,                   /* mmap */
 787         mcd_open,               /* open */
 788         mcd_release             /* release */
 789 };
 790 
 791 
 792 /*
 793  * MCD interrupt descriptor
 794  */
 795 
 796 static struct sigaction mcd_sigaction = {
 797         mcd_interrupt,
 798         0,
 799         SA_INTERRUPT,
 800         NULL
 801 };
 802 
 803 
 804 /*
 805  * Test for presence of drive and initialize it.  Called at boot time.
 806  */
 807 
 808 unsigned long
 809 mcd_init(unsigned long mem_start, unsigned long mem_end)
     /* [previous][next][first][last][top][bottom][index][help] */
 810 {
 811         int count;
 812         unsigned char result[3];
 813 
 814         if (register_blkdev(MAJOR_NR, "mcd", &mcd_fops) != 0)
 815         {
 816                 printk("mcd: Unable to get major %d for Mitsumi CD-ROM\n",
 817                        MAJOR_NR);
 818                 return mem_start;
 819         }
 820 
 821         if (check_region(mcd_port, 4)) {
 822           printk("mcd: Init failed, I/O port (%X) already in use\n",
 823                  mcd_port);
 824           return mem_start;
 825         }
 826           
 827         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 828         read_ahead[MAJOR_NR] = 4;
 829 
 830         /* check for card */
 831 
 832         outb(0, MCDPORT(1));                    /* send reset */
 833         for (count = 0; count < 1000000; count++)
 834                 (void) inb(MCDPORT(1));         /* delay a bit */
 835 
 836         outb(0x40, MCDPORT(0));                 /* send get-stat cmd */
 837         for (count = 0; count < 1000000; count++)
 838                 if (!(inb(MCDPORT(1)) & MFL_STATUS))
 839                         break;
 840 
 841         if (count >= 1000000) {
 842                 printk("mcd: Init failed. No mcd device at 0x%x irq %d\n",
 843                      mcd_port, mcd_irq);
 844                 return mem_start;
 845         }
 846         count = inb(MCDPORT(0));                /* pick up the status */
 847         
 848         outb(MCMD_GET_VERSION,MCDPORT(0));
 849         for(count=0;count<3;count++)
 850                 if(getValue(result+count)) {
 851                         printk("mcd: mitsumi get version failed at 0x%d\n",
 852                                mcd_port);
 853                         return mem_start;
 854                 }       
 855                                         
 856         printk("mcd: Mitsumi version : %02X %c %x\n",
 857                result[0],result[1],result[2]);
 858 
 859 
 860         mcdVersion=result[2];
 861 
 862         if (mcdVersion >=4)
 863                 outb(4,MCDPORT(2));     /* magic happens */
 864 
 865         /* don't get the IRQ until we know for sure the drive is there */
 866 
 867         if (irqaction(MCD_INTR_NR,  &mcd_sigaction))
 868         {
 869                 printk("mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", MCD_INTR_NR);
 870                 return mem_start;
 871         }
 872         snarf_region(mcd_port, 4);
 873         mcdPresent = 1;
 874         printk("mcd: Mitsumi CD-ROM Drive present at addr %x, irq %d\n",
 875                mcd_port, mcd_irq);
 876         return mem_start;
 877 }
 878 
 879 
 880 static void
 881 hsg2msf(long hsg, struct msf *msf)
     /* [previous][next][first][last][top][bottom][index][help] */
 882 {
 883         hsg += 150;
 884         msf -> min = hsg / 4500;
 885         hsg %= 4500;
 886         msf -> sec = hsg / 75;
 887         msf -> frame = hsg % 75;
 888 
 889         bin2bcd(&msf -> min);           /* convert to BCD */
 890         bin2bcd(&msf -> sec);
 891         bin2bcd(&msf -> frame);
 892 }
 893 
 894 
 895 static void
 896 bin2bcd(unsigned char *p)
     /* [previous][next][first][last][top][bottom][index][help] */
 897 {
 898         int u, t;
 899 
 900         u = *p % 10;
 901         t = *p / 10;
 902         *p = u | (t << 4);
 903 }
 904 
 905 static int
 906 bcd2bin(unsigned char bcd)
     /* [previous][next][first][last][top][bottom][index][help] */
 907 {
 908         return (bcd >> 4) * 10 + (bcd & 0xF);
 909 }
 910 
 911 
 912 /*
 913  * See if a status is ready from the drive and return it
 914  * if it is ready.
 915  */
 916 
 917 static int
 918 mcdStatus(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 919 {
 920         int i;
 921         int st;
 922 
 923         st = inb(MCDPORT(1)) & MFL_STATUS;
 924         if (!st)
 925         {
 926                 i = inb(MCDPORT(0)) & 0xFF;
 927                 return i;
 928         }
 929         else
 930                 return -1;
 931 }
 932 
 933 
 934 /*
 935  * Send a play or read command to the drive
 936  */
 937 
 938 static void
 939 sendMcdCmd(int cmd, struct mcd_Play_msf *params)
     /* [previous][next][first][last][top][bottom][index][help] */
 940 {
 941         outb(cmd, MCDPORT(0));
 942         outb(params -> start.min, MCDPORT(0));
 943         outb(params -> start.sec, MCDPORT(0));
 944         outb(params -> start.frame, MCDPORT(0));
 945         outb(params -> end.min, MCDPORT(0));
 946         outb(params -> end.sec, MCDPORT(0));
 947         outb(params -> end.frame, MCDPORT(0));
 948 }
 949 
 950 
 951 /*
 952  * Timer interrupt routine to test for status ready from the drive.
 953  * (see the next routine)
 954  */
 955 
 956 static void
 957 mcdStatTimer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 958 {
 959         if (!(inb(MCDPORT(1)) & MFL_STATUS))
 960         {
 961                 wake_up(&mcd_waitq);
 962                 return;
 963         }
 964 
 965         McdTimeout--;
 966         if (McdTimeout <= 0)
 967         {
 968                 wake_up(&mcd_waitq);
 969                 return;
 970         }
 971 
 972         SET_TIMER(mcdStatTimer, 1);
 973 }
 974 
 975 
 976 /*
 977  * Wait for a status to be returned from the drive.  The actual test
 978  * (see routine above) is done by the timer interrupt to avoid
 979  * excessive rescheduling.
 980  */
 981 
 982 static int
 983 getMcdStatus(int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 984 {
 985         int st;
 986 
 987         McdTimeout = timeout;
 988         SET_TIMER(mcdStatTimer, 1);
 989         sleep_on(&mcd_waitq);
 990         if (McdTimeout <= 0)
 991                 return -1;
 992 
 993         st = inb(MCDPORT(0)) & 0xFF;
 994         if (st == 0xFF)
 995                 return -1;
 996 
 997         if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
 998                 /* XXX might be an error? look at q-channel? */
 999                 audioStatus = CDROM_AUDIO_COMPLETED;
1000 
1001         if (st & MST_DSK_CHG)
1002         {
1003                 mcdDiskChanged = 1;
1004                 tocUpToDate = 0;
1005                 audioStatus = CDROM_AUDIO_NO_STATUS;
1006         }
1007 
1008         return st;
1009 }
1010 
1011 
1012 /*
1013  * Read a value from the drive.  Should return quickly, so a busy wait
1014  * is used to avoid excessive rescheduling.
1015  */
1016 
1017 static int
1018 getValue(unsigned char *result)
     /* [previous][next][first][last][top][bottom][index][help] */
1019 {
1020         int count;
1021         int s;
1022 
1023         for (count = 0; count < 2000; count++)
1024                 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1025                         break;
1026 
1027         if (count >= 2000)
1028         {
1029                 printk("mcd: getValue timeout\n");
1030                 return -1;
1031         }
1032 
1033         s = inb(MCDPORT(0)) & 0xFF;
1034         *result = (unsigned char) s;
1035         return 0;
1036 }
1037 
1038 
1039 /*
1040  * Read the current Q-channel info.  Also used for reading the
1041  * table of contents.
1042  */
1043 
1044 int
1045 GetQChannelInfo(struct mcd_Toc *qp)
     /* [previous][next][first][last][top][bottom][index][help] */
1046 {
1047         unsigned char notUsed;
1048         int retry;
1049 
1050         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1051         {
1052                 outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
1053                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1054                         break;
1055         }
1056 
1057         if (retry >= MCD_RETRY_ATTEMPTS)
1058                 return -1;
1059 
1060         if (getValue(&qp -> ctrl_addr) < 0) return -1;
1061         if (getValue(&qp -> track) < 0) return -1;
1062         if (getValue(&qp -> pointIndex) < 0) return -1;
1063         if (getValue(&qp -> trackTime.min) < 0) return -1;
1064         if (getValue(&qp -> trackTime.sec) < 0) return -1;
1065         if (getValue(&qp -> trackTime.frame) < 0) return -1;
1066         if (getValue(&notUsed) < 0) return -1;
1067         if (getValue(&qp -> diskTime.min) < 0) return -1;
1068         if (getValue(&qp -> diskTime.sec) < 0) return -1;
1069         if (getValue(&qp -> diskTime.frame) < 0) return -1;
1070 
1071         return 0;
1072 }
1073 
1074 
1075 /*
1076  * Read the table of contents (TOC) and TOC header if neccessary
1077  */
1078 
1079 static int
1080 updateToc()
     /* [previous][next][first][last][top][bottom][index][help] */
1081 {
1082         if (tocUpToDate)
1083                 return 0;
1084 
1085         if (GetDiskInfo() < 0)
1086                 return -EIO;
1087 
1088         if (GetToc() < 0)
1089                 return -EIO;
1090 
1091         tocUpToDate = 1;
1092         return 0;
1093 }
1094 
1095 
1096 /*
1097  * Read the table of contents header
1098  */
1099 
1100 static int
1101 GetDiskInfo()
     /* [previous][next][first][last][top][bottom][index][help] */
1102 {
1103         int retry;
1104 
1105         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1106         {
1107                 outb(MCMD_GET_DISK_INFO, MCDPORT(0));
1108                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1109                         break;
1110         }
1111 
1112         if (retry >= MCD_RETRY_ATTEMPTS)
1113                 return -1;
1114 
1115         if (getValue(&DiskInfo.first) < 0) return -1;
1116         if (getValue(&DiskInfo.last) < 0) return -1;
1117 
1118         DiskInfo.first = bcd2bin(DiskInfo.first);
1119         DiskInfo.last = bcd2bin(DiskInfo.last);
1120 
1121         if (getValue(&DiskInfo.diskLength.min) < 0) return -1;
1122         if (getValue(&DiskInfo.diskLength.sec) < 0) return -1;
1123         if (getValue(&DiskInfo.diskLength.frame) < 0) return -1;
1124         if (getValue(&DiskInfo.firstTrack.min) < 0) return -1;
1125         if (getValue(&DiskInfo.firstTrack.sec) < 0) return -1;
1126         if (getValue(&DiskInfo.firstTrack.frame) < 0) return -1;
1127 
1128 #ifdef MCD_DEBUG
1129 printk("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",
1130         DiskInfo.first,
1131         DiskInfo.last,
1132         DiskInfo.diskLength.min,
1133         DiskInfo.diskLength.sec,
1134         DiskInfo.diskLength.frame,
1135         DiskInfo.firstTrack.min,
1136         DiskInfo.firstTrack.sec,
1137         DiskInfo.firstTrack.frame);
1138 #endif
1139 
1140         return 0;
1141 }
1142 
1143 
1144 /*
1145  * Read the table of contents (TOC)
1146  */
1147 
1148 static int
1149 GetToc()
     /* [previous][next][first][last][top][bottom][index][help] */
1150 {
1151         int i, px;
1152         int limit;
1153         int retry;
1154         struct mcd_Toc qInfo;
1155 
1156         for (i = 0; i < MAX_TRACKS; i++)
1157                 Toc[i].pointIndex = 0;
1158 
1159         i = DiskInfo.last + 3;
1160 
1161         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1162         {
1163                 outb(MCMD_STOP, MCDPORT(0));
1164                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1165                         break;
1166         }
1167 
1168         if (retry >= MCD_RETRY_ATTEMPTS)
1169                 return -1;
1170 
1171         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1172         {
1173                 outb(MCMD_SET_MODE, MCDPORT(0));
1174                 outb(0x05, MCDPORT(0));                 /* mode: toc */
1175                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1176                         break;
1177         }
1178 
1179         if (retry >= MCD_RETRY_ATTEMPTS)
1180                 return -1;
1181 
1182         for (limit = 300; limit > 0; limit--)
1183         {
1184                 if (GetQChannelInfo(&qInfo) < 0)
1185                         break;
1186 
1187                 px = bcd2bin(qInfo.pointIndex);
1188                 if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
1189                         if (Toc[px].pointIndex == 0)
1190                         {
1191                                 Toc[px] = qInfo;
1192                                 i--;
1193                         }
1194 
1195                 if (i <= 0)
1196                         break;
1197         }
1198 
1199         Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
1200 
1201         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1202         {
1203                 outb(MCMD_SET_MODE, MCDPORT(0));
1204                 outb(0x01, MCDPORT(0));
1205                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1206                         break;
1207         }
1208 
1209 #ifdef MCD_DEBUG
1210 for (i = 1; i <= DiskInfo.last; i++)
1211 printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
1212 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1213 Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
1214 Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1215 for (i = 100; i < 103; i++)
1216 printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
1217 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1218 Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
1219 Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1220 #endif
1221 
1222         return limit > 0 ? 0 : -1;
1223 }
1224 

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