| 43 | struct 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 | |
| 57 | struct 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 | |
| 86 | int 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 | |