5 #include <linux/cdrom.h>
7 #include <linux/iso_fs.h>
10 #include <sys/ioctl.h>
12 #include <sys/types.h>
23 #define LOC QString("MythCDROMLinux:")
26 #ifndef ASSUME_WANT_AUDIO
27 #define ASSUME_WANT_AUDIO 1 // NOLINT(cppcoreguidelines-macro-usage)
47 #if (Q_BYTE_ORDER == Q_BIG_ENDIAN)
57 #if (Q_BYTE_ORDER == Q_BIG_ENDIAN)
77 #if (Q_BYTE_ORDER == Q_BIG_ENDIAN)
92 #if (Q_BYTE_ORDER == Q_BIG_ENDIAN)
138 MythCDROM(par, DevicePath, SuperMount, AllowEject) {
162 bool SuperMount,
bool AllowEject)
164 return new MythCDROMLinux(par, devicePath, SuperMount, AllowEject);
178 int drive_status = ioctl(
m_deviceHandle, CDROM_DRIVE_STATUS, CDSL_CURRENT);
180 if (drive_status == -1)
182 LOG(VB_MEDIA, LOG_ERR,
LOC +
":driveStatus() - ioctl failed: " +
ENO);
186 if (drive_status == CDS_TRAY_OPEN &&
m_devicePath.contains(
"/dev/scd"))
200 cgc.cmd[0] = GPCMD_READ_DISC_INFO;
203 cgc.buffer =
reinterpret_cast<uint8_t*
>(&di);
205 cgc.data_direction = CGC_DATA_READ;
209 LOG(VB_MEDIA, LOG_ERR,
LOC +
210 ":hasWritableMedia() - failed to send packet to " +
m_devicePath +
ENO);
214 switch (di.m_discStatus)
224 return di.m_erasable;
246 cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION;
251 cgc.buffer =
reinterpret_cast<uint8_t*
>(&es);
253 cgc.data_direction = CGC_DATA_READ;
257 || (es.m_notificationClass != 0
x4))
259 LOG(VB_MEDIA, LOG_ERR,
LOC +
260 ":SCSIstatus() - failed to send SCSI packet to " +
m_devicePath +
ENO);
261 return CDS_TRAY_OPEN;
264 if (es.m_mediaPresent)
266 LOG(VB_MEDIA, LOG_DEBUG,
LOC +
267 ":SCSIstatus() - ioctl said tray was open, "
268 "but drive is actually closed with a disc");
273 LOG(VB_MEDIA, LOG_DEBUG,
LOC +
274 ":SCSIstatus() - tray is definitely open");
275 return CDS_TRAY_OPEN;
278 LOG(VB_MEDIA, LOG_DEBUG,
LOC +
":SCSIstatus() - ioctl said tray was open, "
279 "but drive is actually closed with no disc");
303 LOG(VB_MEDIA, LOG_DEBUG,
LOC +
":eject - Ejecting CDROM");
307 LOG(VB_MEDIA, LOG_DEBUG,
"CDROMEJECT ioctl failed" +
ENO);
312 LOG(VB_MEDIA, LOG_DEBUG,
LOC +
":eject - Loading CDROM");
317 LOG(VB_MEDIA, LOG_DEBUG,
"CDROMCLOSETRAY ioctl failed" +
ENO);
330 operator int()
const {
return m_fd; }
338 std::array<uint8_t,6> allowRmBlk {ALLOW_MEDIUM_REMOVAL, 0, 0, 0, 0, 0};
339 std::array<uint8_t,6> startStop1Blk {START_STOP, 0, 0, 0, 1, 0};
340 std::array<uint8_t,6> startStop2Blk {START_STOP, 0, 0, 0, 2, 0};
341 std::array<uint8_t,16> sense_buffer {};
342 const unsigned DID_OK = 0;
343 const unsigned DRIVER_OK = 0;
348 LOG(VB_MEDIA, LOG_DEBUG,
LOC +
":ejectSCSI");
349 if ((ioctl(fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000))
352 LOG(VB_MEDIA, LOG_DEBUG,
"SG_GET_VERSION_NUM ioctl failed" +
ENO);
356 memset(&io_hdr, 0,
sizeof(sg_io_hdr_t));
357 io_hdr.interface_id =
'S';
359 io_hdr.mx_sb_len = sense_buffer.size();
360 io_hdr.dxfer_direction = SG_DXFER_NONE;
361 io_hdr.sbp = sense_buffer.data();
362 io_hdr.timeout = 10000;
364 io_hdr.cmdp = allowRmBlk.data();
365 if (ioctl(fd, SG_IO, &io_hdr) < 0)
367 LOG(VB_MEDIA, LOG_DEBUG,
"SG_IO allowRmBlk ioctl failed" +
ENO);
370 if (io_hdr.host_status != DID_OK || io_hdr.driver_status != DRIVER_OK)
372 LOG(VB_MEDIA, LOG_DEBUG,
"SG_IO allowRmBlk failed");
376 io_hdr.cmdp = startStop1Blk.data();
377 if (ioctl(fd, SG_IO, &io_hdr) < 0)
379 LOG(VB_MEDIA, LOG_DEBUG,
"SG_IO START_STOP(start) ioctl failed" +
ENO);
382 if (io_hdr.host_status != DID_OK || io_hdr.driver_status != DRIVER_OK)
384 LOG(VB_MEDIA, LOG_DEBUG,
"SG_IO START_STOP(start) failed");
388 io_hdr.cmdp = startStop2Blk.data();
389 if (ioctl(fd, SG_IO, &io_hdr) < 0)
391 LOG(VB_MEDIA, LOG_DEBUG,
"SG_IO START_STOP(eject) ioctl failed" +
ENO);
394 if (io_hdr.host_status != DID_OK || io_hdr.driver_status != DRIVER_OK)
396 LOG(VB_MEDIA, LOG_DEBUG,
"SG_IO START_STOP(eject) failed");
401 (void)ioctl(fd, BLKRRPART);
408 return (ioctl(
m_deviceHandle, CDROM_MEDIA_CHANGED, CDSL_CURRENT) > 0);
413 return (ioctl(
m_deviceHandle, CDROM_DRIVE_STATUS, CDSL_CURRENT) ==
420 bool OpenedHere =
false;
425 LOG(VB_MEDIA, LOG_DEBUG,
LOC +
":testMedia - failed to open '" +
431 LOG(VB_MEDIA, LOG_DEBUG,
LOC +
":testMedia - Opened device");
445 LOG(VB_MEDIA, LOG_DEBUG,
LOC +
446 ":testMedia - Failed to get drive status of '" +
m_devicePath +
456 bool OpenedHere =
false;
466 LOG(VB_MEDIA, LOG_ERR,
LOC +
467 ":checkMedia() - cannot open device '" +
m_devicePath +
"' : " +
468 ENO +
"- returning UNKNOWN");
496 case CDS_DRIVE_NOT_READY:
498 " No info or drive not ready");
502 LOG(VB_GENERAL, LOG_ERR,
"Failed to get drive status of " +
521 LOG(VB_MEDIA, LOG_DEBUG,
"Disc useable, media unchanged. All good!");
539 LOG(VB_MEDIA, LOG_DEBUG,
"Disc is unmountable?");
557 LOG(VB_MEDIA, LOG_INFO,
"Found a data disk");
561 (
off_t) 2048*16, SEEK_SET);
563 struct iso_primary_descriptor buf {};
565 while ((sr != (
off_t) -1) && (readin < 2048))
569 if ((rr < 0) && ((EAGAIN == errno) || (EINTR == errno)))
578 m_volumeID = QString(buf.volume_id).trimmed();
581 QString(
reinterpret_cast<char*
>(buf.creation_date)).left(16));
589 LOG(VB_MEDIA, LOG_INFO,
631 LOG(VB_MEDIA, LOG_DEBUG,
"found an audio disk");
637 LOG(VB_MEDIA, LOG_DEBUG,
"found a mixed CD");
641 #if ASSUME_WANT_AUDIO
666 LOG(VB_MEDIA, LOG_DEBUG,
"found a blank or writable disk");
670 LOG(VB_MEDIA, LOG_DEBUG,
"found no disk");
675 LOG(VB_MEDIA, LOG_DEBUG,
"found unknown disk type: " +
676 QString::number(
type));
690 LOG(VB_MEDIA, LOG_DEBUG, QString(
"Returning %1")
700 LOG(VB_MEDIA, LOG_DEBUG,
LOC +
":lock - Locking CDROM door");
704 LOG(VB_MEDIA, LOG_WARNING,
"lock() - CDROM_LOCKDOOR ioctl failed" +
ENO);
714 LOG(VB_MEDIA, LOG_DEBUG,
LOC +
":unlock - Unlocking CDROM door");
718 LOG(VB_MEDIA, LOG_WARNING,
"unlock() - CDROM_LOCKDOOR ioctl failed" +
ENO);
722 LOG(VB_GENERAL, LOG_INFO,
"Failed to open device, CDROM tray will "
733 if (stat(path.toLocal8Bit().constData(), &sb) < 0)
735 LOG(VB_GENERAL, LOG_ERR,
LOC +
":isSameDevice() -- " +
736 QString(
"Failed to stat '%1'").arg(path) +
ENO);
739 dev_t new_rdev = sb.st_rdev;
742 if (stat(
m_devicePath.toLocal8Bit().constData(), &sb) < 0)
744 LOG(VB_GENERAL, LOG_ERR,
LOC +
":isSameDevice() -- " +
748 return (sb.st_rdev == new_rdev);
751 #if defined(SG_IO) && defined(GPCMD_SET_STREAMING)
757 std::array<uint8_t,28> buffer {};
758 std::array<uint8_t,16> cmd {};
759 std::array<uint8_t,16> sense {};
760 struct sg_io_hdr sghdr {};
767 LOG(VB_MEDIA, LOG_ERR,
LOC +
768 " Changing CD/DVD speed needs write access");
772 if (fstat(fd, &st) == -1)
775 LOG(VB_MEDIA, LOG_ERR,
LOC +
776 QString(
":setDeviceSpeed() Failed. device %1 not found")
781 if (!S_ISBLK(st.st_mode))
784 LOG(VB_MEDIA, LOG_ERR,
LOC +
785 ":setDeviceSpeed() Failed. Not a block device");
801 LOG(VB_MEDIA, LOG_INFO,
LOC +
802 ":setDeviceSpeed() - Restored CD/DVD Speed");
810 rate = (speed > 0 && speed < 100) ? speed * 177 : speed;
812 LOG(VB_MEDIA, LOG_INFO,
LOC +
813 QString(
":setDeviceSpeed() - Limiting CD/DVD Speed to %1KB/s")
819 sghdr.interface_id =
'S';
820 sghdr.timeout = 5000;
821 sghdr.dxfer_direction = SG_DXFER_TO_DEV;
822 sghdr.mx_sb_len = sense.size();
823 sghdr.dxfer_len = buffer.size();
824 sghdr.cmd_len = cmd.size();
825 sghdr.sbp = sense.data();
826 sghdr.dxferp = buffer.data();
827 sghdr.cmdp = cmd.data();
829 cmd[0] = GPCMD_SET_STREAMING;
830 cmd[10] = buffer.size();
837 buffer[12] = buffer[20] = (rate >> 24) & 0xff;
838 buffer[13] = buffer[21] = (rate >> 16) & 0xff;
839 buffer[14] = buffer[22] = (rate >> 8) & 0xff;
840 buffer[15] = buffer[23] = rate & 0xff;
843 buffer[18] = buffer[26] = 0x03;
844 buffer[19] = buffer[27] = 0xe8;
846 if (ioctl(fd, SG_IO, &sghdr) < 0)
848 LOG(VB_MEDIA, LOG_ERR,
LOC +
" Limit CD/DVD Speed Failed" +
ENO);
854 if (ioctl(fd, CDROM_SELECT_SPEED, speed) < 0)
856 LOG(VB_MEDIA, LOG_ERR,
LOC +
857 " Limit CD/DVD CDROM_SELECT_SPEED Failed" +
ENO);
859 LOG(VB_MEDIA, LOG_INFO,
LOC +
860 ":setDeviceSpeed() - CD/DVD Speed Set Successful");