Ticket #4025: cdromeject.diff

File cdromeject.diff, 5.1 KB (added by maverik044 <level42@…>, 13 years ago)
  • mythtv/libs/libmyth/mythcdrom-linux.cpp

    old new public: 
    3131    virtual bool isSameDevice(const QString &path);
    3232    virtual MediaError lock(void);
    3333    virtual MediaError unlock(void);
     34    virtual int driveStatus(void);
    3435};
    3536
    3637MythCDROM *GetMythCDROMLinux(QObject* par, const char* devicePath,
    MythCDROM *GetMythCDROMLinux(QObject* pa 
    3940    return new MythCDROMLinux(par, devicePath, SuperMount, AllowEject);
    4041}
    4142
     43struct event_header {
     44        unsigned char data_len[2];
     45#ifdef WORDS_BIGENDIAN
     46        unsigned char nea                : 1;
     47        unsigned char reserved1          : 4;
     48        unsigned char notification_class : 3;
     49#else
     50        unsigned char notification_class : 3;
     51        unsigned char reserved1          : 4;
     52        unsigned char nea                : 1;
     53#endif
     54        unsigned char supp_event_class;
     55};
     56 
     57struct media_event_desc {
     58#ifdef WORDS_BIGENDIAN
     59        unsigned char reserved1          : 4;
     60        unsigned char media_event_code   : 4;
     61        unsigned char reserved2          : 6;
     62        unsigned char media_present      : 1;
     63        unsigned char door_open          : 1;
     64#else
     65        unsigned char media_event_code   : 4;
     66        unsigned char reserved1          : 4;
     67        unsigned char door_open          : 1;
     68        unsigned char media_present      : 1;
     69        unsigned char reserved2          : 6;
     70#endif
     71        unsigned char start_slot;
     72        unsigned char end_slot;
     73};
     74
     75
     76// Routine to determine drive status
     77// If the CDROM is managed by the SCSI driver, then CDROM_DRIVE_STATUS
     78// as reported by ioctl will always return CDS_TRAY_OPEN if the tray is
     79// closed with no media.  To determine the actual drive status we need
     80// to ask the drive directly by sending a packet to the drive.
     81// Note that in recent kernels, whether you have a IDE/ATA/SATA or SCSI
     82// CDROM, the drive is managed by the SCSI driver and therefore needs
     83// this work around.  This code is based on the routine cdrom_get_media_event
     84// in cdrom.c of the linux kernel
     85
     86int MythCDROMLinux::driveStatus()
     87{
     88    int drive_status, stat;
     89    struct cdrom_generic_command cgc;
     90    unsigned char buffer[8];
     91    struct event_header *eh = (struct event_header *)buffer;
     92    struct media_event_desc *med = (struct media_event_desc *)&buffer[sizeof(struct event_header)];
     93    QString device_path = getDevicePath();   
     94 
     95    drive_status = ioctl(m_DeviceHandle, CDROM_DRIVE_STATUS, CDSL_CURRENT);
     96   
     97    if ((drive_status != CDS_TRAY_OPEN) || (!device_path.contains("/dev/scd")))
     98      return drive_status;
     99
     100    // VERBOSE(VB_MEDIA, "MythCDROMLinux::driveStatus detected SCSI managed CDROM");
     101   
     102    // If the CDROM is managed by the SCSI driver and is reporting tray open
     103    // Lets double check with the drive itself.
     104   
     105    memset(&cgc, 0, sizeof(struct cdrom_generic_command));
     106    memset(&buffer, 0, 8);
     107   
     108    cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION;
     109    cgc.cmd[1] = 1;
     110    cgc.cmd[4] = 1 << 4;
     111    cgc.cmd[8] = sizeof(buffer);
     112    cgc.quiet  = 1;
     113    cgc.buffer = buffer;
     114    cgc.buflen = sizeof(buffer);
     115    cgc.data_direction = CGC_DATA_READ;
     116   
     117    stat = ioctl(m_DeviceHandle, CDROM_SEND_PACKET, &cgc);
     118   
     119    if ((stat < 0) || eh->nea || (eh->notification_class != 0x4))
     120    {
     121      VERBOSE(VB_MEDIA, "MythCDROMLinux::driveStatus - failed to send CDROM packet");
     122      return drive_status;
     123    }
     124           
     125    if (med->media_present)
     126    {
     127//      VERBOSE(VB_MEDIA, "MythCDROMLinux::driveStatus disc ok");
     128      return CDS_DISC_OK;
     129    }
     130    else if (med->door_open)
     131    {
     132//      VERBOSE(VB_MEDIA, "MythCDROMLinux::driveStatus tray open");
     133      return CDS_TRAY_OPEN;
     134    }
     135    else
     136    {
     137//      VERBOSE(VB_MEDIA, "MythCDROMLinux::driveStatus no disc");
     138      return CDS_NO_DISC;
     139    }
     140}
     141
    42142MediaError MythCDROMLinux::eject(bool open_close)
    43143{
    44144    if (!isDeviceOpen())
    MediaError MythCDROMLinux::eject(bool op 
    54154
    55155        // This allows us to catch any drives that the OS has problems
    56156        // detecting the status of (some always report OPEN when empty)
    57         if (ioctl(m_DeviceHandle, CDROM_DRIVE_STATUS) == CDS_TRAY_OPEN)
     157        if (driveStatus() == CDS_TRAY_OPEN)
    58158            return MEDIAERR_FAILED;
    59159        else
    60160            return MEDIAERR_OK;
    MediaError MythCDROMLinux::testMedia() 
    94194    }
    95195
    96196    // Since the device was is/was open we can get it's status...
    97     int Stat = ioctl(m_DeviceHandle, CDROM_DRIVE_STATUS, CDSL_CURRENT);
     197    int Stat = driveStatus();
    98198   
    99199    // Be nice and close the device if we opened it, otherwise it might be locked when the user doesn't want it to be.
    100200    if (OpenedHere)
    MediaStatus MythCDROMLinux::checkMedia() 
    128228    if (isDeviceOpen())
    129229    {
    130230        //VERBOSE(VB_MEDIA, "MythCDROMLinux::checkMedia - Device is open...");
    131         int ret = ioctl(m_DeviceHandle, CDROM_DRIVE_STATUS, CDSL_CURRENT);
     231        int ret = driveStatus();
    132232        switch (ret)
    133233        {
    134234            case CDS_DISC_OK: