| | 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 | |