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         if (result[0] == result[1] && result[1] == result[2])
 857                 return mem_start;
 858 
 859         printk("mcd: Mitsumi version : %02X %c %x\n",
 860                result[0],result[1],result[2]);
 861 
 862 
 863         mcdVersion=result[2];
 864 
 865         if (mcdVersion >=4)
 866                 outb(4,MCDPORT(2));     /* magic happens */
 867 
 868         /* don't get the IRQ until we know for sure the drive is there */
 869 
 870         if (irqaction(MCD_INTR_NR,  &mcd_sigaction))
 871         {
 872                 printk("mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", MCD_INTR_NR);
 873                 return mem_start;
 874         }
 875         snarf_region(mcd_port, 4);
 876         mcdPresent = 1;
 877         printk("mcd: Mitsumi CD-ROM Drive present at addr %x, irq %d\n",
 878                mcd_port, mcd_irq);
 879         return mem_start;
 880 }
 881 
 882 
 883 static void
 884 hsg2msf(long hsg, struct msf *msf)
     /* [previous][next][first][last][top][bottom][index][help] */
 885 {
 886         hsg += 150;
 887         msf -> min = hsg / 4500;
 888         hsg %= 4500;
 889         msf -> sec = hsg / 75;
 890         msf -> frame = hsg % 75;
 891 
 892         bin2bcd(&msf -> min);           /* convert to BCD */
 893         bin2bcd(&msf -> sec);
 894         bin2bcd(&msf -> frame);
 895 }
 896 
 897 
 898 static void
 899 bin2bcd(unsigned char *p)
     /* [previous][next][first][last][top][bottom][index][help] */
 900 {
 901         int u, t;
 902 
 903         u = *p % 10;
 904         t = *p / 10;
 905         *p = u | (t << 4);
 906 }
 907 
 908 static int
 909 bcd2bin(unsigned char bcd)
     /* [previous][next][first][last][top][bottom][index][help] */
 910 {
 911         return (bcd >> 4) * 10 + (bcd & 0xF);
 912 }
 913 
 914 
 915 /*
 916  * See if a status is ready from the drive and return it
 917  * if it is ready.
 918  */
 919 
 920 static int
 921 mcdStatus(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 922 {
 923         int i;
 924         int st;
 925 
 926         st = inb(MCDPORT(1)) & MFL_STATUS;
 927         if (!st)
 928         {
 929                 i = inb(MCDPORT(0)) & 0xFF;
 930                 return i;
 931         }
 932         else
 933                 return -1;
 934 }
 935 
 936 
 937 /*
 938  * Send a play or read command to the drive
 939  */
 940 
 941 static void
 942 sendMcdCmd(int cmd, struct mcd_Play_msf *params)
     /* [previous][next][first][last][top][bottom][index][help] */
 943 {
 944         outb(cmd, MCDPORT(0));
 945         outb(params -> start.min, MCDPORT(0));
 946         outb(params -> start.sec, MCDPORT(0));
 947         outb(params -> start.frame, MCDPORT(0));
 948         outb(params -> end.min, MCDPORT(0));
 949         outb(params -> end.sec, MCDPORT(0));
 950         outb(params -> end.frame, MCDPORT(0));
 951 }
 952 
 953 
 954 /*
 955  * Timer interrupt routine to test for status ready from the drive.
 956  * (see the next routine)
 957  */
 958 
 959 static void
 960 mcdStatTimer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 961 {
 962         if (!(inb(MCDPORT(1)) & MFL_STATUS))
 963         {
 964                 wake_up(&mcd_waitq);
 965                 return;
 966         }
 967 
 968         McdTimeout--;
 969         if (McdTimeout <= 0)
 970         {
 971                 wake_up(&mcd_waitq);
 972                 return;
 973         }
 974 
 975         SET_TIMER(mcdStatTimer, 1);
 976 }
 977 
 978 
 979 /*
 980  * Wait for a status to be returned from the drive.  The actual test
 981  * (see routine above) is done by the timer interrupt to avoid
 982  * excessive rescheduling.
 983  */
 984 
 985 static int
 986 getMcdStatus(int timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
 987 {
 988         int st;
 989 
 990         McdTimeout = timeout;
 991         SET_TIMER(mcdStatTimer, 1);
 992         sleep_on(&mcd_waitq);
 993         if (McdTimeout <= 0)
 994                 return -1;
 995 
 996         st = inb(MCDPORT(0)) & 0xFF;
 997         if (st == 0xFF)
 998                 return -1;
 999 
1000         if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
1001                 /* XXX might be an error? look at q-channel? */
1002                 audioStatus = CDROM_AUDIO_COMPLETED;
1003 
1004         if (st & MST_DSK_CHG)
1005         {
1006                 mcdDiskChanged = 1;
1007                 tocUpToDate = 0;
1008                 audioStatus = CDROM_AUDIO_NO_STATUS;
1009         }
1010 
1011         return st;
1012 }
1013 
1014 
1015 /*
1016  * Read a value from the drive.  Should return quickly, so a busy wait
1017  * is used to avoid excessive rescheduling.
1018  */
1019 
1020 static int
1021 getValue(unsigned char *result)
     /* [previous][next][first][last][top][bottom][index][help] */
1022 {
1023         int count;
1024         int s;
1025 
1026         for (count = 0; count < 2000; count++)
1027                 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1028                         break;
1029 
1030         if (count >= 2000)
1031         {
1032                 printk("mcd: getValue timeout\n");
1033                 return -1;
1034         }
1035 
1036         s = inb(MCDPORT(0)) & 0xFF;
1037         *result = (unsigned char) s;
1038         return 0;
1039 }
1040 
1041 
1042 /*
1043  * Read the current Q-channel info.  Also used for reading the
1044  * table of contents.
1045  */
1046 
1047 int
1048 GetQChannelInfo(struct mcd_Toc *qp)
     /* [previous][next][first][last][top][bottom][index][help] */
1049 {
1050         unsigned char notUsed;
1051         int retry;
1052 
1053         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1054         {
1055                 outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
1056                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1057                         break;
1058         }
1059 
1060         if (retry >= MCD_RETRY_ATTEMPTS)
1061                 return -1;
1062 
1063         if (getValue(&qp -> ctrl_addr) < 0) return -1;
1064         if (getValue(&qp -> track) < 0) return -1;
1065         if (getValue(&qp -> pointIndex) < 0) return -1;
1066         if (getValue(&qp -> trackTime.min) < 0) return -1;
1067         if (getValue(&qp -> trackTime.sec) < 0) return -1;
1068         if (getValue(&qp -> trackTime.frame) < 0) return -1;
1069         if (getValue(&notUsed) < 0) return -1;
1070         if (getValue(&qp -> diskTime.min) < 0) return -1;
1071         if (getValue(&qp -> diskTime.sec) < 0) return -1;
1072         if (getValue(&qp -> diskTime.frame) < 0) return -1;
1073 
1074         return 0;
1075 }
1076 
1077 
1078 /*
1079  * Read the table of contents (TOC) and TOC header if neccessary
1080  */
1081 
1082 static int
1083 updateToc()
     /* [previous][next][first][last][top][bottom][index][help] */
1084 {
1085         if (tocUpToDate)
1086                 return 0;
1087 
1088         if (GetDiskInfo() < 0)
1089                 return -EIO;
1090 
1091         if (GetToc() < 0)
1092                 return -EIO;
1093 
1094         tocUpToDate = 1;
1095         return 0;
1096 }
1097 
1098 
1099 /*
1100  * Read the table of contents header
1101  */
1102 
1103 static int
1104 GetDiskInfo()
     /* [previous][next][first][last][top][bottom][index][help] */
1105 {
1106         int retry;
1107 
1108         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1109         {
1110                 outb(MCMD_GET_DISK_INFO, MCDPORT(0));
1111                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1112                         break;
1113         }
1114 
1115         if (retry >= MCD_RETRY_ATTEMPTS)
1116                 return -1;
1117 
1118         if (getValue(&DiskInfo.first) < 0) return -1;
1119         if (getValue(&DiskInfo.last) < 0) return -1;
1120 
1121         DiskInfo.first = bcd2bin(DiskInfo.first);
1122         DiskInfo.last = bcd2bin(DiskInfo.last);
1123 
1124         if (getValue(&DiskInfo.diskLength.min) < 0) return -1;
1125         if (getValue(&DiskInfo.diskLength.sec) < 0) return -1;
1126         if (getValue(&DiskInfo.diskLength.frame) < 0) return -1;
1127         if (getValue(&DiskInfo.firstTrack.min) < 0) return -1;
1128         if (getValue(&DiskInfo.firstTrack.sec) < 0) return -1;
1129         if (getValue(&DiskInfo.firstTrack.frame) < 0) return -1;
1130 
1131 #ifdef MCD_DEBUG
1132 printk("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",
1133         DiskInfo.first,
1134         DiskInfo.last,
1135         DiskInfo.diskLength.min,
1136         DiskInfo.diskLength.sec,
1137         DiskInfo.diskLength.frame,
1138         DiskInfo.firstTrack.min,
1139         DiskInfo.firstTrack.sec,
1140         DiskInfo.firstTrack.frame);
1141 #endif
1142 
1143         return 0;
1144 }
1145 
1146 
1147 /*
1148  * Read the table of contents (TOC)
1149  */
1150 
1151 static int
1152 GetToc()
     /* [previous][next][first][last][top][bottom][index][help] */
1153 {
1154         int i, px;
1155         int limit;
1156         int retry;
1157         struct mcd_Toc qInfo;
1158 
1159         for (i = 0; i < MAX_TRACKS; i++)
1160                 Toc[i].pointIndex = 0;
1161 
1162         i = DiskInfo.last + 3;
1163 
1164         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1165         {
1166                 outb(MCMD_STOP, MCDPORT(0));
1167                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1168                         break;
1169         }
1170 
1171         if (retry >= MCD_RETRY_ATTEMPTS)
1172                 return -1;
1173 
1174         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1175         {
1176                 outb(MCMD_SET_MODE, MCDPORT(0));
1177                 outb(0x05, MCDPORT(0));                 /* mode: toc */
1178                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1179                         break;
1180         }
1181 
1182         if (retry >= MCD_RETRY_ATTEMPTS)
1183                 return -1;
1184 
1185         for (limit = 300; limit > 0; limit--)
1186         {
1187                 if (GetQChannelInfo(&qInfo) < 0)
1188                         break;
1189 
1190                 px = bcd2bin(qInfo.pointIndex);
1191                 if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
1192                         if (Toc[px].pointIndex == 0)
1193                         {
1194                                 Toc[px] = qInfo;
1195                                 i--;
1196                         }
1197 
1198                 if (i <= 0)
1199                         break;
1200         }
1201 
1202         Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
1203 
1204         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++)
1205         {
1206                 outb(MCMD_SET_MODE, MCDPORT(0));
1207                 outb(0x01, MCDPORT(0));
1208                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1209                         break;
1210         }
1211 
1212 #ifdef MCD_DEBUG
1213 for (i = 1; i <= DiskInfo.last; i++)
1214 printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
1215 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1216 Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
1217 Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1218 for (i = 100; i < 103; i++)
1219 printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
1220 i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1221 Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
1222 Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1223 #endif
1224 
1225         return limit > 0 ? 0 : -1;
1226 }
1227 

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