00001 #include <sys/types.h>
00002 #include <sys/stat.h>
00003 #include <sys/ioctl.h>
00004 #include <linux/cdrom.h>
00005 #include <scsi/sg.h>
00006 #include <fcntl.h>
00007 #include <errno.h>
00008 #include <stdint.h>
00009 #include <limits.h>
00010 #include <linux/iso_fs.h>
00011 #include <unistd.h>
00012
00013 #include <QDateTime>
00014
00015 #include "mythcdrom.h"
00016 #include "mythcdrom-linux.h"
00017 #include "mythconfig.h"
00018 #include "mythlogging.h"
00019 #ifdef USING_LIBUDF
00020 #include <cdio/udf.h>
00021 #endif
00022
00023 #define LOC QString("MythCDROMLinux:")
00024
00025
00026 #define ASSUME_WANT_AUDIO 1
00027
00028
00029
00030
00031
00032 typedef struct cdrom_generic_command CDROMgenericCmd;
00033
00034
00035
00036
00037
00038 typedef struct
00039 {
00040 uint16_t data_len[2];
00041 #if HAVE_BIGENDIAN
00042 uint8_t nea : 1;
00043 uint8_t reserved1 : 4;
00044 uint8_t notification_class : 3;
00045 #else
00046 uint8_t notification_class : 3;
00047 uint8_t reserved1 : 4;
00048 uint8_t nea : 1;
00049 #endif
00050 uint8_t supp_event_class;
00051 #if HAVE_BIGENDIAN
00052 uint8_t reserved2 : 4;
00053 uint8_t media_event_code : 4;
00054 uint8_t reserved3 : 6;
00055 uint8_t media_present : 1;
00056 uint8_t door_open : 1;
00057 #else
00058 uint8_t media_event_code : 4;
00059 uint8_t reserved2 : 4;
00060 uint8_t door_open : 1;
00061 uint8_t media_present : 1;
00062 uint8_t reserved3 : 6;
00063 #endif
00064 uint8_t start_slot;
00065 uint8_t end_slot;
00066 } CDROMeventStatus;
00067
00068
00069 typedef struct {
00070 uint16_t disc_information_length;
00071 #if HAVE_BIGENDIAN
00072 uint8_t reserved1 : 3;
00073 uint8_t erasable : 1;
00074 uint8_t border_status : 2;
00075 uint8_t disc_status : 2;
00076 #else
00077 uint8_t disc_status : 2;
00078 uint8_t border_status : 2;
00079 uint8_t erasable : 1;
00080 uint8_t reserved1 : 3;
00081 #endif
00082 uint8_t n_first_track;
00083 uint8_t n_sessions_lsb;
00084 uint8_t first_track_lsb;
00085 uint8_t last_track_lsb;
00086 #if HAVE_BIGENDIAN
00087 uint8_t did_v : 1;
00088 uint8_t dbc_v : 1;
00089 uint8_t uru : 1;
00090 uint8_t reserved2 : 5;
00091 #else
00092 uint8_t reserved2 : 5;
00093 uint8_t uru : 1;
00094 uint8_t dbc_v : 1;
00095 uint8_t did_v : 1;
00096 #endif
00097 uint8_t disc_type;
00098 uint8_t n_sessions_msb;
00099 uint8_t first_track_msb;
00100 uint8_t last_track_msb;
00101 uint32_t disc_id;
00102 uint32_t lead_in;
00103 uint32_t lead_out;
00104 uint8_t disc_bar_code[8];
00105 uint8_t reserved3;
00106 uint8_t n_opc;
00107 } CDROMdiscInfo;
00108
00109 enum CDROMdiscStatus
00110 {
00111 MEDIA_IS_EMPTY = 0x0,
00112 MEDIA_IS_APPENDABLE = 0x1,
00113 MEDIA_IS_COMPLETE = 0x2,
00114 MEDIA_IS_OTHER = 0x3
00115 };
00116
00117
00124 class MythCDROMLinux: public MythCDROM
00125 {
00126 public:
00127 MythCDROMLinux(QObject* par, const char* DevicePath, bool SuperMount,
00128 bool AllowEject):
00129 MythCDROM(par, DevicePath, SuperMount, AllowEject) {
00130 }
00131
00132 virtual MythMediaError testMedia(void);
00133 virtual bool mediaChanged(void);
00134 virtual bool checkOK(void);
00135 virtual MythMediaStatus checkMedia(void);
00136 virtual MythMediaError eject(bool open_close = true);
00137 virtual void setSpeed(int speed);
00138 virtual void setSpeed(const char *device, int speed);
00139 virtual bool isSameDevice(const QString &path);
00140 virtual MythMediaError lock(void);
00141 virtual MythMediaError unlock(void);
00142
00143 private:
00144 int driveStatus(void);
00145 bool hasWritableMedia(void);
00146 int SCSIstatus(void);
00147 };
00148
00149 MythCDROM *GetMythCDROMLinux(QObject* par, const char* devicePath,
00150 bool SuperMount, bool AllowEject)
00151 {
00152 return new MythCDROMLinux(par, devicePath, SuperMount, AllowEject);
00153 }
00154
00155
00164 int MythCDROMLinux::driveStatus()
00165 {
00166 int drive_status = ioctl(m_DeviceHandle, CDROM_DRIVE_STATUS, CDSL_CURRENT);
00167
00168 if (drive_status == -1)
00169 {
00170 LOG(VB_MEDIA, LOG_ERR, LOC + ":driveStatus() - ioctl failed: " + ENO);
00171 return CDS_NO_INFO;
00172 }
00173
00174 if (drive_status == CDS_TRAY_OPEN && m_DevicePath.contains("/dev/scd"))
00175 return SCSIstatus();
00176
00177 return drive_status;
00178 }
00179
00183 bool MythCDROMLinux::hasWritableMedia()
00184 {
00185 unsigned char buffer[32];
00186 CDROMgenericCmd cgc;
00187 CDROMdiscInfo *di;
00188
00189
00190 memset(buffer, 0, sizeof(buffer));
00191 memset(&cgc, 0, sizeof(cgc));
00192
00193 cgc.cmd[0] = GPCMD_READ_DISC_INFO;
00194 cgc.cmd[8] = sizeof(buffer);
00195 cgc.quiet = 1;
00196 cgc.buffer = buffer;
00197 cgc.buflen = sizeof(buffer);
00198 cgc.data_direction = CGC_DATA_READ;
00199
00200 if (ioctl(m_DeviceHandle, CDROM_SEND_PACKET, &cgc) < 0)
00201 {
00202 LOG(VB_MEDIA, LOG_ERR, LOC +
00203 ":hasWritableMedia() - failed to send packet to " + m_DevicePath);
00204 return false;
00205 }
00206
00207 di = (CDROMdiscInfo *) buffer;
00208
00209 switch (di->disc_status)
00210 {
00211 case MEDIA_IS_EMPTY:
00212 return true;
00213
00214 case MEDIA_IS_APPENDABLE:
00215
00216
00217
00218 case MEDIA_IS_COMPLETE:
00219 return di->erasable;
00220
00221 case MEDIA_IS_OTHER:
00222 ;
00223 }
00224
00225 return false;
00226 }
00227
00236 int MythCDROMLinux::SCSIstatus()
00237 {
00238 unsigned char buffer[8];
00239 CDROMgenericCmd cgc;
00240 CDROMeventStatus *es;
00241
00242
00243 memset(buffer, 0, sizeof(buffer));
00244 memset(&cgc, 0, sizeof(cgc));
00245
00246 cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION;
00247 cgc.cmd[1] = 1;
00248 cgc.cmd[4] = 1 << 4;
00249 cgc.cmd[8] = sizeof(buffer);
00250 cgc.quiet = 1;
00251 cgc.buffer = buffer;
00252 cgc.buflen = sizeof(buffer);
00253 cgc.data_direction = CGC_DATA_READ;
00254
00255 es = (CDROMeventStatus *) buffer;
00256
00257 if ((ioctl(m_DeviceHandle, CDROM_SEND_PACKET, &cgc) < 0)
00258 || es->nea
00259 || (es->notification_class != 0x4))
00260 {
00261 LOG(VB_MEDIA, LOG_ERR, LOC +
00262 ":SCSIstatus() - failed to send SCSI packet to " + m_DevicePath);
00263 return CDS_TRAY_OPEN;
00264 }
00265
00266 if (es->media_present)
00267 {
00268 LOG(VB_MEDIA, LOG_DEBUG, LOC +
00269 ":SCSIstatus() - ioctl said tray was open, "
00270 "but drive is actually closed with a disc");
00271 return CDS_DISC_OK;
00272 }
00273 else if (es->door_open)
00274 {
00275 LOG(VB_MEDIA, LOG_DEBUG, LOC +
00276 ":SCSIstatus() - tray is definitely open");
00277 return CDS_TRAY_OPEN;
00278 }
00279
00280 LOG(VB_MEDIA, LOG_DEBUG, LOC + ":SCSIstatus() - ioctl said tray was open, "
00281 "but drive is actually closed with no disc");
00282 return CDS_NO_DISC;
00283 }
00284
00285
00286 MythMediaError MythCDROMLinux::eject(bool open_close)
00287 {
00288 if (!isDeviceOpen())
00289 {
00290 if (!openDevice())
00291 return MEDIAERR_FAILED;
00292 }
00293
00294 if (open_close)
00295 return (ioctl(m_DeviceHandle, CDROMEJECT) == 0) ? MEDIAERR_OK
00296 : MEDIAERR_FAILED;
00297 else
00298 {
00299
00300 ioctl(m_DeviceHandle, CDROMCLOSETRAY);
00301
00302
00303
00304 if (driveStatus() == CDS_TRAY_OPEN)
00305 return MEDIAERR_FAILED;
00306 else
00307 return MEDIAERR_OK;
00308 }
00309 }
00310
00311
00312 bool MythCDROMLinux::mediaChanged()
00313 {
00314 return (ioctl(m_DeviceHandle, CDROM_MEDIA_CHANGED, CDSL_CURRENT) > 0);
00315 }
00316
00317 bool MythCDROMLinux::checkOK()
00318 {
00319 return (ioctl(m_DeviceHandle, CDROM_DRIVE_STATUS, CDSL_CURRENT) ==
00320 CDS_DISC_OK);
00321 }
00322
00323
00324 MythMediaError MythCDROMLinux::testMedia()
00325 {
00326 bool OpenedHere = false;
00327 if (!isDeviceOpen())
00328 {
00329 if (!openDevice())
00330 {
00331 LOG(VB_MEDIA, LOG_DEBUG, LOC + ":testMedia - failed to open '" +
00332 m_DevicePath + "' : " +ENO);
00333 if (errno == EBUSY)
00334 return isMounted() ? MEDIAERR_OK : MEDIAERR_FAILED;
00335 else
00336 return MEDIAERR_FAILED;
00337 }
00338 LOG(VB_MEDIA, LOG_DEBUG, LOC + ":testMedia - Opened device");
00339 OpenedHere = true;
00340 }
00341
00342
00343 int Stat = driveStatus();
00344
00345
00346
00347 if (OpenedHere)
00348 closeDevice();
00349
00350 if (Stat == -1)
00351 {
00352 LOG(VB_MEDIA, LOG_DEBUG, LOC +
00353 ":testMedia - Failed to get drive status of '" + m_DevicePath +
00354 "' : " + ENO);
00355 return MEDIAERR_FAILED;
00356 }
00357
00358 return MEDIAERR_OK;
00359 }
00360
00361 MythMediaStatus MythCDROMLinux::checkMedia()
00362 {
00363 bool OpenedHere = false;
00364
00365
00366
00367 if (!isDeviceOpen())
00368 {
00369 OpenedHere = openDevice();
00370
00371 if (!OpenedHere)
00372 {
00373 LOG(VB_MEDIA, LOG_ERR, LOC +
00374 ":checkMedia() - cannot open device '" + m_DevicePath + "' : " +
00375 ENO + "- returning UNKNOWN");
00376 m_MediaType = MEDIATYPE_UNKNOWN;
00377 return setStatus(MEDIASTAT_UNKNOWN, false);
00378 }
00379 }
00380
00381 switch (driveStatus())
00382 {
00383 case CDS_DISC_OK:
00384 LOG(VB_MEDIA, LOG_DEBUG, m_DevicePath + " Disk OK, type = " +
00385 MediaTypeString(m_MediaType) );
00386
00387 break;
00388 case CDS_TRAY_OPEN:
00389 LOG(VB_MEDIA, LOG_DEBUG, m_DevicePath + " Tray open or no disc");
00390
00391
00392 setStatus(MEDIASTAT_OPEN, OpenedHere);
00393
00394 m_MediaType = MEDIATYPE_UNKNOWN;
00395 return MEDIASTAT_OPEN;
00396 break;
00397 case CDS_NO_DISC:
00398 LOG(VB_MEDIA, LOG_DEBUG, m_DevicePath + " No disc");
00399 m_MediaType = MEDIATYPE_UNKNOWN;
00400 return setStatus(MEDIASTAT_NODISK, OpenedHere);
00401 break;
00402 case CDS_NO_INFO:
00403 case CDS_DRIVE_NOT_READY:
00404 LOG(VB_MEDIA, LOG_DEBUG, m_DevicePath +
00405 " No info or drive not ready");
00406 m_MediaType = MEDIATYPE_UNKNOWN;
00407 return setStatus(MEDIASTAT_UNKNOWN, OpenedHere);
00408 default:
00409 LOG(VB_GENERAL, LOG_ERR, "Failed to get drive status of " +
00410 m_DevicePath + " : " + ENO);
00411 m_MediaType = MEDIATYPE_UNKNOWN;
00412 return setStatus(MEDIASTAT_UNKNOWN, OpenedHere);
00413 }
00414
00415 if (mediaChanged())
00416 {
00417 LOG(VB_MEDIA, LOG_INFO, m_DevicePath + " Media changed");
00418
00419
00420 return setStatus(MEDIASTAT_OPEN, OpenedHere);
00421 }
00422
00423
00424 if (isUsable())
00425 {
00426 LOG(VB_MEDIA, LOG_DEBUG, "Disc useable, media unchanged. All good!");
00427 if (OpenedHere)
00428 closeDevice();
00429 return MEDIASTAT_USEABLE;
00430 }
00431
00432
00433 if (m_Status == MEDIASTAT_ERROR)
00434 {
00435 LOG(VB_MEDIA, LOG_DEBUG, "Disc is unmountable?");
00436 if (OpenedHere)
00437 closeDevice();
00438 return m_Status;
00439 }
00440
00441 if ((m_Status == MEDIASTAT_OPEN) ||
00442 (m_Status == MEDIASTAT_UNKNOWN))
00443 {
00444 LOG(VB_MEDIA, LOG_INFO, m_DevicePath + " Current status " +
00445 MythMediaDevice::MediaStatusStrings[m_Status]);
00446 int type = ioctl(m_DeviceHandle, CDROM_DISC_STATUS, CDSL_CURRENT);
00447 switch (type)
00448 {
00449 case CDS_DATA_1:
00450 case CDS_DATA_2:
00451 {
00452 m_MediaType = MEDIATYPE_DATA;
00453 LOG(VB_MEDIA, LOG_INFO, "Found a data disk");
00454
00455
00456 off_t sr = lseek(m_DeviceHandle,
00457 (off_t) 2048*16, SEEK_SET);
00458
00459 struct iso_primary_descriptor buf;
00460 ssize_t readin = 0;
00461 while ((sr != (off_t) -1) && (readin < 2048))
00462 {
00463 ssize_t rr = read(
00464 m_DeviceHandle, ((char*)&buf) + readin, 2048 - readin);
00465 if ((rr < 0) && ((EAGAIN == errno) || (EINTR == errno)))
00466 continue;
00467 else if (rr < 0)
00468 break;
00469 readin += rr;
00470 }
00471
00472 if (readin == 2048)
00473 {
00474 m_VolumeID = QString(buf.volume_id).trimmed();
00475 m_KeyID = QString("%1%2")
00476 .arg(m_VolumeID)
00477 .arg(QString(buf.creation_date).left(16));
00478 }
00479 else
00480 {
00481 m_VolumeID = "UNKNOWN";
00482 m_KeyID = m_VolumeID +
00483 QDateTime::currentDateTime().toString(Qt::ISODate);
00484 }
00485
00486 LOG(VB_MEDIA, LOG_INFO,
00487 QString("Volume ID: %1").arg(m_VolumeID));
00488 #ifdef USING_LIBUDF
00489
00490
00491
00492 udf_t *pUdf = udf_open(m_DevicePath.toAscii());
00493 if (NULL != pUdf)
00494 {
00495 udf_dirent_t *pUdfRoot = udf_get_root(pUdf, true, 0);
00496 if (NULL != pUdfRoot)
00497 {
00498 if (NULL != udf_fopen(pUdfRoot, "VIDEO_TS"))
00499 m_MediaType = MEDIATYPE_DVD;
00500 else if (NULL != udf_fopen(pUdfRoot, "BDMV"))
00501 m_MediaType = MEDIATYPE_BD;
00502
00503 udf_dirent_free(pUdfRoot);
00504 }
00505 udf_close(pUdf);
00506
00507 if (MEDIATYPE_DATA != m_MediaType)
00508 {
00509
00510 m_Status = MEDIASTAT_NOTMOUNTED;
00511 return setStatus(MEDIASTAT_USEABLE, OpenedHere);
00512 }
00513 }
00514 #endif
00515
00516
00517 if (isMounted())
00518 onDeviceMounted();
00519 else if (!mount())
00520 return setStatus(MEDIASTAT_ERROR, OpenedHere);
00521
00522 if (isMounted())
00523 {
00524
00525 m_Status = MEDIASTAT_NOTMOUNTED;
00526 return setStatus(MEDIASTAT_MOUNTED, OpenedHere);
00527 }
00528 else if (m_MediaType == MEDIATYPE_DVD)
00529 {
00530
00531 m_Status = MEDIASTAT_NOTMOUNTED;
00532 return setStatus(MEDIASTAT_USEABLE, OpenedHere);
00533 }
00534 else
00535 return setStatus(MEDIASTAT_NOTMOUNTED, OpenedHere);
00536 break;
00537 }
00538 case CDS_AUDIO:
00539 LOG(VB_MEDIA, LOG_DEBUG, "found an audio disk");
00540 m_MediaType = MEDIATYPE_AUDIO;
00541 return setStatus(MEDIASTAT_USEABLE, OpenedHere);
00542 break;
00543 case CDS_MIXED:
00544 m_MediaType = MEDIATYPE_MIXED;
00545 LOG(VB_MEDIA, LOG_DEBUG, "found a mixed CD");
00546
00547
00548
00549 #ifdef ASSUME_WANT_AUDIO
00550 return setStatus(MEDIASTAT_USEABLE, OpenedHere);
00551 #else
00552 mount();
00553 if (isMounted())
00554 {
00555
00556
00557 m_Status = MEDIASTAT_NOTMOUNTED;
00558 return setStatus(MEDIASTAT_MOUNTED, OpenedHere);
00559 }
00560 else
00561 {
00562 return setStatus(MEDIASTAT_USEABLE, OpenedHere);
00563 }
00564 #endif
00565 break;
00566 case CDS_NO_INFO:
00567 case CDS_NO_DISC:
00568 if (hasWritableMedia())
00569 {
00570 LOG(VB_MEDIA, LOG_DEBUG, "found a blank or writable disk");
00571 return setStatus(MEDIASTAT_UNFORMATTED, OpenedHere);
00572 }
00573
00574 LOG(VB_MEDIA, LOG_DEBUG, "found no disk");
00575 m_MediaType = MEDIATYPE_UNKNOWN;
00576 return setStatus(MEDIASTAT_UNKNOWN, OpenedHere);
00577 break;
00578 default:
00579 LOG(VB_MEDIA, LOG_DEBUG, "found unknown disk type: " +
00580 QString::number(type));
00581 m_MediaType = MEDIATYPE_UNKNOWN;
00582 return setStatus(MEDIASTAT_UNKNOWN, OpenedHere);
00583 }
00584 }
00585
00586 if (m_AllowEject)
00587 unlock();
00588 else
00589 lock();
00590
00591 if (OpenedHere)
00592 closeDevice();
00593
00594 LOG(VB_MEDIA, LOG_DEBUG, QString("Returning %1")
00595 .arg(MythMediaDevice::MediaStatusStrings[m_Status]));
00596 return m_Status;
00597 }
00598
00599 MythMediaError MythCDROMLinux::lock()
00600 {
00601 MythMediaError ret = MythMediaDevice::lock();
00602 if (ret == MEDIAERR_OK)
00603 ioctl(m_DeviceHandle, CDROM_LOCKDOOR, 1);
00604
00605 return ret;
00606 }
00607
00608 MythMediaError MythCDROMLinux::unlock()
00609 {
00610 if (isDeviceOpen() || openDevice())
00611 {
00612 LOG(VB_MEDIA, LOG_DEBUG, LOC + ":unlock - Unlocking CDROM door");
00613 ioctl(m_DeviceHandle, CDROM_LOCKDOOR, 0);
00614 }
00615 else
00616 {
00617 LOG(VB_GENERAL, LOG_INFO, "Failed to open device, CDROM try will "
00618 "remain locked.");
00619 }
00620
00621 return MythMediaDevice::unlock();
00622 }
00623
00624 bool MythCDROMLinux::isSameDevice(const QString &path)
00625 {
00626 dev_t new_rdev;
00627 struct stat sb;
00628
00629 if (stat(path.toLocal8Bit().constData(), &sb) < 0)
00630 {
00631 LOG(VB_GENERAL, LOG_ERR, LOC + ":isSameDevice() -- " +
00632 QString("Failed to stat '%1'").arg(path) + ENO);
00633 return false;
00634 }
00635 new_rdev = sb.st_rdev;
00636
00637
00638 if (stat(m_DevicePath.toLocal8Bit().constData(), &sb) < 0)
00639 {
00640 LOG(VB_GENERAL, LOG_ERR, LOC + ":isSameDevice() -- " +
00641 QString("Failed to stat '%1'").arg(m_DevicePath) + ENO);
00642 return false;
00643 }
00644 return (sb.st_rdev == new_rdev);
00645 }
00646
00647 #if defined(SG_IO) && defined(GPCMD_SET_STREAMING)
00648
00649
00650
00651 void MythCDROMLinux::setSpeed(int speed)
00652 {
00653 MythCDROMLinux::setSpeed(m_DevicePath.toLocal8Bit().constData(), speed);
00654 }
00655
00656 void MythCDROMLinux::setSpeed(const char *device, int speed)
00657 {
00658 int fd;
00659 unsigned char buffer[28];
00660 unsigned char cmd[16];
00661 unsigned char sense[16];
00662 struct sg_io_hdr sghdr;
00663 struct stat st;
00664 int rate = 0;
00665
00666 memset(&sghdr, 0, sizeof(sghdr));
00667 memset(buffer, 0, sizeof(buffer));
00668 memset(sense, 0, sizeof(sense));
00669 memset(cmd, 0, sizeof(cmd));
00670 memset(&st, 0, sizeof(st));
00671
00672 if ((fd = open(device, O_RDWR | O_NONBLOCK)) == -1)
00673 {
00674 LOG(VB_MEDIA, LOG_ERR, LOC +
00675 " Changing CD/DVD speed needs write access");
00676 return;
00677 }
00678
00679 if (fstat(fd, &st) == -1)
00680 {
00681 close(fd);
00682 LOG(VB_MEDIA, LOG_ERR, LOC +
00683 QString(":setSpeed() Failed. device %1 not found") .arg(device));
00684 return;
00685 }
00686
00687 if (!S_ISBLK(st.st_mode))
00688 {
00689 close(fd);
00690 LOG(VB_MEDIA, LOG_ERR, LOC + ":setSpeed() Failed. Not a block device");
00691 return;
00692 }
00693
00694 if (speed < 0)
00695 speed = -1;
00696
00697 switch(speed)
00698 {
00699 case 0:
00700 close(fd);
00701 return;
00702 case -1:
00703 {
00704 rate = 0;
00705 buffer[0] = 4;
00706 LOG(VB_MEDIA, LOG_INFO, LOC +
00707 ":setSpeed() - Restored CD/DVD Speed");
00708 break;
00709 }
00710 default:
00711 {
00712
00713
00714
00715 rate = (speed > 0 && speed < 100) ? speed * 177 : speed;
00716
00717 LOG(VB_MEDIA, LOG_INFO, LOC +
00718 QString(":setSpeed() - Limiting CD/DVD Speed to %1KB/s")
00719 .arg(rate));
00720 break;
00721 }
00722 }
00723
00724 sghdr.interface_id = 'S';
00725 sghdr.timeout = 5000;
00726 sghdr.dxfer_direction = SG_DXFER_TO_DEV;
00727 sghdr.mx_sb_len = sizeof(sense);
00728 sghdr.dxfer_len = sizeof(buffer);
00729 sghdr.cmd_len = sizeof(cmd);
00730 sghdr.sbp = sense;
00731 sghdr.dxferp = buffer;
00732 sghdr.cmdp = cmd;
00733
00734 cmd[0] = GPCMD_SET_STREAMING;
00735 cmd[10] = sizeof(buffer);
00736
00737 buffer[8] = 0xff;
00738 buffer[9] = 0xff;
00739 buffer[10] = 0xff;
00740 buffer[11] = 0xff;
00741
00742 buffer[12] = buffer[20] = (rate >> 24) & 0xff;
00743 buffer[13] = buffer[21] = (rate >> 16) & 0xff;
00744 buffer[14] = buffer[22] = (rate >> 8) & 0xff;
00745 buffer[15] = buffer[23] = rate & 0xff;
00746
00747
00748 buffer[18] = buffer[26] = 0x03;
00749 buffer[19] = buffer[27] = 0xe8;
00750
00751 if (ioctl(fd, SG_IO, &sghdr) < 0)
00752 {
00753 LOG(VB_MEDIA, LOG_ERR, LOC + " Limit CD/DVD Speed Failed");
00754 }
00755 else
00756 {
00757
00758
00759 if (ioctl(fd, CDROM_SELECT_SPEED, speed) < 0)
00760 {
00761 LOG(VB_MEDIA, LOG_ERR, LOC +
00762 " Limit CD/DVD CDROM_SELECT_SPEED Failed");
00763 }
00764 LOG(VB_MEDIA, LOG_INFO, LOC +
00765 ":setSpeed() - CD/DVD Speed Set Successful");
00766 }
00767
00768 close(fd);
00769 }
00770 #endif