⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mcd.c.txt

📁 Linux块设备驱动分析与模拟实现
💻 TXT
📖 第 1 页 / 共 3 页
字号:
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)
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)
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)
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()
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()
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()
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()
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)
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)
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)
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 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -