File indexing completed on 2025-03-23 04:28:09
0001 /* 0002 SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 #include "k3bdevice.h" 0006 #include "k3bdeviceglobals.h" 0007 #include "k3btrack.h" 0008 #include "k3btoc.h" 0009 #include "k3bdiskinfo.h" 0010 #include "k3bdiskinfo_p.h" 0011 #include "k3bmmc.h" 0012 #include "k3bscsicommand.h" 0013 #include "k3bcrc.h" 0014 0015 #include "config-k3b.h" 0016 0017 #include <Solid/Device> 0018 #include <Solid/OpticalDrive> 0019 #include <Solid/Block> 0020 #include <Solid/StorageAccess> 0021 #ifdef Q_OS_NETBSD 0022 #include <Solid/GenericInterface> 0023 #endif 0024 0025 #include <qglobal.h> 0026 #include <QDebug> 0027 #include <QFile> 0028 #include <QMutex> 0029 #include <QStringList> 0030 0031 #include <sys/types.h> 0032 #include <sys/ioctl.h> 0033 0034 #include <stdio.h> 0035 #include <stdlib.h> 0036 #include <fcntl.h> 0037 #include <unistd.h> 0038 #include <errno.h> 0039 #include <sys/stat.h> 0040 #include <math.h> 0041 #include <stdarg.h> 0042 #include <limits.h> 0043 0044 0045 #ifdef Q_OS_LINUX 0046 0047 #include <linux/version.h> 0048 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,70) 0049 typedef unsigned char u8; 0050 #endif 0051 0052 #undef __STRICT_ANSI__ 0053 #include <linux/cdrom.h> 0054 #define __STRICT_ANSI__ 0055 0056 #endif // Q_OS_LINUX 0057 0058 #ifdef Q_OS_FREEBSD 0059 #include <stdio.h> 0060 #include <camlib.h> 0061 #define CD_FRAMESIZE_RAW 2352 0062 #endif 0063 0064 #ifdef Q_OS_NETBSD 0065 #include <sys/cdio.h> 0066 #endif 0067 0068 #ifdef HAVE_RESMGR 0069 extern "C" { 0070 #include <resmgr.h> 0071 } 0072 #endif 0073 0074 #ifdef Q_OS_FREEBSD 0075 #define HANDLE_DEFAULT_VALUE 0 0076 #endif 0077 #ifdef Q_OS_WIN32 0078 #define HANDLE_DEFAULT_VALUE INVALID_HANDLE_VALUE 0079 #endif 0080 #ifdef Q_OS_LINUX 0081 #define HANDLE_DEFAULT_VALUE -1 0082 #endif 0083 #ifdef Q_OS_NETBSD 0084 #define HANDLE_DEFAULT_VALUE -1 0085 #endif 0086 0087 // 0088 // Very evil hacking: force the speed values to be accurate 0089 // as long as "they" do not introduce other "broken" DVD 0090 // speeds like 2.4 this works fine 0091 // 0092 namespace { 0093 int fixupDvdWritingSpeed( int speed ) 0094 { 0095 // 0096 // Some writers report their speeds in 1000 bytes per second instead of 1024. 0097 // 0098 if( speed % K3b::Device::SPEED_FACTOR_DVD == 0 ) 0099 return speed; 0100 0101 else if( speed % 1352 == 0 ) 0102 return speed*K3b::Device::SPEED_FACTOR_DVD/1352; 0103 0104 // has to be 2.4x speed 0105 else 0106 return 3324; 0107 } 0108 } 0109 0110 class K3b::Device::Device::Private 0111 { 0112 public: 0113 Private() 0114 : deviceHandle(HANDLE_DEFAULT_VALUE), 0115 openedReadWrite(false), 0116 burnfree(false) { 0117 } 0118 0119 Solid::Device solidDevice; 0120 0121 QString vendor; 0122 QString description; 0123 QString version; 0124 int maxReadSpeed; 0125 int maxWriteSpeed; 0126 int currentWriteSpeed; 0127 0128 bool dvdMinusTestwrite; 0129 0130 int bufferSize; 0131 0132 WritingModes writeModes; 0133 0134 QString blockDevice; 0135 QString genericDevice; 0136 0137 MediaTypes readCapabilities; 0138 MediaTypes writeCapabilities; 0139 MediaTypes supportedProfiles; 0140 Handle deviceHandle; 0141 bool openedReadWrite; 0142 bool burnfree; 0143 0144 QMutex mutex; 0145 QMutex openCloseMutex; 0146 }; 0147 0148 #ifdef Q_OS_FREEBSD 0149 K3b::Device::Device::Handle K3b::Device::openDevice( const char* name, bool write ) 0150 { 0151 K3b::Device::Device::Handle handle = cam_open_device (name, O_RDWR); 0152 qDebug() << "(K3b::Device::openDevice) open device " << name 0153 << ((handle)?" succeeded.":" failed.") << Qt::endl; 0154 return handle; 0155 } 0156 #endif 0157 0158 0159 #if defined(Q_OS_LINUX) || defined(Q_OS_NETBSD) 0160 K3b::Device::Device::Handle K3b::Device::openDevice( const char* name, bool write ) 0161 { 0162 K3b::Device::Device::Handle fd = HANDLE_DEFAULT_VALUE; 0163 int flags = O_NONBLOCK | O_CLOEXEC; 0164 if( write ) 0165 flags |= O_RDWR; 0166 else 0167 flags |= O_RDONLY; 0168 0169 #ifdef HAVE_RESMGR 0170 // first try resmgr 0171 fd = ::rsm_open_device( name, flags ); 0172 // qDebug() << "(K3b::Device::Device) resmgr open: " << fd; 0173 #endif 0174 0175 if( fd < 0 ) 0176 fd = ::open( name, flags ); 0177 0178 if( fd < 0 ) { 0179 qDebug() << "(K3b::Device::Device) could not open device " 0180 << name << ( write ? " for writing" : " for reading" ) << Qt::endl; 0181 qDebug() << " (" << QString::fromLocal8Bit( ::strerror(errno) ) << ")"; 0182 fd = HANDLE_DEFAULT_VALUE; 0183 0184 // at least open it read-only (which is sufficient for kernels < 2.6.8 anyway) 0185 if( write ) 0186 return openDevice( name, false ); 0187 } 0188 0189 return fd; 0190 } 0191 #endif 0192 0193 #ifdef Q_OS_WIN32 0194 #define NAME_COUNT 25 0195 0196 K3b::Device::Device::Handle K3b::Device::openDevice( const char* name, bool write ) 0197 { 0198 bool status = false; 0199 K3b::Device::Device::Handle deviceHandle = HANDLE_DEFAULT_VALUE; 0200 char string[NAME_COUNT + 1]; 0201 // check if name is already a device name 0202 if (name[0] == '\\') 0203 strncpy(string, name, NAME_COUNT); 0204 else 0205 _snprintf(string, NAME_COUNT, "\\\\.\\%s", name); 0206 deviceHandle = CreateFileA(string, 0207 GENERIC_READ | GENERIC_WRITE , // at least inquiry needs write access 0208 FILE_SHARE_READ | (write ? FILE_SHARE_WRITE : 0), 0209 NULL, 0210 OPEN_EXISTING, 0211 0, 0212 NULL); 0213 0214 if( deviceHandle == INVALID_HANDLE_VALUE ) 0215 deviceHandle = CreateFileA(string, 0216 GENERIC_READ, 0217 FILE_SHARE_READ, 0218 NULL, 0219 OPEN_EXISTING, 0220 0, 0221 NULL); 0222 0223 if (deviceHandle == INVALID_HANDLE_VALUE) { 0224 int errorCode = GetLastError(); 0225 qDebug() << "Error opening " << string << "Error:" << errorCode << Qt::endl; 0226 return HANDLE_DEFAULT_VALUE; 0227 } 0228 0229 return deviceHandle; 0230 } 0231 #endif 0232 0233 0234 K3b::Device::Device::Device( const Solid::Device& dev ) 0235 { 0236 #ifdef Q_OS_NETBSD 0237 const Solid::GenericInterface *gi = dev.as<Solid::GenericInterface>(); 0238 #endif 0239 d = new Private; 0240 d->solidDevice = dev; 0241 // TODO: block device address might not be "stdio:/path" 0242 #ifndef Q_OS_NETBSD 0243 d->blockDevice = dev.as<Solid::Block>()->device(); 0244 #else 0245 if (gi->propertyExists("block.netbsd.raw_device")) 0246 d->blockDevice = gi->property("block.netbsd.raw_device").toString(); 0247 else 0248 d->blockDevice = dev.as<Solid::Block>()->device(); 0249 #endif 0250 d->writeModes = {}; 0251 d->maxWriteSpeed = 0; 0252 d->maxReadSpeed = 0; 0253 d->burnfree = false; 0254 d->dvdMinusTestwrite = true; 0255 d->bufferSize = 0; 0256 } 0257 0258 0259 K3b::Device::Device::~Device() 0260 { 0261 close(); 0262 delete d; 0263 } 0264 0265 0266 QString K3b::Device::Device::vendor() const 0267 { 0268 return d->vendor; 0269 } 0270 0271 0272 QString K3b::Device::Device::description() const 0273 { 0274 return d->description; 0275 } 0276 0277 0278 QString K3b::Device::Device::version() const 0279 { 0280 return d->version; 0281 } 0282 0283 0284 bool K3b::Device::Device::dvdMinusTestwrite() const 0285 { 0286 return d->dvdMinusTestwrite; 0287 } 0288 0289 0290 int K3b::Device::Device::maxReadSpeed() const 0291 { 0292 return d->maxReadSpeed; 0293 } 0294 0295 0296 int K3b::Device::Device::currentWriteSpeed() const 0297 { 0298 return d->currentWriteSpeed; 0299 } 0300 0301 0302 int K3b::Device::Device::bufferSize() const 0303 { 0304 return d->bufferSize; 0305 } 0306 0307 0308 QString K3b::Device::Device::blockDeviceName() const 0309 { 0310 return d->blockDevice; 0311 } 0312 0313 0314 int K3b::Device::Device::maxWriteSpeed() const 0315 { 0316 return d->maxWriteSpeed; 0317 } 0318 0319 0320 void K3b::Device::Device::setCurrentWriteSpeed( int s ) 0321 { 0322 d->currentWriteSpeed = s; 0323 } 0324 0325 0326 void K3b::Device::Device::setMaxReadSpeed( int s ) 0327 { 0328 d->maxReadSpeed = s; 0329 } 0330 0331 0332 void K3b::Device::Device::setMaxWriteSpeed( int s ) 0333 { 0334 d->maxWriteSpeed = s; 0335 } 0336 0337 0338 Solid::Device K3b::Device::Device::solidDevice() const 0339 { 0340 return d->solidDevice; 0341 } 0342 0343 0344 Solid::StorageAccess* K3b::Device::Device::solidStorage() const 0345 { 0346 QList<Solid::Device> storages = Solid::Device::listFromType( Solid::DeviceInterface::StorageAccess, d->solidDevice.udi() ); 0347 if( storages.isEmpty() ) 0348 return nullptr; 0349 else 0350 return storages.first().as<Solid::StorageAccess>(); 0351 } 0352 0353 0354 bool K3b::Device::Device::init( bool bCheckWritingModes ) 0355 { 0356 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": init()"; 0357 0358 // 0359 // they all should read CD-ROM. 0360 // 0361 d->readCapabilities = MEDIA_CD_ROM; 0362 d->writeCapabilities = {}; 0363 d->supportedProfiles = {}; 0364 0365 if( !open() ) 0366 return false; 0367 0368 // 0369 // inquiry 0370 // use a 36 bytes buffer since not all devices return the full inquiry struct 0371 // 0372 ScsiCommand cmd( this ); 0373 unsigned char buf[36]; 0374 cmd.clear(); 0375 ::memset( buf, 0, sizeof(buf) ); 0376 struct inquiry* inq = (struct inquiry*)buf; 0377 cmd[0] = MMC_INQUIRY; 0378 cmd[4] = sizeof(buf); 0379 cmd[5] = 0; 0380 if( cmd.transport( TR_DIR_READ, buf, sizeof(buf) ) ) { 0381 qCritical() << "(K3b::Device::Device) Unable to do inquiry." << Qt::endl; 0382 close(); 0383 return false; 0384 } 0385 else { 0386 d->vendor = QString::fromLatin1( (char*)(inq->vendor), 8 ).trimmed(); 0387 d->description = QString::fromLatin1( (char*)(inq->product), 16 ).trimmed(); 0388 d->version = QString::fromLatin1( (char*)(inq->revision), 4 ).trimmed(); 0389 } 0390 0391 if( d->vendor.isEmpty() ) 0392 d->vendor = "UNKNOWN"; 0393 if( d->description.isEmpty() ) 0394 d->description = "UNKNOWN"; 0395 0396 // 0397 // We probe all features of the device. Since not all devices support the GET CONFIGURATION command 0398 // we also query the mode page 2A and use the cdrom.h stuff to get as much information as possible 0399 // 0400 checkFeatures(); 0401 0402 // 0403 // Check the supported write modes (WRITINGMODE_TAO, WRITINGMODE_SAO, WRITINGMODE_RAW) by trying to set them 0404 // We do this before checking mode page 2A in case some readers allow changing 0405 // the write parameter page 0406 // 0407 if( bCheckWritingModes ) 0408 checkWritingModes(); 0409 0410 // 0411 // Most current drives support the 2A mode page 0412 // Here we can get some more information (cdrecord -prcap does exactly this) 0413 // 0414 checkFor2AFeatures(); 0415 0416 d->maxWriteSpeed = determineMaximalWriteSpeed(); 0417 0418 // 0419 // Check Just-Link via Ricoh mode page 0x30 0420 // 0421 if( !d->burnfree ) 0422 checkForJustLink(); 0423 0424 // 0425 // Support for some very old drives 0426 // 0427 checkForAncientWriters(); 0428 0429 // 0430 // If it can be written it can also be read 0431 // 0432 d->readCapabilities |= d->writeCapabilities; 0433 0434 close(); 0435 0436 return furtherInit(); 0437 } 0438 0439 0440 bool K3b::Device::Device::furtherInit() 0441 { 0442 #ifdef Q_OS_LINUX 0443 0444 // 0445 // Since all CDR drives at least support WRITINGMODE_TAO, all CDRW drives should support 0446 // mode page 2a and all DVD writer should support mode page 2a or the GET CONFIGURATION 0447 // command this is redundant and may be removed for BSD ports or even completely 0448 // 0449 // We just keep it here because of the "should" in the sentence above. If someone can tell me 0450 // that the linux driver does nothing more we can remove it completely. 0451 // 0452 open(); 0453 int drivetype = ::ioctl( handle(), CDROM_GET_CAPABILITY, CDSL_CURRENT ); 0454 if( drivetype < 0 ) { 0455 qDebug() << "Error while retrieving capabilities."; 0456 close(); 0457 return false; 0458 } 0459 0460 d->readCapabilities |= MEDIA_CD_ROM; 0461 0462 if( drivetype & CDC_CD_R ) 0463 d->writeCapabilities |= MEDIA_CD_R; 0464 if( drivetype & CDC_CD_RW ) 0465 d->writeCapabilities |= MEDIA_CD_RW; 0466 if( drivetype & CDC_DVD_R ) 0467 d->writeCapabilities |= MEDIA_DVD_R; 0468 if( drivetype & CDC_DVD ) 0469 d->readCapabilities |= MEDIA_DVD_ROM; 0470 0471 close(); 0472 0473 #endif // Q_OS_LINUX 0474 #ifdef Q_OS_WIN32 0475 qDebug() << __FUNCTION__ << "to be implemented"; 0476 #endif 0477 return true; 0478 } 0479 0480 0481 void K3b::Device::Device::checkForAncientWriters() 0482 { 0483 // TODO: add a boolean which determines if this device is non-MMC so we may warn the user at K3b startup about it 0484 0485 // 0486 // There are a lot writers out there which behave like the TEAC R5XS 0487 // 0488 if( ( vendor().startsWith("TEAC") && ( description().startsWith("CD-R50S") || 0489 description().startsWith("CD-R55S") ) ) 0490 || 0491 ( vendor().startsWith("SAF") && ( description().startsWith("CD-R2006PLUS") || 0492 description().startsWith("CD-RW226") || 0493 description().startsWith("CD-R4012") ) ) 0494 || 0495 ( vendor().startsWith("JVC") && ( description().startsWith("XR-W2001") || 0496 description().startsWith("XR-W2010") || 0497 description().startsWith("R2626") ) ) 0498 || 0499 ( vendor().startsWith("PINNACLE") && ( description().startsWith("RCD-1000") || 0500 description().startsWith("RCD5020") || 0501 description().startsWith("RCD5040") || 0502 description().startsWith("RCD 4X4") ) ) 0503 || 0504 ( vendor().startsWith("Traxdata") && description().startsWith("CDR4120") ) ) { 0505 d->writeModes = WRITINGMODE_TAO; 0506 d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; 0507 d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; 0508 d->maxWriteSpeed = 4; 0509 d->maxReadSpeed = 12; 0510 d->bufferSize = 1024; 0511 d->burnfree = false; 0512 } 0513 else if( vendor().startsWith("TEAC") ) { 0514 if( description().startsWith("CD-R56S") ) { 0515 d->writeModes |= WRITINGMODE_TAO; 0516 d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; 0517 d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; 0518 d->maxWriteSpeed = 6; 0519 d->maxReadSpeed = 24; 0520 d->bufferSize = 1302; 0521 d->burnfree = false; 0522 } 0523 if( description().startsWith("CD-R58S") ) { 0524 d->writeModes |= WRITINGMODE_TAO; 0525 d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; 0526 d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; 0527 d->maxWriteSpeed = 8; 0528 d->maxReadSpeed = 24; 0529 d->bufferSize = 4096; 0530 d->burnfree = false; 0531 } 0532 } 0533 else if( vendor().startsWith("MATSHITA") ) { 0534 if( description().startsWith("CD-R CW-7501") ) { 0535 d->writeModes = WRITINGMODE_TAO|WRITINGMODE_SAO; 0536 d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; 0537 d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; 0538 d->maxWriteSpeed = 2; 0539 d->maxReadSpeed = 4; 0540 d->bufferSize = 1024; 0541 d->burnfree = false; 0542 } 0543 if( description().startsWith("CD-R CW-7502") ) { 0544 d->writeModes = WRITINGMODE_TAO|WRITINGMODE_SAO; 0545 d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; 0546 d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; 0547 d->maxWriteSpeed = 4; 0548 d->maxReadSpeed = 8; 0549 d->bufferSize = 1024; 0550 d->burnfree = false; 0551 } 0552 else if( description().startsWith("CD-R56S") ) { 0553 d->writeModes |= WRITINGMODE_TAO; 0554 d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; 0555 d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; 0556 d->maxWriteSpeed = 6; 0557 d->maxReadSpeed = 24; 0558 d->bufferSize = 1302; 0559 d->burnfree = false; 0560 } 0561 } 0562 else if( vendor().startsWith("HP") ) { 0563 if( description().startsWith("CD-Writer 6020") ) { 0564 d->writeModes = WRITINGMODE_TAO; 0565 d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; 0566 d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; 0567 d->maxWriteSpeed = 2; 0568 d->maxReadSpeed = 6; 0569 d->bufferSize = 1024; 0570 d->burnfree = false; 0571 } 0572 } 0573 else if( vendor().startsWith( "PHILIPS" ) ) { 0574 if( description().startsWith( "CDD2600" ) ) { 0575 d->writeModes = WRITINGMODE_TAO|WRITINGMODE_SAO; 0576 d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; 0577 d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R; 0578 d->maxWriteSpeed = 2; 0579 d->maxReadSpeed = 6; 0580 d->bufferSize = 1024; 0581 d->burnfree = false; 0582 } 0583 } 0584 } 0585 0586 0587 bool K3b::Device::Device::dao() const 0588 { 0589 return d->writeModes & WRITINGMODE_SAO; 0590 } 0591 0592 0593 bool K3b::Device::Device::supportsRawWriting() const 0594 { 0595 return( writingModes() & (WRITINGMODE_RAW|WRITINGMODE_RAW_R16|WRITINGMODE_RAW_R96P|WRITINGMODE_RAW_R96R) ); 0596 } 0597 0598 0599 bool K3b::Device::Device::writesCd() const 0600 { 0601 return ( d->writeCapabilities & MEDIA_CD_R ) && ( d->writeModes & WRITINGMODE_TAO ); 0602 } 0603 0604 0605 bool K3b::Device::Device::burner() const 0606 { 0607 return ( writesCd() || writesDvd() ); 0608 } 0609 0610 0611 bool K3b::Device::Device::writesCdrw() const 0612 { 0613 return d->writeCapabilities & MEDIA_CD_RW; 0614 } 0615 0616 0617 bool K3b::Device::Device::writesDvd() const 0618 { 0619 return ( writesDvdPlus() || writesDvdMinus() ); 0620 } 0621 0622 0623 bool K3b::Device::Device::writesDvdPlus() const 0624 { 0625 return d->writeCapabilities & (MEDIA_DVD_PLUS_R|MEDIA_DVD_PLUS_RW); 0626 } 0627 0628 0629 bool K3b::Device::Device::writesDvdMinus() const 0630 { 0631 return d->writeCapabilities & (MEDIA_DVD_R|MEDIA_DVD_RW); 0632 } 0633 0634 0635 bool K3b::Device::Device::readsDvd() const 0636 { 0637 return d->readCapabilities & MEDIA_DVD_ROM; 0638 } 0639 0640 0641 K3b::Device::DeviceTypes K3b::Device::Device::type() const 0642 { 0643 DeviceTypes r = {}; 0644 if( readCapabilities() & MEDIA_CD_ROM ) 0645 r |= DEVICE_CD_ROM; 0646 if( writeCapabilities() & MEDIA_CD_R ) 0647 r |= DEVICE_CD_R; 0648 if( writeCapabilities() & MEDIA_CD_RW ) 0649 r |= DEVICE_CD_RW; 0650 if( readCapabilities() & MEDIA_DVD_ROM ) 0651 r |= DEVICE_DVD_ROM; 0652 if( writeCapabilities() & MEDIA_DVD_RAM ) 0653 r |= DEVICE_DVD_RAM; 0654 if( writeCapabilities() & MEDIA_DVD_R ) 0655 r |= DEVICE_DVD_R; 0656 if( writeCapabilities() & MEDIA_DVD_RW ) 0657 r |= DEVICE_DVD_RW; 0658 if( writeCapabilities() & MEDIA_DVD_R_DL ) 0659 r |= DEVICE_DVD_R_DL; 0660 if( writeCapabilities() & MEDIA_DVD_PLUS_R ) 0661 r |= DEVICE_DVD_PLUS_R; 0662 if( writeCapabilities() & MEDIA_DVD_PLUS_RW ) 0663 r |= DEVICE_DVD_PLUS_RW; 0664 if( writeCapabilities() & MEDIA_DVD_PLUS_R_DL ) 0665 r |= DEVICE_DVD_PLUS_R_DL; 0666 if( readCapabilities() & MEDIA_HD_DVD_ROM ) 0667 r |= DEVICE_HD_DVD_ROM; 0668 if( writeCapabilities() & MEDIA_HD_DVD_R ) 0669 r |= DEVICE_HD_DVD_R; 0670 if( writeCapabilities() & MEDIA_HD_DVD_RAM ) 0671 r |= DEVICE_HD_DVD_RAM; 0672 if( readCapabilities() & MEDIA_BD_ROM ) 0673 r |= DEVICE_BD_ROM; 0674 if( writeCapabilities() & MEDIA_BD_R ) 0675 r |= DEVICE_BD_R; 0676 if( writeCapabilities() & MEDIA_BD_RE ) 0677 r |= DEVICE_BD_RE; 0678 0679 return r; 0680 } 0681 0682 0683 K3b::Device::MediaTypes K3b::Device::Device::readCapabilities() const 0684 { 0685 return d->readCapabilities; 0686 } 0687 0688 0689 K3b::Device::MediaTypes K3b::Device::Device::writeCapabilities() const 0690 { 0691 return d->writeCapabilities; 0692 } 0693 0694 0695 K3b::Device::WritingModes K3b::Device::Device::writingModes() const 0696 { 0697 return d->writeModes; 0698 } 0699 0700 0701 bool K3b::Device::Device::burnproof() const 0702 { 0703 return burnfree(); 0704 } 0705 0706 0707 bool K3b::Device::Device::burnfree() const 0708 { 0709 return d->burnfree; 0710 } 0711 0712 0713 bool K3b::Device::Device::isDVD() const 0714 { 0715 if( readsDvd() ) 0716 return( mediaType() & MEDIA_DVD_ALL ); 0717 else 0718 return false; 0719 } 0720 0721 0722 int K3b::Device::Device::isEmpty() const 0723 { 0724 // if the device is already opened we do not close it 0725 // to allow fast multiple method calls in a row 0726 bool needToClose = !isOpen(); 0727 0728 int ret = STATE_UNKNOWN; 0729 if( !open() ) 0730 return STATE_UNKNOWN; 0731 0732 if( !testUnitReady() ) 0733 return STATE_NO_MEDIA; 0734 0735 UByteArray data; 0736 0737 if( readDiscInformation( data ) ) { 0738 disc_info_t* inf = (disc_info_t*)data.data(); 0739 switch( inf->status ) { 0740 case 0: 0741 ret = STATE_EMPTY; 0742 break; 0743 case 1: 0744 ret = STATE_INCOMPLETE; 0745 break; 0746 case 2: 0747 ret = STATE_COMPLETE; 0748 break; 0749 default: 0750 ret = STATE_UNKNOWN; 0751 break; 0752 } 0753 } 0754 0755 if( needToClose ) 0756 close(); 0757 0758 return ret; 0759 } 0760 0761 0762 int K3b::Device::Device::numSessions() const 0763 { 0764 // 0765 // Session Info 0766 // ============ 0767 // Byte 0-1: Data Length 0768 // Byte 2: First Complete Session Number (Hex) - always 1 0769 // Byte 3: Last Complete Session Number (Hex) 0770 // 0771 0772 int ret = -1; 0773 0774 UByteArray data; 0775 0776 int m = mediaType(); 0777 if( m & MEDIA_CD_ALL ) { 0778 // 0779 // Although disk_info should get the real value without ide-scsi 0780 // I keep getting wrong values (the value is too high. I think the leadout 0781 // gets counted as session sometimes :() 0782 // 0783 if( readTocPmaAtip( data, 1, 0, 0 ) ) { 0784 ret = data[3]; 0785 } 0786 else { 0787 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": could not get session info !"; 0788 } 0789 } 0790 else if ( m & ( MEDIA_DVD_PLUS_RW|MEDIA_DVD_RW_OVWR|MEDIA_BD_RE ) ) { 0791 // fabricate value 0792 int e = isEmpty(); 0793 return ( e == STATE_COMPLETE ? 1 : 0 ); 0794 } 0795 else { 0796 if( readDiscInformation( data ) ) { 0797 ret = (int)( data[9]<<8 | data[4] ); 0798 0799 // do only count complete sessions 0800 if( (data[2]>>2) != 3 ) 0801 ret--; 0802 } 0803 } 0804 0805 return ret; 0806 } 0807 0808 0809 K3b::Device::Track::DataMode K3b::Device::Device::getDataMode( const K3b::Msf& sector ) const 0810 { 0811 bool needToClose = !isOpen(); 0812 0813 Track::DataMode ret = Track::UNKNOWN; 0814 0815 if( !open() ) 0816 return ret; 0817 0818 // we use readCdMsf here since it's defined mandatory in MMC1 and 0819 // we only use this method for CDs anyway 0820 unsigned char data[2352]; 0821 bool readSuccess = readCdMsf( data, 2352, 0822 0, // all sector types 0823 false, // no dap 0824 sector, 0825 sector+1, 0826 true, // SYNC 0827 true, // HEADER 0828 true, // SUBHEADER 0829 true, // USER DATA 0830 true, // EDC/ECC 0831 0, // no c2 info 0832 0 ); 0833 0834 if( readSuccess ) { 0835 if ( data[15] == 0x1 ) 0836 ret = Track::MODE1; 0837 else if ( data[15] == 0x2 ) 0838 ret = Track::MODE2; 0839 if ( ret == Track::MODE2 ) { 0840 if ( data[16] == data[20] && 0841 data[17] == data[21] && 0842 data[18] == data[22] && 0843 data[19] == data[23] ) { 0844 if ( data[18] & 0x20 ) 0845 ret = Track::XA_FORM2; 0846 else 0847 ret = Track::XA_FORM1; 0848 } 0849 } 0850 } 0851 0852 if( needToClose ) 0853 close(); 0854 0855 return ret; 0856 } 0857 0858 0859 0860 K3b::Device::Track::DataMode K3b::Device::Device::getTrackDataMode( const K3b::Device::Track& track ) const 0861 { 0862 return getDataMode( track.firstSector() ); 0863 } 0864 0865 0866 K3b::Device::Toc K3b::Device::Device::readToc() const 0867 { 0868 // if the device is already opened we do not close it 0869 // to allow fast multiple method calls in a row 0870 bool needToClose = !isOpen(); 0871 0872 Toc toc; 0873 0874 if( !open() ) 0875 return toc; 0876 0877 int mt = mediaType(); 0878 0879 // 0880 // Use the profile if available because DVD-ROM units need to treat DVD+-R(W) media as DVD-ROM 0881 // if supported at all 0882 // 0883 if( currentProfile() == MEDIA_DVD_ROM ) 0884 mt = MEDIA_DVD_ROM; 0885 0886 if( mt & (MEDIA_DVD_MINUS_ALL|MEDIA_DVD_PLUS_RW|MEDIA_DVD_ROM) ) { 0887 if( !readFormattedToc( toc, mt ) ) { 0888 K3b::Msf size; 0889 if( readCapacity( size ) ) { 0890 Track track; 0891 track.setFirstSector( 0 ); 0892 track.setLastSector( size.lba() ); 0893 track.setSession( 1 ); 0894 track.setType( Track::TYPE_DATA ); 0895 track.setMode( Track::DVD ); 0896 track.setCopyPermitted( mt != MEDIA_DVD_ROM ); 0897 track.setPreEmphasis( mt != MEDIA_DVD_ROM ); 0898 0899 toc.append( track ); 0900 } 0901 else 0902 qDebug() << "(K3b::Device::Device) " << blockDeviceName() 0903 << "READ CAPACITY for toc failed." << Qt::endl; 0904 } 0905 } 0906 0907 else if( mt & (MEDIA_DVD_PLUS_R|MEDIA_DVD_PLUS_R_DL) ) { 0908 // 0909 // a DVD+R disk may have multiple sessions 0910 // every session may contain up to 16 fragments 0911 // if the disk is open there is one open session 0912 // every closed session is viewed as a track whereas 0913 // every fragment of the open session is viewed as a track 0914 // 0915 // We may use 0916 // READ DISK INFORMATION 0917 // READ TRACK INFORMATION: track number FFh, however, does not refer to the invisible track 0918 // READ TOC/PMA/ATIP: form 0 refers to all closed sessions 0919 // form 1 refers to the last closed session 0920 // 0921 readFormattedToc( toc, mt ); 0922 } 0923 0924 else if( mt & MEDIA_BD_ALL ) { 0925 readFormattedToc( toc, mt ); 0926 } 0927 0928 else if( mt == MEDIA_DVD_RAM ) { 0929 qDebug() << "(K3b::Device::readDvdToc) no dvdram support"; 0930 } 0931 0932 0933 else if( mt & MEDIA_CD_ALL ) { 0934 bool success = readRawToc( toc ); 0935 if( !success ) { 0936 success = readFormattedToc( toc, mt ); 0937 0938 #ifdef Q_OS_LINUX 0939 if( !success ) { 0940 qDebug() << "(K3b::Device::Device) MMC READ TOC failed. falling back to cdrom.h."; 0941 readTocLinux(toc); 0942 } 0943 #endif 0944 0945 if( success ) 0946 fixupToc( toc ); 0947 } 0948 } 0949 0950 if( needToClose ) 0951 close(); 0952 0953 return toc; 0954 } 0955 0956 0957 void K3b::Device::Device::readIsrcMcn( K3b::Device::Toc& toc ) const 0958 { 0959 // read MCN and ISRC of all tracks 0960 QByteArray mcn; 0961 if( readMcn( mcn ) ) { 0962 toc.setMcn( mcn ); 0963 qDebug() << "(K3b::Device::Device) found MCN: " << mcn; 0964 } 0965 else 0966 qDebug() << "(K3b::Device::Device) no MCN found."; 0967 0968 for( int i = 1; i <= toc.count(); ++i ) { 0969 QByteArray isrc; 0970 if( toc[i-1].type() == Track::TYPE_AUDIO ) { 0971 if( readIsrc( i, isrc ) ) { 0972 qDebug() << "(K3b::Device::Device) found ISRC for track " << i << ": " << isrc; 0973 toc[i-1].setIsrc( isrc ); 0974 } 0975 else 0976 qDebug() << "(K3b::Device::Device) no ISRC found for track " << i; 0977 } 0978 } 0979 } 0980 0981 0982 bool K3b::Device::Device::readFormattedToc( K3b::Device::Toc& toc, int mt ) const 0983 { 0984 // if the device is already opened we do not close it 0985 // to allow fast multiple method calls in a row 0986 bool needToClose = !isOpen(); 0987 0988 bool success = false; 0989 0990 toc.clear(); 0991 0992 int lastTrack = 0; 0993 0994 UByteArray data; 0995 if( !(mt & MEDIA_CD_ALL) ) { 0996 // 0997 // on DVD-R(W) multisession disks only two sessions are represented as tracks in the readTocPmaAtip 0998 // response (fabricated TOC). Thus, we use readDiscInformation for DVD media to get the proper number of tracks 0999 // 1000 if( readDiscInformation( data ) ) { 1001 lastTrack = (int)( data[11]<<8 | data[6] ); 1002 1003 if( readTrackInformation( data, 1, lastTrack ) ) { 1004 track_info_t* trackInfo = (track_info_t*)data.data(); 1005 1006 if( trackInfo->blank ) { 1007 lastTrack--; 1008 } 1009 1010 success = true; 1011 } 1012 else 1013 return false; 1014 } 1015 else 1016 return false; 1017 } 1018 else { 1019 if( readTocPmaAtip( data, 0, 0, 1 ) ) { 1020 1021 if( data.size() < 4 ) { 1022 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": formatted toc data too small."; 1023 } 1024 else if( data.size() != ( (int)sizeof(toc_track_descriptor) * ((int)data[3]+1) ) + 4 ) { 1025 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": invalid formatted toc data length: " 1026 << (data.size()-2) << Qt::endl; 1027 } 1028 else { 1029 lastTrack = data[3]; 1030 toc_track_descriptor* td = (toc_track_descriptor*)&data[4]; 1031 for( int i = 0; i < lastTrack; ++i ) { 1032 1033 Track track; 1034 unsigned int control = 0; 1035 1036 // 1037 // In case READ TRACK INFORMATION fails: 1038 // no session number info 1039 // no track length and thus possibly incorrect last sector for 1040 // multisession disks 1041 // 1042 track.setFirstSector( from4Byte( td[i].start_adr ) ); 1043 track.setLastSector( from4Byte( td[i+1].start_adr ) - 1 ); 1044 control = td[i].control; 1045 1046 track.setType( (control & 0x4) ? Track::TYPE_DATA : Track::TYPE_AUDIO ); 1047 track.setMode( getTrackDataMode( track ) ); 1048 track.setCopyPermitted( control & 0x2 ); 1049 track.setPreEmphasis( control & 0x1 ); 1050 1051 toc.append( track ); 1052 } 1053 1054 success = true; 1055 } 1056 } 1057 } 1058 1059 1060 // 1061 // Try to get information for all the tracks 1062 // 1063 for( int i = 0; i < lastTrack; ++i ) { 1064 if( toc.count() < i+1 ) 1065 toc.append( Track() ); 1066 1067 UByteArray trackData; 1068 if( readTrackInformation( trackData, 1, i+1 ) ) { 1069 track_info_t* trackInfo = (track_info_t*)trackData.data(); 1070 1071 toc[i].setFirstSector( from4Byte( trackInfo->track_start ) ); 1072 1073 if( i > 0 && toc[i-1].lastSector() == 0 ) 1074 toc[i-1].setLastSector( toc[i].firstSector() - 1 ); 1075 1076 // There are drives that return 0 track length here! 1077 // Some drives even return an invalid length here. :( 1078 if( from4Byte( trackInfo->track_size ) > 0 ) 1079 toc[i].setLastSector( toc[i].firstSector() + from4Byte( trackInfo->track_size ) - 1 ); 1080 1081 if( trackInfo->nwa_v ) { 1082 toc[i].setNextWritableAddress( from4Byte( trackInfo->next_writable ) ); 1083 toc[i].setFreeBlocks( from4Byte( trackInfo->free_blocks ) ); 1084 } 1085 1086 toc[i].setSession( (int)((trackInfo->session_number_m<<8 & 0xf0) | 1087 (trackInfo->session_number_l & 0x0f)) ); //FIXME: is this BCD? 1088 1089 int control = trackInfo->track_mode; 1090 1091 if( mt & MEDIA_CD_ALL ) { 1092 toc[i].setType( (control & 0x4) ? Track::TYPE_DATA : Track::TYPE_AUDIO ); 1093 toc[i].setMode( getTrackDataMode( toc[i] ) ); 1094 } 1095 else { 1096 toc[i].setType( Track::TYPE_DATA ); 1097 toc[i].setMode( Track::DVD ); 1098 } 1099 toc[i].setCopyPermitted( control & 0x2 ); 1100 toc[i].setPreEmphasis( control & 0x1 ); 1101 } 1102 else if( !(mt & MEDIA_CD_ALL) ) { 1103 success = false; 1104 } 1105 } 1106 1107 // this can only happen with DVD media 1108 if( !toc.isEmpty() && toc.last().lastSector() == 0 ) { 1109 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " no track length for the last non-empty track."; 1110 UByteArray trackData; 1111 if( readTrackInformation( trackData, 1, lastTrack+1 ) ) { 1112 track_info_t* trackInfo = (track_info_t*)trackData.data(); 1113 1114 toc.last().setLastSector( from4Byte( trackInfo->track_start ) - 1 ); 1115 } 1116 } 1117 1118 1119 if( needToClose ) 1120 close(); 1121 1122 return success; 1123 } 1124 1125 1126 bool K3b::Device::Device::readRawToc( K3b::Device::Toc& toc ) const 1127 { 1128 // if the device is already opened we do not close it 1129 // to allow fast multiple method calls in a row 1130 bool needToClose = !isOpen(); 1131 1132 bool success = false; 1133 1134 toc.clear(); 1135 1136 if( open() ) { 1137 // 1138 // Read Raw TOC (format: 0010b) 1139 // 1140 // For POINT from 01h-63h we get all the tracks 1141 // POINT a1h gices us the last track number in the session in PMIN 1142 // POINT a2h gives the start of the session lead-out in PMIN,PSEC,PFRAME 1143 // 1144 1145 UByteArray data; 1146 1147 if( readTocPmaAtip( data, 2, false, 1 ) ) { 1148 if( data.size() > 4 ) { 1149 success = true; 1150 1151 toc_raw_track_descriptor* tr = (toc_raw_track_descriptor*)&data[4]; 1152 1153 // 1154 // debug the raw toc data 1155 // 1156 qDebug() << "Session | ADR | CONTROL| TNO | POINT | Min | Sec | Frame | Zero | PMIN | PSEC | PFRAME |"; 1157 for( int i = 0; i < (data.size()-4)/(int)sizeof(toc_raw_track_descriptor); ++i ) { 1158 QString s; 1159 s += QString( " %1 |" ).arg( (int)tr[i].session_number, 6 ); 1160 s += QString( " %1 |" ).arg( (int)tr[i].adr, 6 ); 1161 s += QString( " %1 |" ).arg( (int)tr[i].control, 6 ); 1162 s += QString( " %1 |" ).arg( (int)tr[i].tno, 6 ); 1163 s += QString( " %1 |" ).arg( (int)tr[i].point, 6, 16 ); 1164 s += QString( " %1 |" ).arg( (int)tr[i].min, 6 ); 1165 s += QString( " %1 |" ).arg( (int)tr[i].sec, 6 ); 1166 s += QString( " %1 |" ).arg( (int)tr[i].frame, 6 ); 1167 s += QString( " %1 |" ).arg( (int)tr[i].zero, 6, 16 ); 1168 s += QString( " %1 |" ).arg( (int)tr[i].p_min, 6 ); 1169 s += QString( " %1 |" ).arg( (int)tr[i].p_sec, 6 ); 1170 s += QString( " %1 |" ).arg( (int)tr[i].p_frame, 6 ); 1171 qDebug() << s; 1172 } 1173 1174 // 1175 // First we try to determine if the raw toc data uses BCD values 1176 // 1177 int isBcd = rawTocDataWithBcdValues( data ); 1178 if( isBcd == -1 ) { 1179 return false; 1180 } 1181 1182 K3b::Msf sessionLeadOut; 1183 1184 for( unsigned int i = 0; i < (data.size()-4)/(unsigned int)sizeof(toc_raw_track_descriptor); ++i ) { 1185 if( tr[i].adr == 1 && tr[i].point <= 0x63 ) { 1186 // track 1187 Track track; 1188 track.setSession( tr[i].session_number ); 1189 1190 // :( We use 00:00:00 == 0 lba) 1191 if( isBcd ) 1192 track.setFirstSector( K3b::Msf( K3b::Device::fromBcd(tr[i].p_min), 1193 K3b::Device::fromBcd(tr[i].p_sec), 1194 K3b::Device::fromBcd(tr[i].p_frame) ) - 150 ); 1195 else 1196 track.setFirstSector( K3b::Msf( tr[i].p_min, tr[i].p_sec, tr[i].p_frame ) - 150 ); 1197 1198 track.setType( tr[i].control & 0x4 ? Track::TYPE_DATA : Track::TYPE_AUDIO ); 1199 track.setMode( track.type() == Track::TYPE_DATA ? getTrackDataMode(track) : Track::UNKNOWN ); 1200 track.setCopyPermitted( tr[i].control & 0x2 ); 1201 track.setPreEmphasis( tr[i].control & 0x1 ); 1202 1203 // 1204 // only do this within a session because otherwise we already set the last sector with the session leadout 1205 // 1206 if( !toc.isEmpty() ) 1207 if( toc[toc.count()-1].session() == track.session() ) 1208 toc[toc.count()-1].setLastSector( track.firstSector() - 1 ); 1209 1210 toc.append(track); 1211 } 1212 else if( tr[i].point == 0xa2 ) { 1213 // 1214 // since the session is always reported before the tracks this is where we do this: 1215 // set the previous session's last tracks's last sector to the first sector of the 1216 // session leadout (which was reported before the tracks) 1217 // 1218 // This only happens on multisession CDs 1219 // 1220 if( !toc.isEmpty() ) 1221 toc[toc.count()-1].setLastSector( sessionLeadOut - 1 ); 1222 1223 // this is save since the descriptors are reported in ascending order of the session number 1224 // :( We use 00:00:00 == 0 lba) 1225 if( isBcd ) 1226 sessionLeadOut = K3b::Msf( K3b::Device::fromBcd(tr[i].p_min), 1227 K3b::Device::fromBcd(tr[i].p_sec), 1228 K3b::Device::fromBcd(tr[i].p_frame) ) - 150; 1229 else 1230 sessionLeadOut = K3b::Msf( tr[i].p_min, tr[i].p_sec, tr[i].p_frame ) - 150; 1231 } 1232 } 1233 1234 qDebug() << blockDeviceName() << ": setting last sector of last track to " << (sessionLeadOut-1).lba(); 1235 1236 // set the last track's last sector 1237 if( !toc.isEmpty() ) 1238 toc[toc.count()-1].setLastSector( sessionLeadOut - 1 ); 1239 } 1240 else 1241 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " empty raw toc."; 1242 } 1243 } 1244 1245 if( needToClose ) 1246 close(); 1247 1248 return success; 1249 } 1250 1251 1252 int K3b::Device::Device::rawTocDataWithBcdValues( const UByteArray& data ) const 1253 { 1254 toc_raw_track_descriptor* tr = (toc_raw_track_descriptor*)&data[4]; 1255 1256 bool notBcd = false; 1257 bool notHex = false; 1258 1259 // 1260 // in most cases this will already tell us if a drive does not provide bcd numbers 1261 // (which should be all newer MMC drives) 1262 // 1263 for( unsigned int i = 0; i < (data.size()-4)/(unsigned int)sizeof(toc_raw_track_descriptor); ++i ) { 1264 if( tr[i].adr == 1 && tr[i].point <= 0xa2) { 1265 if( !K3b::Device::isValidBcd(tr[i].p_min) || 1266 !K3b::Device::isValidBcd(tr[i].p_sec) || 1267 !K3b::Device::isValidBcd(tr[i].p_frame) ) { 1268 notBcd = true; 1269 break; 1270 } 1271 1272 // we only need to check sec and frame since min needs to be <= 99 1273 // and bcd values are never bigger than 99. 1274 else if( (int)K3b::Device::fromBcd(tr[i].p_sec) >= 60 || 1275 (int)K3b::Device::fromBcd(tr[i].p_frame) >= 75 ) { 1276 notBcd = true; 1277 break; 1278 } 1279 } 1280 } 1281 1282 1283 // 1284 // all values are valid bcd values but we still don't know for sure if they are really 1285 // used as bcd. So we also check the HEX values. 1286 // 1287 for( unsigned int i = 0; i < (data.size()-4)/(unsigned int)sizeof(toc_raw_track_descriptor); ++i ) { 1288 if( tr[i].adr == 1 && tr[i].point <= 0xa2 ) { 1289 if( (int)tr[i].p_min > 99 || 1290 (int)tr[i].p_sec >= 60 || 1291 (int)tr[i].p_frame >= 75 ) { 1292 notHex = true; 1293 break; 1294 } 1295 } 1296 } 1297 1298 1299 // 1300 // If all values are valid bcd and valid hex we check the start sectors of the tracks. 1301 // 1302 if( !notHex || !notBcd ) { 1303 K3b::Msf sessionLeadOutHex, sessionLeadOutBcd; 1304 K3b::Msf lastTrackHex, lastTrackBcd; 1305 1306 for( unsigned int i = 0; i < (data.size()-4)/(unsigned int)sizeof(toc_raw_track_descriptor); ++i ) { 1307 1308 if( tr[i].adr == 1 ) { 1309 if( tr[i].point < 0x64 ) { 1310 1311 // check hex values 1312 if( K3b::Msf( tr[i].p_min, tr[i].p_sec, tr[i].p_frame ) < 1313 lastTrackHex ) 1314 notHex = true; 1315 1316 // check bcd values 1317 if( K3b::Msf( K3b::Device::fromBcd(tr[i].p_min), K3b::Device::fromBcd(tr[i].p_sec), K3b::Device::fromBcd(tr[i].p_frame) ) < 1318 lastTrackBcd ) 1319 notBcd = true; 1320 1321 lastTrackBcd = K3b::Msf( K3b::Device::fromBcd(tr[i].p_min), K3b::Device::fromBcd(tr[i].p_sec), K3b::Device::fromBcd(tr[i].p_frame) ); 1322 lastTrackHex = K3b::Msf( tr[i].p_min, tr[i].p_sec, tr[i].p_frame ); 1323 } 1324 else if( tr[i].point == 0xa2 ) { 1325 if( sessionLeadOutHex < lastTrackHex ) 1326 notHex = true; 1327 if( sessionLeadOutBcd < lastTrackBcd ) 1328 notBcd = true; 1329 1330 sessionLeadOutHex = K3b::Msf( tr[i].p_min, tr[i].p_sec, tr[i].p_frame ); 1331 sessionLeadOutBcd = K3b::Msf( K3b::Device::fromBcd(tr[i].p_min), K3b::Device::fromBcd(tr[i].p_sec), K3b::Device::fromBcd(tr[i].p_frame) ); 1332 } 1333 } 1334 } 1335 1336 // check the last track 1337 if( sessionLeadOutHex < lastTrackHex ) 1338 notHex = true; 1339 if( sessionLeadOutBcd < lastTrackBcd ) 1340 notBcd = true; 1341 } 1342 1343 1344 if( !notBcd && !notHex ) { 1345 qDebug() << "(K3b::Device::Device) need to compare raw toc to formatted toc. :("; 1346 // 1347 // All values are valid bcd and valid HEX values so we compare with the formatted toc. 1348 // This slows us down a lot but in most cases this should not be reached anyway. 1349 // 1350 // TODO: also check the bcd values 1351 // 1352 K3b::Device::Toc formattedToc; 1353 if( readFormattedToc( formattedToc, MEDIA_CD_ROM ) ) { 1354 for( unsigned int i = 0; i < (data.size()-4)/(unsigned int)sizeof(toc_raw_track_descriptor); ++i ) { 1355 if( tr[i].adr == 1 && tr[i].point < 0x64 ) { 1356 unsigned int track = (int)tr[i].point; 1357 1358 // FIXME: do bcd drive also encode the track number in bcd? If so test it, too. 1359 1360 if( ( int )track > formattedToc.count() ) { 1361 notHex = true; 1362 break; 1363 } 1364 1365 K3b::Msf posHex( tr[i].p_min, 1366 tr[i].p_sec, 1367 tr[i].p_frame ); 1368 K3b::Msf posBcd( K3b::Device::fromBcd(tr[i].p_min), 1369 K3b::Device::fromBcd(tr[i].p_sec), 1370 K3b::Device::fromBcd(tr[i].p_frame) ); 1371 posHex -= 150; 1372 posBcd -= 150; 1373 if( posHex != formattedToc[track-1].firstSector() ) 1374 notHex = true; 1375 if( posBcd != formattedToc[track-1].firstSector() ) 1376 notBcd = true; 1377 } 1378 } 1379 } 1380 } 1381 1382 if( notBcd ) 1383 qDebug() << "(K3b::Device::Device) found invalid bcd values. No bcd toc."; 1384 if( notHex ) 1385 qDebug() << "(K3b::Device::Device) found invalid hex values. No hex toc."; 1386 1387 if( notBcd == notHex ) { 1388 qDebug() << "(K3b::Device::Device) unable to determine if hex (" << notHex << ") or bcd (" << notBcd << ")."; 1389 if( !notHex ) { 1390 qDebug() << "Assuming hex encoding in favor of newer drives and the more reliable raw toc."; 1391 return 0; 1392 } 1393 return -1; 1394 } 1395 else if( notBcd ) 1396 return 0; 1397 else 1398 return 1; 1399 } 1400 1401 1402 K3b::Device::CdText K3b::Device::Device::readCdText() const 1403 { 1404 return CdText( readRawCdText() ); 1405 } 1406 1407 1408 QByteArray K3b::Device::Device::readRawCdText( bool* success ) const 1409 { 1410 // if the device is already opened we do not close it 1411 // to allow fast multiple method calls in a row 1412 bool needToClose = !isOpen(); 1413 1414 QByteArray textData; 1415 1416 if ( success ) 1417 *success = false; 1418 1419 if( open() ) { 1420 UByteArray data; 1421 1422 if( readTocPmaAtip( data, 5, false, 0 ) ) { 1423 // we need more than the header and a multiple of 18 bytes to have valid CD-TEXT 1424 if( data.size() > 4 && data.size()%18 == 4 ) { 1425 textData.append( QByteArray( reinterpret_cast<char*>(data.data()), data.size() ) ); 1426 if ( success ) 1427 *success = true; 1428 } 1429 else { 1430 qDebug() << "invalid CD-TEXT length: " << data.size(); 1431 } 1432 } 1433 1434 if( needToClose ) 1435 close(); 1436 } 1437 1438 return textData; 1439 } 1440 1441 1442 #ifdef Q_OS_LINUX 1443 // fallback 1444 bool K3b::Device::Device::readTocLinux( K3b::Device::Toc& toc ) const 1445 { 1446 // if the device is already opened we do not close it 1447 // to allow fast multiple method calls in a row 1448 bool needToClose = !isOpen(); 1449 1450 bool success = true; 1451 1452 toc.clear(); 1453 1454 struct cdrom_tochdr tochdr; 1455 struct cdrom_tocentry tocentry; 1456 1457 usageLock(); 1458 if( open() ) { 1459 // 1460 // CDROMREADTOCHDR ioctl returns: 1461 // cdth_trk0: First Track Number 1462 // cdth_trk1: Last Track Number 1463 // 1464 if( ::ioctl( d->deviceHandle, CDROMREADTOCHDR, &tochdr ) ) { 1465 qDebug() << "(K3b::Device::Device) could not get toc header !"; 1466 success = false; 1467 } 1468 else { 1469 Track lastTrack; 1470 for (int i = tochdr.cdth_trk0; i <= tochdr.cdth_trk1 + 1; i++) { 1471 ::memset(&tocentry,0,sizeof (struct cdrom_tocentry)); 1472 // get Lead-Out Information too 1473 tocentry.cdte_track = (i<=tochdr.cdth_trk1) ? i : CDROM_LEADOUT; 1474 tocentry.cdte_format = CDROM_LBA; 1475 // 1476 // CDROMREADTOCENTRY ioctl returns: 1477 // cdte_addr.lba: Start Sector Number (LBA Format requested) 1478 // cdte_ctrl: 4 ctrl bits 1479 // 00x0b: 2 audio Channels(no pre-emphasis) 1480 // 00x1b: 2 audio Channels(pre-emphasis) 1481 // 10x0b: audio Channels(no pre-emphasis),reserved in cd-rw 1482 // 10x1b: audio Channels(pre-emphasis),reserved in cd-rw 1483 // 01x0b: data track, recorded uninterrupted 1484 // 01x1b: data track, recorded incremental 1485 // 11xxb: reserved 1486 // xx0xb: digital copy prohibited 1487 // xx1xb: digital copy permitted 1488 // cdte_addr: 4 addr bits (type of Q-Subchannel data) 1489 // 0000b: no Information 1490 // 0001b: current position data 1491 // 0010b: MCN 1492 // 0011b: ISRC 1493 // 0100b-1111b: reserved 1494 // cdte_datamode: 0: Data Mode1 1495 // 1: CD-I 1496 // 2: CD-XA Mode2 1497 // 1498 1499 if( ::ioctl( d->deviceHandle, CDROMREADTOCENTRY, &tocentry ) ) { 1500 qDebug() << "(K3b::Device::Device) error reading tocentry " << i; 1501 success = false; 1502 break; 1503 } 1504 1505 int startSec = tocentry.cdte_addr.lba; 1506 int control = tocentry.cdte_ctrl & 0x0f; 1507 int mode = tocentry.cdte_datamode; 1508 if( i > tochdr.cdth_trk0 ) { 1509 Track track( lastTrack.firstSector(), startSec-1, lastTrack.type(), lastTrack.mode() ); 1510 track.setPreEmphasis( control & 0x1 ); 1511 track.setCopyPermitted( control & 0x2 ); 1512 toc.append( track ); 1513 } 1514 Track::TrackType trackType = Track::TYPE_UNKNOWN; 1515 Track::DataMode trackMode = Track::UNKNOWN; 1516 if( (control & 0x04 ) && (tocentry.cdte_track != CDROM_LEADOUT) ) { 1517 trackType = Track::TYPE_DATA; 1518 if( mode == 1 ) 1519 trackMode = Track::MODE1; 1520 else if( mode == 2 ) 1521 trackMode = Track::MODE2; 1522 1523 Track::DataMode tm = getDataMode(startSec); 1524 if( tm != Track::UNKNOWN ) 1525 trackMode = tm; 1526 } 1527 else 1528 trackType = Track::TYPE_AUDIO; 1529 1530 lastTrack = Track( startSec, startSec, trackType, trackMode ); 1531 } 1532 } 1533 1534 if( needToClose ) 1535 close(); 1536 } 1537 else 1538 success = false; 1539 1540 usageUnlock(); 1541 1542 return success; 1543 } 1544 #endif // Q_OS_LINUX 1545 1546 1547 bool K3b::Device::Device::fixupToc( K3b::Device::Toc& toc ) const 1548 { 1549 bool success = false; 1550 1551 // 1552 // This is a very lame method of fixing the TOC of an Advanced Audio CD 1553 // (a CD with two sessions: one with audio tracks and one with the data track) 1554 // If a drive does not support reading raw toc or reading track info we only 1555 // get every track's first sector. But between sessions there is a gap which is used 1556 // for ms stuff. In this case it's 11400 sectors in size. When ripping ausio we would 1557 // include these 11400 sectors which would result in a strange ending audio file. 1558 // 1559 if( numSessions() > 1 || toc.contentType() == MIXED ) { 1560 qDebug() << "(K3b::Device::Device) fixup multisession toc..."; 1561 1562 // 1563 // we need to update the last sector of every last track in every session 1564 // for now we only update the track before the last session... 1565 // This is the most often case: Advanced Audio CD 1566 // 1567 1568 UByteArray data; 1569 if( readTocPmaAtip( data, 1, false, 0 ) ) { 1570 1571 // 1572 // data[6] - first track number in last complete session 1573 // data[8-11] - start address of first track in last session 1574 // 1575 1576 toc[(unsigned int)data[6]-2].setLastSector( from4Byte( &data[8] ) - 11400 - 1 ); 1577 1578 success = true; 1579 } 1580 else 1581 qDebug() << "(K3b::Device::Device) FIXUP TOC failed."; 1582 } 1583 1584 return success; 1585 } 1586 1587 1588 bool K3b::Device::Device::block( bool b ) const 1589 { 1590 // 1591 // For some reason the Scsi Command does not work here. 1592 // So we use the ioctl on Linux systems 1593 // 1594 #if defined(Q_OS_LINUX) 1595 bool success = false; 1596 bool needToClose = !isOpen(); 1597 usageLock(); 1598 if( open() ) { 1599 success = ( ::ioctl( d->deviceHandle, CDROM_LOCKDOOR, b ? 1 : 0 ) == 0 ); 1600 if( needToClose ) 1601 close(); 1602 } 1603 usageUnlock(); 1604 if ( success ) 1605 return success; 1606 #elif defined(Q_OS_NETBSD) 1607 bool success = false; 1608 bool needToClose = !isOpen(); 1609 int arg = b ? 1 : 0; 1610 usageLock(); 1611 if( open() ) { 1612 success = ( ::ioctl( d->deviceHandle, DIOCLOCK, &arg ) == 0 ); 1613 if( needToClose ) 1614 close(); 1615 } 1616 usageUnlock(); 1617 if ( success ) 1618 return success; 1619 #endif 1620 1621 ScsiCommand cmd( this ); 1622 cmd[0] = MMC_PREVENT_ALLOW_MEDIUM_REMOVAL; 1623 cmd[5] = 0; // Necessary to set the proper command length 1624 if( b ) 1625 cmd[4] = 0x01; 1626 int r = cmd.transport( TR_DIR_WRITE ); 1627 1628 if( r ) 1629 qDebug() << "(K3b::Device::Device) MMC ALLOW MEDIA REMOVAL failed."; 1630 1631 return ( r == 0 ); 1632 } 1633 1634 bool K3b::Device::Device::rewritable() const 1635 { 1636 UByteArray data; 1637 1638 if( readDiscInformation( data ) ) { 1639 disc_info_t* inf = (disc_info_t*)data.data(); 1640 bool e = inf->erasable; 1641 1642 return e; 1643 } 1644 else 1645 return false; 1646 } 1647 1648 1649 bool K3b::Device::Device::eject() const 1650 { 1651 #ifdef Q_OS_NETBSD 1652 bool success = false; 1653 bool needToClose = !isOpen(); 1654 int arg = 0; 1655 1656 usageLock(); 1657 if( open() ) { 1658 if ( ::ioctl( d->deviceHandle, DIOCEJECT, &arg ) >= 0) 1659 success = true; 1660 if( needToClose ) 1661 close(); 1662 } 1663 usageUnlock(); 1664 if ( success ) 1665 return success; 1666 #endif 1667 1668 ScsiCommand cmd( this ); 1669 cmd[0] = MMC_PREVENT_ALLOW_MEDIUM_REMOVAL; 1670 cmd[5] = 0; // Necessary to set the proper command length 1671 cmd.transport( TR_DIR_WRITE ); 1672 1673 cmd[0] = MMC_START_STOP_UNIT; 1674 cmd[5] = 0; // Necessary to set the proper command length 1675 cmd[4] = 0x2; // eject medium LoEj = 1, Start = 0 1676 if (!cmd.transport( TR_DIR_WRITE )) { 1677 return true; 1678 } 1679 1680 #if defined(Q_OS_LINUX) 1681 bool success = false; 1682 bool needToClose = !isOpen(); 1683 1684 usageLock(); 1685 if( open() ) { 1686 if( ::ioctl( d->deviceHandle, CDROMEJECT ) >= 0 ) 1687 success = true; 1688 if( needToClose ) 1689 close(); 1690 } 1691 usageUnlock(); 1692 return success; 1693 #else 1694 return false; 1695 #endif 1696 } 1697 1698 1699 bool K3b::Device::Device::load() const 1700 { 1701 #ifdef Q_OS_NETBSD 1702 bool success = false; 1703 bool needToClose = !isOpen(); 1704 int arg = 0; 1705 1706 usageLock(); 1707 if( open() ) { 1708 if ( ::ioctl( d->deviceHandle, CDIOCCLOSE, &arg ) >= 0) 1709 success = true; 1710 if( needToClose ) 1711 close(); 1712 } 1713 usageUnlock(); 1714 if ( success ) 1715 return success; 1716 #elif defined(Q_OS_LINUX) 1717 bool success = false; 1718 bool needToClose = !isOpen(); 1719 1720 usageLock(); 1721 if( open() ) { 1722 if( ::ioctl( d->deviceHandle, CDROMCLOSETRAY ) >= 0 ) 1723 success = true; 1724 if( needToClose ) 1725 close(); 1726 } 1727 usageUnlock(); 1728 if ( success ) 1729 return success; 1730 #endif 1731 1732 ScsiCommand cmd( this ); 1733 cmd[0] = MMC_START_STOP_UNIT; 1734 cmd[4] = 0x3; // LoEj = 1, Start = 1 1735 cmd[5] = 0; // Necessary to set the proper command length 1736 return !cmd.transport(); 1737 } 1738 1739 1740 bool K3b::Device::Device::setAutoEjectEnabled( bool enabled ) const 1741 { 1742 bool success = false; 1743 #ifdef Q_OS_LINUX 1744 1745 bool needToClose = !isOpen(); 1746 usageLock(); 1747 if ( open() ) { 1748 success = ( ::ioctl( d->deviceHandle, CDROMEJECT_SW, enabled ? 1 : 0 ) == 0 ); 1749 if ( needToClose ) { 1750 close(); 1751 } 1752 } 1753 usageUnlock(); 1754 #endif 1755 return success; 1756 } 1757 1758 1759 K3b::Device::Device::Handle K3b::Device::Device::handle() const 1760 { 1761 return d->deviceHandle; 1762 } 1763 1764 1765 bool K3b::Device::Device::open( bool write ) const 1766 { 1767 if( d->openedReadWrite != write ) 1768 close(); 1769 1770 QMutexLocker ml( &d->openCloseMutex ); 1771 1772 d->openedReadWrite = write; 1773 1774 if( d->deviceHandle == HANDLE_DEFAULT_VALUE) 1775 d->deviceHandle = openDevice( QFile::encodeName(blockDeviceName()), write ); 1776 1777 return ( d->deviceHandle != HANDLE_DEFAULT_VALUE); 1778 } 1779 1780 1781 void K3b::Device::Device::close() const 1782 { 1783 QMutexLocker ml( &d->openCloseMutex ); 1784 1785 if( d->deviceHandle == HANDLE_DEFAULT_VALUE) 1786 return; 1787 1788 #if defined(Q_OS_FREEBSD) 1789 cam_close_device(d->deviceHandle); 1790 #elif defined(Q_OS_WIN32) 1791 CloseHandle(d->deviceHandle); 1792 #else 1793 ::close( d->deviceHandle ); 1794 #endif 1795 d->deviceHandle = HANDLE_DEFAULT_VALUE; 1796 } 1797 1798 1799 bool K3b::Device::Device::isOpen() const 1800 { 1801 return ( d->deviceHandle != HANDLE_DEFAULT_VALUE); 1802 } 1803 1804 1805 int K3b::Device::Device::supportedProfiles() const 1806 { 1807 return d->supportedProfiles; 1808 } 1809 1810 1811 int K3b::Device::Device::currentProfile() const 1812 { 1813 unsigned char profileBuf[8]; 1814 ::memset( profileBuf, 0, 8 ); 1815 1816 ScsiCommand cmd( this ); 1817 cmd[0] = MMC_GET_CONFIGURATION; 1818 cmd[1] = 1; 1819 cmd[8] = 8; 1820 cmd[9] = 0; // Necessary to set the proper command length 1821 1822 if( cmd.transport( TR_DIR_READ, profileBuf, 8 ) ) { 1823 qDebug() << "(K3b::Device::Device) " << blockDeviceName() 1824 << " GET_CONFIGURATION failed." << Qt::endl; 1825 return MEDIA_UNKNOWN; 1826 } 1827 else { 1828 short profile = from2Byte( &profileBuf[6] ); 1829 1830 // 1831 // Plextor drives might not set a current profile 1832 // In that case we get the list of all current profiles 1833 // and simply use the first one in that list. 1834 // 1835 if( profile == 0x00 ) { 1836 qDebug() << "(K3b::Device::Device) " << blockDeviceName() 1837 << " current profile 0. Checking current profile list instead." << Qt::endl; 1838 UByteArray data; 1839 if( getFeature( data, FEATURE_PROFILE_LIST ) ) { 1840 int featureLen( data[11] ); 1841 for( int j = 0; j < featureLen; j+=4 ) { 1842 // use the first current profile we encounter 1843 if( data[12+j+2] & 0x1 ) { 1844 profile = from2Byte( &data[12+j] ); 1845 break; 1846 } 1847 } 1848 } 1849 } 1850 1851 switch (profile) { 1852 case 0x00: return MEDIA_NONE; 1853 case 0x08: return MEDIA_CD_ROM; 1854 case 0x09: return MEDIA_CD_R; 1855 case 0x0A: return MEDIA_CD_RW; 1856 case 0x10: return MEDIA_DVD_ROM; 1857 case 0x11: return MEDIA_DVD_R_SEQ; 1858 case 0x12: return MEDIA_DVD_RAM; 1859 case 0x13: return MEDIA_DVD_RW_OVWR; 1860 case 0x14: return MEDIA_DVD_RW_SEQ; 1861 case 0x15: return MEDIA_DVD_R_DL_SEQ; 1862 case 0x16: return MEDIA_DVD_R_DL_JUMP; 1863 case 0x1A: return MEDIA_DVD_PLUS_RW; 1864 case 0x1B: return MEDIA_DVD_PLUS_R; 1865 case 0x2B: return MEDIA_DVD_PLUS_R_DL; 1866 case 0x40: return MEDIA_BD_ROM; 1867 case 0x41: { 1868 if( featureCurrent( FEATURE_BD_PSEUDO_OVERWRITE ) == 1 ) 1869 return MEDIA_BD_R_SRM_POW; 1870 else 1871 return MEDIA_BD_R_SRM; 1872 } 1873 case 0x42: return MEDIA_BD_R_RRM; 1874 case 0x43: return MEDIA_BD_RE; 1875 case 0x50: return MEDIA_HD_DVD_ROM; 1876 case 0x51: return MEDIA_HD_DVD_R; 1877 case 0x52: return MEDIA_HD_DVD_RAM; 1878 default: return MEDIA_UNKNOWN; 1879 } 1880 } 1881 } 1882 1883 1884 K3b::Device::DiskInfo K3b::Device::Device::diskInfo() const 1885 { 1886 DiskInfo inf; 1887 1888 // if the device is already opened we do not close it 1889 // to allow fast multiple method calls in a row 1890 bool needToClose = !isOpen(); 1891 1892 if( open() ) { 1893 1894 UByteArray data; 1895 1896 // 1897 // The first thing to do should be: checking if a media is loaded 1898 // We cannot rely on the profile here since at least some Plextor 1899 // drives return the NO MEDIUM profile for CD media 1900 // 1901 if( !testUnitReady() ) { 1902 // no disk or tray open 1903 inf.d->diskState = STATE_NO_MEDIA; 1904 inf.d->mediaType = MEDIA_NONE; 1905 inf.d->currentProfile = MEDIA_NONE; 1906 } 1907 else 1908 inf.d->currentProfile = currentProfile(); 1909 1910 if( inf.diskState() != STATE_NO_MEDIA ) { 1911 1912 if( readDiscInformation( data ) ) { 1913 disc_info_t* dInf = (disc_info_t*)data.data(); 1914 // 1915 // Copy the needed values from the disk_info struct 1916 // 1917 switch( dInf->status ) { 1918 case 0: 1919 inf.d->diskState = STATE_EMPTY; 1920 break; 1921 case 1: 1922 inf.d->diskState = STATE_INCOMPLETE; 1923 break; 1924 case 2: 1925 inf.d->diskState = STATE_COMPLETE; 1926 break; 1927 default: 1928 inf.d->diskState = STATE_UNKNOWN; 1929 break; 1930 } 1931 1932 switch( dInf->border ) { 1933 case 0: 1934 inf.d->lastSessionState = STATE_EMPTY; 1935 break; 1936 case 1: 1937 inf.d->lastSessionState = STATE_INCOMPLETE; 1938 break; 1939 case 2: 1940 inf.d->lastSessionState = STATE_COMPLETE; 1941 break; 1942 default: 1943 inf.d->lastSessionState = STATE_UNKNOWN; 1944 break; 1945 } 1946 1947 switch( dInf->bg_f_status&0x3 ) { 1948 case 0x0: 1949 inf.d->bgFormatState = BG_FORMAT_NONE; 1950 break; 1951 case 0x1: 1952 inf.d->bgFormatState = BG_FORMAT_INCOMPLETE; 1953 break; 1954 case 0x2: 1955 inf.d->bgFormatState = BG_FORMAT_IN_PROGRESS; 1956 break; 1957 case 0x3: 1958 inf.d->bgFormatState = BG_FORMAT_COMPLETE; 1959 break; 1960 } 1961 1962 inf.d->numTracks = (dInf->last_track_l & 0xff) | (dInf->last_track_m<<8 & 0xff00); 1963 if( inf.diskState() == STATE_EMPTY ) 1964 inf.d->numTracks = 0; 1965 1966 // FIXME: I am not sure if this is accurate. Better test the last track's RT field 1967 else if( inf.diskState() == STATE_INCOMPLETE ) 1968 inf.d->numTracks--; // do not count the invisible track 1969 1970 inf.d->rewritable = dInf->erasable; 1971 1972 // 1973 // This is the Last Possible Lead-Out Start Address in HMSF format 1974 // This is only valid for CD-R(W) and DVD+R media. 1975 // For complete media this shall be filled with 0xff 1976 // 1977 if( dInf->lead_out_m != 0xff && 1978 dInf->lead_out_r != 0xff && 1979 dInf->lead_out_s != 0xff && 1980 dInf->lead_out_f != 0xff ) 1981 inf.d->capacity = K3b::Msf( dInf->lead_out_m + dInf->lead_out_r*60, 1982 dInf->lead_out_s, 1983 dInf->lead_out_f ) - 150; 1984 1985 // 1986 // This is the position where the next Session shall be recorded in HMSF format 1987 // This is only valid for CD-R(W) and DVD+R media. 1988 // For complete media this shall be filled with 0xff 1989 // 1990 if( dInf->lead_in_m != 0xff && 1991 dInf->lead_in_r != 0xff && 1992 dInf->lead_in_s != 0xff && 1993 dInf->lead_in_f != 0xff ) 1994 inf.d->usedCapacity = K3b::Msf( dInf->lead_in_m + dInf->lead_in_r*60, 1995 dInf->lead_in_s, 1996 dInf->lead_in_f ) - 4500; 1997 } 1998 else { 1999 qDebug() << "(K3b::Device::Device) " << blockDeviceName() 2000 << " fabricating disk information for a stupid device." << Qt::endl; 2001 Toc toc = readToc(); 2002 if( !toc.isEmpty() ) { 2003 inf.d->diskState = STATE_COMPLETE; 2004 inf.d->lastSessionState = STATE_COMPLETE; 2005 inf.d->numTracks = toc.count(); 2006 inf.d->capacity = inf.d->usedCapacity = toc.length(); 2007 } 2008 } 2009 2010 2011 // 2012 // The mediatype needs to be set 2013 // 2014 inf.d->mediaType = mediaType(); 2015 2016 // At least some Plextor drives return profile NONE for CD media 2017 // or CD_ROM for writable media 2018 if( inf.d->mediaType & (MEDIA_UNKNOWN|MEDIA_NONE|MEDIA_CD_ROM) ) { 2019 // probably it is a CD 2020 if( inf.rewritable() ) 2021 inf.d->mediaType = MEDIA_CD_RW; 2022 else if( inf.empty() || inf.appendable() ) 2023 inf.d->mediaType = MEDIA_CD_R; 2024 else 2025 inf.d->mediaType = MEDIA_CD_ROM; 2026 } 2027 2028 if( inf.d->mediaType & MEDIA_DVD_ALL ) { 2029 if( readDvdStructure( data ) ) { 2030 // some debugging stuff 2031 K3b::Msf sda, eda, ea0; 2032 sda = ( data[4+5]<<16 | data[4+6] << 8 | data[4+7] ); 2033 eda = ( data[4+9]<<16 | data[4+10] << 8 | data[4+11] ); 2034 ea0 = ( data[4+13]<<16 | data[4+14] << 8 | data[4+15] ); 2035 2036 qDebug() << "First sec data area: " << sda.toString() 2037 << " (LBA " << QString::number(sda.lba()) 2038 << ") (" << QString::number(sda.mode1Bytes()) << Qt::endl; 2039 qDebug() << "Last sec data area: " << eda.toString() 2040 << " (LBA " << QString::number(eda.lba()) 2041 << ") (" << QString::number(eda.mode1Bytes()) << " Bytes)" << Qt::endl; 2042 qDebug() << "Last sec layer 1: " << ea0.toString() 2043 << " (LBA " << QString::number(ea0.lba()) 2044 << ") (" << QString::number(ea0.mode1Bytes()) << " Bytes)" << Qt::endl; 2045 2046 2047 K3b::Msf da0 = ea0 - sda + 1; 2048 K3b::Msf da1 = eda - ea0; 2049 qDebug() << "Layer 1 length: " << da0.toString() 2050 << " (LBA " << QString::number(da0.lba()) 2051 << ") (" << QString::number(da0.mode1Bytes()) << " Bytes)" << Qt::endl; 2052 qDebug() << "Layer 2 length: " << da1.toString() 2053 << " (LBA " << QString::number(da1.lba()) 2054 << ") (" << QString::number(da1.mode1Bytes()) << " Bytes)" << Qt::endl; 2055 2056 inf.d->numLayers = ((data[6]&0x60) == 0 ? 1 : 2); 2057 2058 bool otp = (data[4+2] & 0xF); 2059 2060 // ea0 is 0 if the medium does not use Opposite track path 2061 if( otp && ea0 > 0 ) 2062 inf.d->firstLayerSize = da0; 2063 else 2064 inf.d->firstLayerSize = 0; 2065 } 2066 else { 2067 qDebug() << "(K3b::Device::Device) Unable to read DVD structure for num of layers."; 2068 inf.d->numLayers = ( (inf.d->mediaType & MEDIA_WRITABLE_DVD_DL) ? 2 : 1 ); 2069 } 2070 } 2071 2072 2073 // 2074 // Number of sessions for non-empty disks 2075 // 2076 if( inf.diskState() != STATE_EMPTY ) { 2077 int sessions = numSessions(); 2078 if( sessions >= 0 ) 2079 inf.d->numSessions = sessions; 2080 else 2081 qDebug() << "(K3b::Device::Device) could not get session info via READ TOC/PMA/ATIP."; 2082 } 2083 else 2084 inf.d->numSessions = 0; 2085 2086 inf.d->mediaId = mediaId( inf.mediaType() ); 2087 2088 // 2089 // Now we determine the size: 2090 2091 // for all empty and appendable media READ FORMAT CAPACITIES should return the proper unformatted size 2092 // for complete disks we may use the READ_CAPACITY command or the start sector from the leadout 2093 // 2094 int media = inf.mediaType(); 2095 // 2096 // Use the profile if available because DVD-ROM units need to treat DVD+-R(W) media as DVD-ROM 2097 // if supported at all 2098 // 2099 if( inf.currentProfile() == MEDIA_DVD_ROM ) 2100 media = MEDIA_DVD_ROM; 2101 2102 switch( media ) { 2103 case MEDIA_CD_R: 2104 case MEDIA_CD_RW: 2105 if( inf.d->capacity == 0 ) { 2106 if( readTocPmaAtip( data, 0x4, true, 0 ) ) { 2107 2108 struct atip_descriptor* atip = (struct atip_descriptor*)data.data(); 2109 2110 if( data.size() >= 11 ) { 2111 inf.d->capacity = K3b::Msf( atip->lead_out_m, atip->lead_out_s, atip->lead_out_f ) - 150; 2112 debugBitfield( &atip->lead_out_m, 3 ); 2113 qDebug() << blockDeviceName() << ": ATIP capacity: " << inf.d->capacity.toString(); 2114 } 2115 } 2116 } 2117 2118 // 2119 // for empty and appendable media capacity and usedCapacity should be filled in from 2120 // diskinfo above. If not they are both still 0 2121 // 2122 if( inf.d->capacity != 0 && 2123 ( inf.diskState() == STATE_EMPTY || inf.d->usedCapacity != 0 ) ) { 2124 // done. 2125 break; 2126 } 2127 Q_FALLTHROUGH(); 2128 2129 default: 2130 case MEDIA_CD_ROM: 2131 if( inf.d->capacity > 0 && inf.d->usedCapacity == 0 ) 2132 inf.d->usedCapacity = inf.d->capacity; 2133 2134 if( inf.d->usedCapacity == 0 ) { 2135 K3b::Msf readCap; 2136 if( readCapacity( readCap ) ) { 2137 qDebug() << "(K3b::Device::Device) READ CAPACITY: " << readCap.toString() 2138 << " other capacity: " << inf.d->capacity.toString() << Qt::endl; 2139 // 2140 // READ CAPACITY returns the last written sector 2141 // that means the size is actually readCap + 1 2142 // 2143 inf.d->usedCapacity = readCap + 1; 2144 } 2145 else { 2146 qDebug() << "(K3b::Device::Device) " << blockDeviceName() 2147 << " Falling back to readToc for capacity." << Qt::endl; 2148 inf.d->usedCapacity = readToc().length(); 2149 } 2150 } 2151 break; 2152 2153 case MEDIA_DVD_ROM: { 2154 K3b::Msf readCap; 2155 if( readCapacity( readCap ) ) { 2156 qDebug() << "(K3b::Device::Device) READ CAPACITY: " << readCap.toString() 2157 << " other capacity: " << inf.d->capacity.toString() << Qt::endl; 2158 // 2159 // READ CAPACITY returns the last written sector 2160 // that means the size is actually readCap + 1 2161 // 2162 inf.d->usedCapacity = readCap + 1; 2163 } 2164 else { 2165 // 2166 // Only one track, use it's size 2167 // 2168 if( readTrackInformation( data, 0x1, 0x1 ) ) { 2169 track_info_t* trackInfo = (track_info_t*)data.data(); 2170 inf.d->usedCapacity = from4Byte( trackInfo->track_size ); 2171 } 2172 else 2173 qDebug() << "(K3b::Device::Device) " << blockDeviceName() 2174 << "READ TRACK INFORMATION for DVD-ROM failed." << Qt::endl; 2175 } 2176 2177 break; 2178 } 2179 2180 case MEDIA_DVD_PLUS_R: 2181 case MEDIA_DVD_PLUS_R_DL: 2182 if( inf.appendable() || inf.empty() ) { 2183 // 2184 // get remaining space via the invisible track 2185 // 2186 if( readTrackInformation( data, 0x1, /*0xff*/ inf.numTracks()+1 ) ) { 2187 track_info_t* trackInfo = (track_info_t*)data.data(); 2188 inf.d->usedCapacity = from4Byte( trackInfo->track_start ); 2189 inf.d->capacity = from4Byte( trackInfo->track_start ) + from4Byte( trackInfo->track_size ); 2190 } 2191 } 2192 else { 2193 if( readTrackInformation( data, 0x1, inf.numTracks() ) ) { 2194 track_info_t* trackInfo = (track_info_t*)data.data(); 2195 inf.d->capacity = inf.d->usedCapacity 2196 = from4Byte( trackInfo->track_start ) + from4Byte( trackInfo->track_size ); 2197 } 2198 } 2199 break; 2200 2201 case MEDIA_DVD_R: 2202 case MEDIA_DVD_R_SEQ: 2203 case MEDIA_DVD_R_DL: 2204 case MEDIA_DVD_R_DL_JUMP: 2205 case MEDIA_DVD_R_DL_SEQ: 2206 // 2207 // get data from the incomplete track (which is NOT the invisible track 0xff) 2208 // This will fail in case the media is complete! 2209 // 2210 if( readTrackInformation( data, 0x1, inf.numTracks()+1 ) ) { 2211 track_info_t* trackInfo = (track_info_t*)data.data(); 2212 inf.d->usedCapacity = from4Byte( trackInfo->track_start ); 2213 inf.d->capacity = from4Byte( trackInfo->free_blocks ) + from4Byte( trackInfo->track_start ); 2214 } 2215 2216 // 2217 // Get the "really" used space without border-out 2218 // 2219 if( !inf.empty() ) { 2220 K3b::Msf readCap; 2221 if( readCapacity( readCap ) ) { 2222 // 2223 // READ CAPACITY returns the last written sector 2224 // that means the size is actually readCap + 1 2225 // 2226 inf.d->usedCapacity = readCap + 1; 2227 } 2228 else 2229 qDebug() << "(K3b::Device::Device) " << blockDeviceName() 2230 << " READ CAPACITY for DVD-R failed." << Qt::endl; 2231 } 2232 2233 break; 2234 2235 case MEDIA_DVD_RW_OVWR: 2236 inf.d->numSessions = 1; 2237 Q_FALLTHROUGH(); 2238 case MEDIA_DVD_RW: 2239 case MEDIA_DVD_RW_SEQ: 2240 // only one track on a DVD-RW media 2241 if( readTrackInformation( data, 0x1, 0x1 ) ) { 2242 track_info_t* trackInfo = (track_info_t*)data.data(); 2243 inf.d->capacity = from4Byte( trackInfo->track_size ); 2244 if( !inf.empty() ) { 2245 if( readFormatCapacity( 0x10, inf.d->capacity ) ) 2246 qDebug() << blockDeviceName() << ": Format capacity 0x10: " << inf.d->capacity.toString(); 2247 2248 inf.d->usedCapacity = from4Byte( trackInfo->track_size ); 2249 } 2250 } 2251 break; 2252 2253 case MEDIA_DVD_PLUS_RW: { 2254 K3b::Msf currentMax; 2255 int currentMaxFormat = 0; 2256 if( readFormatCapacity( 0x26, inf.d->capacity, ¤tMax, ¤tMaxFormat ) ) { 2257 if( currentMaxFormat == 0x1 ) { // unformatted or blank media 2258 inf.d->usedCapacity = 0; 2259 inf.d->capacity = currentMax; 2260 } 2261 else { 2262 inf.d->usedCapacity = currentMax; 2263 // Plextor drives tend to screw things up and report invalid values 2264 // for the max format capacity of 1.4 GB DVD media 2265 if ( inf.bgFormatState() == BG_FORMAT_COMPLETE ) { 2266 inf.d->capacity = currentMax; 2267 } 2268 } 2269 } 2270 else 2271 qDebug() << "(K3b::Device::Device) " << blockDeviceName() 2272 << " READ FORMAT CAPACITIES for DVD+RW failed." << Qt::endl; 2273 2274 break; 2275 } 2276 2277 case MEDIA_BD_R: 2278 case MEDIA_BD_R_SRM: 2279 case MEDIA_BD_R_SRM_POW: 2280 case MEDIA_BD_R_RRM: 2281 // 2282 // get the invisible track's first sector 2283 // or the next writable address of the last open track 2284 // 2285 if( readDiscInformation( data ) ) { 2286 int lastTrack = (int)( data[11]<<8 | data[6] ); 2287 2288 if( readTrackInformation( data, 1, lastTrack ) ) { 2289 2290 // capacity: last track's start address + last track's size 2291 inf.d->capacity = from4Byte( &data[8] ) + from4Byte( &data[24] ); 2292 2293 if( data[6] & 0x80 ) 2294 inf.d->usedCapacity = from4Byte( &data[8] ); 2295 else if( data[7] & 0x1 ) 2296 inf.d->usedCapacity = from4Byte( &data[12] ); 2297 else 2298 inf.d->usedCapacity = inf.d->capacity; 2299 } 2300 } 2301 break; 2302 2303 case MEDIA_BD_RE: { 2304 K3b::Msf currentMax; 2305 int currentMaxFormat = 0; 2306 if ( readFormatCapacity( 0x00, inf.d->capacity, ¤tMax, ¤tMaxFormat ) ) { 2307 if( currentMaxFormat == 0x1 ) { // unformatted or blank media 2308 inf.d->usedCapacity = 0; 2309 inf.d->capacity = currentMax; 2310 } 2311 else { 2312 inf.d->usedCapacity = currentMax; 2313 } 2314 } 2315 else 2316 qDebug() << "(K3b::Device::Device) " << blockDeviceName() 2317 << " READ FORMAT CAPACITIES for BD-RE failed." << Qt::endl; 2318 break; 2319 } 2320 2321 case MEDIA_BD_ROM: { 2322 K3b::Msf readCap; 2323 if( readCapacity( readCap ) ) { 2324 // 2325 // READ CAPACITY returns the last written sector 2326 // that means the size is actually readCap + 1 2327 // 2328 inf.d->usedCapacity = readCap + 1; 2329 } 2330 2331 break; 2332 } 2333 } 2334 } 2335 2336 if( needToClose ) 2337 close(); 2338 } 2339 2340 return inf; 2341 } 2342 2343 2344 K3b::Device::MediaType K3b::Device::Device::mediaType() const 2345 { 2346 K3b::Device::MediaType m = MEDIA_UNKNOWN; 2347 2348 if( testUnitReady() ) { 2349 2350 int p = currentProfile(); 2351 if ( p != -1 ) 2352 m = ( MediaType )p; 2353 2354 if( m & (MEDIA_UNKNOWN|MEDIA_DVD_ROM|MEDIA_HD_DVD_ROM) ) { 2355 // 2356 // We prefer the mediatype as reported by the media since this way 2357 // even ROM drives may report the correct type of writable media. 2358 // 2359 2360 // 4 bytes header + 2048 bytes layer descriptor 2361 UByteArray data; 2362 if( readDvdStructure( data ) ) { 2363 switch( data[4]&0xF0 ) { 2364 case 0x00: m = MEDIA_DVD_ROM; break; 2365 case 0x10: m = MEDIA_DVD_RAM; break; 2366 case 0x20: m = MEDIA_DVD_R; break; // there seems to be no value for DVD-R DL, it reports DVD-R 2367 case 0x30: m = MEDIA_DVD_RW; break; 2368 case 0x40: m = MEDIA_HD_DVD_ROM; break; 2369 case 0x50: m = MEDIA_HD_DVD_R; break; 2370 case 0x60: m = MEDIA_HD_DVD_RAM; break; 2371 case 0x90: m = MEDIA_DVD_PLUS_RW; break; 2372 case 0xA0: m = MEDIA_DVD_PLUS_R; break; 2373 case 0xE0: m = MEDIA_DVD_PLUS_R_DL; break; 2374 default: 2375 qDebug() << "(K3b::Device::Device) unknown dvd media type: " << QString::number(data[4]&0xF0, 8); 2376 break; // unknown 2377 } 2378 } 2379 } 2380 2381 if( m & (MEDIA_UNKNOWN|MEDIA_BD_ROM) ) { 2382 // 2383 // We prefer the mediatype as reported by the media since this way 2384 // even ROM drives may report the correct type of writable media. 2385 // 2386 2387 UByteArray data; 2388 if( readDiscStructure( data, 1, 0 ) ) { 2389 if( data.size() > 4+12 && 2390 data[4+8] == 'B' && data[4+9] == 'D' ) { 2391 switch( data[4+10] ) { 2392 case 'O': m = MEDIA_BD_ROM; break; 2393 case 'W': m = MEDIA_BD_RE; break; 2394 case 'R': m = MEDIA_BD_R; break; 2395 } 2396 } 2397 } 2398 } 2399 2400 // 2401 // Only old CD or DVD devices do not report a current profile 2402 // or report CD-ROM profile for all CD types 2403 // 2404 if( m & (MEDIA_UNKNOWN|MEDIA_CD_ROM) ) { 2405 UByteArray data; 2406 if( readTocPmaAtip( data, 4, false, 0 ) ) { 2407 if( (data[6]>>6)&1 ) 2408 m = MEDIA_CD_RW; 2409 else 2410 m = MEDIA_CD_R; 2411 } 2412 else 2413 m = MEDIA_CD_ROM; 2414 } 2415 } 2416 2417 return m; 2418 } 2419 2420 2421 bool K3b::Device::Device::readSectorsRaw( unsigned char *buf, int start, int count ) const 2422 { 2423 return readCd( buf, count*2352, 2424 0, // all sector types 2425 false, // no dap 2426 start, 2427 count, 2428 true, // SYNC 2429 true, // HEADER 2430 true, // SUBHEADER 2431 true, // USER DATA 2432 true, // EDC/ECC 2433 0, // no c2 info 2434 0 ); 2435 } 2436 2437 2438 2439 void K3b::Device::Device::checkForJustLink() 2440 { 2441 UByteArray ricoh; 2442 if( modeSense( ricoh, 0x30 ) ) { 2443 2444 // 2445 // 8 byte mode header + 6 byte page data 2446 // 2447 2448 if( ricoh.size() >= 14 ) { 2449 ricoh_mode_page_30* rp = (ricoh_mode_page_30*)(ricoh.data()+8); 2450 d->burnfree = rp->BUEFS; 2451 } 2452 } 2453 } 2454 2455 2456 void K3b::Device::Device::checkFeatures() 2457 { 2458 unsigned char header[1024]; 2459 ::memset( header, 0, 1024 ); 2460 2461 ScsiCommand cmd( this ); 2462 cmd[0] = MMC_GET_CONFIGURATION; 2463 cmd[1] = 2; 2464 cmd[9] = 0; // Necessary to set the proper command length 2465 2466 2467 // 2468 // CD writing features 2469 // 2470 cmd[2] = FEATURE_CD_MASTERING>>8; 2471 cmd[3] = FEATURE_CD_MASTERING; 2472 cmd[8] = 8+8; 2473 if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { 2474 unsigned int len = from4Byte( header ); 2475 if( len >= 12 ) { 2476 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "CD Mastering"; 2477 #ifdef WORDS_BIGENDIAN 2478 struct cd_mastering_feature { 2479 unsigned char reserved1 : 1; 2480 unsigned char BUF : 1; // Burnfree 2481 unsigned char SAO : 1; // Session At Once writing 2482 unsigned char raw_ms : 1; // Writing Multisession in Raw Writing Mode 2483 unsigned char raw : 1; // Writing in WRITINGMODE_RAW mode 2484 unsigned char testwrite : 1; // Simulation write support 2485 unsigned char cd_rw : 1; // CD-RW support 2486 unsigned char rw_sub : 1; // Write R-W sub channels with user data 2487 unsigned char max_cue_length[3]; 2488 }; 2489 #else 2490 struct cd_mastering_feature { 2491 unsigned char rw_sub : 1; // Write R-W sub channels with user data 2492 unsigned char cd_rw : 1; // CD-RW support 2493 unsigned char testwrite : 1; // Simulation write support 2494 unsigned char raw : 1; // Writing in WRITINGMODE_RAW mode 2495 unsigned char raw_ms : 1; // Writing Multisession in Raw Writing Mode 2496 unsigned char SAO : 1; // Session At Once writing 2497 unsigned char BUF : 1; // Burnfree 2498 unsigned char reserved1 : 1; 2499 unsigned char max_cue_length[3]; 2500 }; 2501 #endif 2502 2503 struct cd_mastering_feature* p = (struct cd_mastering_feature*)&header[12]; 2504 if( p->BUF ) d->burnfree = true; 2505 d->writeCapabilities |= MEDIA_CD_R; 2506 if( p->cd_rw ) 2507 d->writeCapabilities |= MEDIA_CD_RW; 2508 // if( p->WRITINGMODE_SAO ) d->writeModes |= WRITINGMODE_SAO; 2509 // if( p->raw || p->raw_ms ) d->writeModes |= WRITINGMODE_RAW; // WRITINGMODE_RAW16 always supported when raw is supported? 2510 } 2511 } 2512 2513 cmd[2] = FEATURE_CD_TRACK_AT_ONCE>>8; 2514 cmd[3] = FEATURE_CD_TRACK_AT_ONCE; 2515 cmd[8] = 8+8; 2516 if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { 2517 unsigned int len = from4Byte( header ); 2518 if( len >= 12 ) { 2519 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "CD Track At Once"; 2520 #ifdef WORDS_BIGENDIAN 2521 struct cd_track_at_once_feature { 2522 unsigned char reserved1 : 1; 2523 unsigned char BUF : 1; // Burnfree 2524 unsigned char reserved2 : 1; 2525 unsigned char rw_raw : 1; // Writing R-W subcode in Raw mode 2526 unsigned char rw_pack : 1; // Writing R-W subcode in Packet mode 2527 unsigned char testwrite : 1; // Simulation write support 2528 unsigned char cd_rw : 1; // CD-RW support 2529 unsigned char rw_sub : 1; // Write R-W sub channels with user data 2530 unsigned char reserved3; 2531 unsigned char data_type[2]; 2532 }; 2533 #else 2534 struct cd_track_at_once_feature { 2535 unsigned char rw_sub : 1; // Write R-W sub channels with user data 2536 unsigned char cd_rw : 1; // CD-RW support 2537 unsigned char testwrite : 1; // Simulation write support 2538 unsigned char rw_pack : 1; // Writing R-W subcode in Packet mode 2539 unsigned char rw_raw : 1; // Writing R-W subcode in Raw mode 2540 unsigned char reserved2 : 1; 2541 unsigned char BUF : 1; // Burnfree 2542 unsigned char reserved1 : 1; 2543 unsigned char reserved3; 2544 unsigned char data_type[2]; 2545 }; 2546 #endif 2547 2548 struct cd_track_at_once_feature* p = (struct cd_track_at_once_feature*)&header[12]; 2549 d->writeModes |= WRITINGMODE_TAO; 2550 if( p->BUF ) d->burnfree = true; 2551 d->writeCapabilities |= MEDIA_CD_R; 2552 if( p->cd_rw ) 2553 d->writeCapabilities |= MEDIA_CD_RW; 2554 2555 // is the following correct? What exactly does rw_sub tell us? 2556 // if( d->writeModes & WRITINGMODE_RAW ) { 2557 // if( p->rw_raw ) d->writeModes |= WRITINGMODE_RAW_R96R; 2558 // if( p->rw_pack ) d->writeModes |= WRITINGMODE_RAW_R96P; 2559 // } 2560 2561 // // check the data types for 1, 2, and 3 (raw16, raw96p, and raw96r) 2562 // debugBitfield( p->data_type, 2 ); 2563 // if( d->writeModes & WRITINGMODE_RAW ) { 2564 // if( p->data_type[1] & 0x20 ) d->writeModes |= WRITINGMODE_RAW_R16; 2565 // if( p->data_type[1] & 0x40 ) d->writeModes |= WRITINGMODE_RAW_R96P; 2566 // if( p->data_type[1] & 0x80 ) d->writeModes |= WRITINGMODE_RAW_R96R; 2567 // } 2568 } 2569 } 2570 2571 cmd[2] = FEATURE_CD_RW_MEDIA_WRITE_SUPPORT>>8; 2572 cmd[3] = FEATURE_CD_RW_MEDIA_WRITE_SUPPORT; 2573 cmd[8] = 8+8; 2574 if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { 2575 unsigned int len = from4Byte( header ); 2576 if( len >= 12 ) { 2577 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "CD-RW Media Write Support"; 2578 d->writeCapabilities |= (MEDIA_CD_R|MEDIA_CD_RW); 2579 } 2580 } 2581 2582 2583 // 2584 // DVD-ROM 2585 // 2586 // FIXME: since MMC5 the feature descr. is 8 bytes in length including a dvd dl read bit at byte 6 2587 cmd[2] = FEATURE_DVD_READ>>8; 2588 cmd[3] = FEATURE_DVD_READ; 2589 cmd[8] = 8+8; 2590 if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { 2591 unsigned int len = from4Byte( header ); 2592 if( len >= 12 ) { 2593 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "DVD Read (MMC5)"; 2594 d->readCapabilities |= MEDIA_DVD_ROM; 2595 if( header[8+6] & 0x1 ) 2596 d->readCapabilities |= MEDIA_WRITABLE_DVD_DL; 2597 } 2598 } 2599 else { 2600 // retry with pre-MMC5 length 2601 cmd[8] = 8+4; 2602 if( !cmd.transport( TR_DIR_READ, header, 12 ) ) { 2603 unsigned int len = from4Byte( header ); 2604 if( len >= 8 ) { 2605 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "DVD Read (pre-MMC5)"; 2606 d->readCapabilities |= MEDIA_DVD_ROM; 2607 } 2608 } 2609 } 2610 2611 // 2612 // DVD+R(W) writing features 2613 // 2614 cmd[2] = FEATURE_DVD_PLUS_R>>8; 2615 cmd[3] = FEATURE_DVD_PLUS_R; 2616 cmd[8] = 8+8; 2617 if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { 2618 unsigned int len = from4Byte( header ); 2619 if( len >= 12 ) { 2620 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "DVD+R"; 2621 d->readCapabilities |= MEDIA_DVD_PLUS_R; 2622 if( header[12] & 0x1 ) 2623 d->writeCapabilities |= MEDIA_DVD_PLUS_R; 2624 } 2625 } 2626 2627 cmd[2] = FEATURE_DVD_PLUS_RW>>8; 2628 cmd[3] = FEATURE_DVD_PLUS_RW; 2629 cmd[8] = 8+8; 2630 if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { 2631 unsigned int len = from4Byte( header ); 2632 if( len >= 12 ) { 2633 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "DVD+RW"; 2634 #ifdef WORDS_BIGENDIAN 2635 struct dvd_plus_rw_feature { 2636 unsigned char reserved1 : 7; 2637 unsigned char write : 1; 2638 unsigned char reserved2 : 6; 2639 unsigned char quick_start : 1; 2640 unsigned char close_only : 1; 2641 // and some stuff we do not use here... 2642 }; 2643 #else 2644 struct dvd_plus_rw_feature { 2645 unsigned char write : 1; 2646 unsigned char reserved1 : 7; 2647 unsigned char close_only : 1; 2648 unsigned char quick_start : 1; 2649 unsigned char reserved2 : 6; 2650 // and some stuff we do not use here... 2651 }; 2652 #endif 2653 2654 struct dvd_plus_rw_feature* p = (struct dvd_plus_rw_feature*)&header[12]; 2655 d->readCapabilities |= MEDIA_DVD_PLUS_RW; 2656 if( p->write ) 2657 d->writeCapabilities |= MEDIA_DVD_PLUS_RW; 2658 } 2659 } 2660 2661 2662 // some older DVD-ROM drives claim to support DVD+R DL 2663 if( d->writeCapabilities & MEDIA_DVD_PLUS_R ) { 2664 cmd[2] = FEATURE_DVD_PLUS_RW_DUAL_LAYER>>8; 2665 cmd[3] = FEATURE_DVD_PLUS_RW_DUAL_LAYER; 2666 cmd[8] = 8+8; 2667 if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { 2668 unsigned int len = from4Byte( header ); 2669 if( len >= 12 ) { 2670 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "DVD+RW Double Layer"; 2671 d->readCapabilities |= MEDIA_DVD_PLUS_RW_DL; 2672 if( header[12] & 0x1 ) 2673 d->writeCapabilities |= MEDIA_DVD_PLUS_RW_DL; 2674 } 2675 } 2676 2677 cmd[2] = FEATURE_DVD_PLUS_R_DUAL_LAYER>>8; 2678 cmd[3] = FEATURE_DVD_PLUS_R_DUAL_LAYER; 2679 cmd[8] = 8+8; 2680 if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { 2681 unsigned int len = from4Byte( header ); 2682 if( len >= 12 ) { 2683 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "DVD+R Double Layer"; 2684 d->readCapabilities |= MEDIA_DVD_PLUS_R_DL; 2685 if( header[12] & 0x1 ) 2686 d->writeCapabilities |= MEDIA_DVD_PLUS_R_DL; 2687 } 2688 } 2689 } 2690 2691 2692 // 2693 // Blue Ray 2694 // 2695 // We do not care for the different BD classes and versions here 2696 // 2697 cmd[2] = FEATURE_BD_READ>>8; 2698 cmd[3] = FEATURE_BD_READ; 2699 cmd[8] = 8+32; 2700 if( !cmd.transport( TR_DIR_READ, header, 40 ) ) { 2701 unsigned int len = from4Byte( header ); 2702 if( len >= 36 ) { 2703 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "BD Read"; 2704 if( header[8+8] || header[8+9] || header[8+10] || header[8+11] || header[8+12] || header[8+13] || header[8+14] || header[8+15] ) 2705 d->readCapabilities |= MEDIA_BD_RE; 2706 if( header[8+16] || header[8+17] || header[8+18] || header[8+19] || header[8+20] || header[8+21] || header[8+22] || header[8+23] ) 2707 d->readCapabilities |= MEDIA_BD_R; 2708 if( header[8+24] || header[8+25] || header[8+26] || header[8+27] || header[8+28] || header[8+29] || header[8+30] || header[8+31] ) 2709 d->readCapabilities |= MEDIA_BD_ROM; 2710 } 2711 } 2712 2713 cmd[2] = FEATURE_BD_WRITE>>8; 2714 cmd[3] = FEATURE_BD_WRITE; 2715 cmd[8] = 8+24; 2716 if( !cmd.transport( TR_DIR_READ, header, 32 ) ) { 2717 unsigned int len = from4Byte( header ); 2718 if( len >= 28 ) { 2719 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "BD Write"; 2720 if( header[8+8] || header[8+9] || header[8+10] || header[8+11] || header[8+12] || header[8+13] || header[8+14] || header[8+15] ) 2721 d->writeCapabilities |= MEDIA_BD_RE; 2722 if( header[8+16] || header[8+17] || header[8+18] || header[8+19] || header[8+20] || header[8+21] || header[8+22] || header[8+23] ) { 2723 d->writeCapabilities |= (MEDIA_BD_R|MEDIA_BD_R_SRM); 2724 d->writeModes |= WRITINGMODE_SRM; 2725 2726 cmd[2] = FEATURE_BD_PSEUDO_OVERWRITE>>8; 2727 cmd[3] = FEATURE_BD_PSEUDO_OVERWRITE; 2728 cmd[8] = 8+8; 2729 if( !cmd.transport( TR_DIR_READ, header, 8+8 ) ) { 2730 unsigned int len = from4Byte( header ); 2731 if( len >= 4+8 ) { 2732 d->writeCapabilities |= MEDIA_BD_R_SRM_POW; 2733 d->writeModes |= WRITINGMODE_SRM_POW; 2734 } 2735 } 2736 2737 cmd[2] = FEATURE_RANDOM_WRITABLE>>8; 2738 cmd[3] = FEATURE_RANDOM_WRITABLE; 2739 cmd[8] = 8+16; 2740 if( !cmd.transport( TR_DIR_READ, header, 8+16 ) ) { 2741 unsigned int len = from4Byte( header ); 2742 if( len >= 4+16 ) { 2743 d->writeCapabilities |= MEDIA_BD_R_RRM; 2744 d->writeModes |= WRITINGMODE_RRM; 2745 } 2746 } 2747 } 2748 } 2749 } 2750 2751 2752 2753 // 2754 // DVD-R(W) 2755 // 2756 cmd[2] = FEATURE_DVD_R_RW_WRITE>>8; 2757 cmd[3] = FEATURE_DVD_R_RW_WRITE; 2758 cmd[8] = 16; 2759 if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { 2760 unsigned int len = from4Byte( header ); 2761 if( len >= 12 ) { 2762 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "DVD-R/-RW Write"; 2763 #ifdef WORDS_BIGENDIAN 2764 struct dvd_r_rw_write_feature { 2765 unsigned char reserved1 : 1; 2766 unsigned char BUF : 1; // Burnfree 2767 unsigned char reserved2 : 2; 2768 unsigned char RDL : 1; 2769 unsigned char testwrite : 1; // Simulation write support 2770 unsigned char dvd_rw : 1; // DVD-RW Writing 2771 unsigned char reserved3 : 1; 2772 unsigned char reserved4[3]; 2773 }; 2774 #else 2775 struct dvd_r_rw_write_feature { 2776 unsigned char reserved3 : 1; 2777 unsigned char dvd_rw : 1; // DVD-RW Writing 2778 unsigned char testwrite : 1; // Simulation write support 2779 unsigned char RDL : 1; 2780 unsigned char reserved2 : 2; 2781 unsigned char BUF : 1; // Burnfree 2782 unsigned char reserved1 : 1; 2783 unsigned char reserved4[3]; 2784 }; 2785 #endif 2786 2787 struct dvd_r_rw_write_feature* p = (struct dvd_r_rw_write_feature*)&header[12]; 2788 if( p->BUF ) d->burnfree = true; 2789 d->writeCapabilities |= (MEDIA_DVD_R|MEDIA_DVD_R_SEQ); 2790 if( p->dvd_rw ) 2791 d->writeCapabilities |= (MEDIA_DVD_RW|MEDIA_DVD_RW_SEQ); 2792 if( p->RDL ) 2793 d->writeCapabilities |= (MEDIA_DVD_R_DL|MEDIA_DVD_R_DL_SEQ); 2794 2795 d->dvdMinusTestwrite = p->testwrite; 2796 } 2797 } 2798 2799 2800 // 2801 // DVD-RW restricted overwrite check 2802 // 2803 cmd[2] = FEATURE_RIGID_RESTRICTED_OVERWRITE>>8; 2804 cmd[3] = FEATURE_RIGID_RESTRICTED_OVERWRITE; 2805 cmd[8] = 16; 2806 if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { 2807 unsigned int len = from4Byte( header ); 2808 if( len >= 12 ) { 2809 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "Rigid Restricted Overwrite"; 2810 d->writeModes |= WRITINGMODE_RES_OVWR; 2811 d->writeCapabilities |= (MEDIA_DVD_RW|MEDIA_DVD_RW_OVWR); 2812 } 2813 } 2814 2815 2816 // 2817 // DVD-R Dual Layer Layer 2818 // 2819 cmd[2] = FEATURE_LAYER_JUMP_RECORDING>>8; 2820 cmd[3] = FEATURE_LAYER_JUMP_RECORDING; 2821 cmd[8] = 12; 2822 if( !cmd.transport( TR_DIR_READ, header, 12 ) ) { 2823 // Now the jump feature is longer than 4 bytes but we don't need the link sizes. 2824 unsigned int len = from4Byte( header ); 2825 if( len >= 8 ) { 2826 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "Layer Jump Recording"; 2827 d->writeCapabilities |= (MEDIA_DVD_R_DL|MEDIA_DVD_R_DL_JUMP); 2828 d->writeModes |= WRITINGMODE_LAYER_JUMP; 2829 } 2830 } 2831 2832 2833 // 2834 // HD-DVD-ROM 2835 // 2836 cmd[2] = FEATURE_HD_DVD_READ>>8; 2837 cmd[3] = FEATURE_HD_DVD_READ; 2838 cmd[8] = 16; 2839 if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { 2840 unsigned int len = from4Byte( header ); 2841 if( len >= 12 ) { 2842 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "HD-DVD Read"; 2843 d->readCapabilities |= MEDIA_HD_DVD_ROM; 2844 if( header[8+4] & 0x1 ) 2845 d->readCapabilities |= MEDIA_HD_DVD_R; 2846 if( header[8+6] & 0x1 ) 2847 d->readCapabilities |= MEDIA_HD_DVD_RAM; 2848 } 2849 } 2850 2851 2852 // 2853 // HD-DVD-R(AM) 2854 // 2855 cmd[2] = FEATURE_HD_DVD_WRITE>>8; 2856 cmd[3] = FEATURE_HD_DVD_WRITE; 2857 cmd[8] = 16; 2858 if( !cmd.transport( TR_DIR_READ, header, 16 ) ) { 2859 unsigned int len = from4Byte( header ); 2860 if( len >= 12 ) { 2861 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "HD-DVD Write"; 2862 if( header[8+4] & 0x1 ) 2863 d->writeCapabilities |= MEDIA_HD_DVD_R; 2864 if( header[8+6] & 0x1 ) 2865 d->writeCapabilities |= MEDIA_HD_DVD_RAM; 2866 } 2867 } 2868 2869 2870 2871 // 2872 // Get the profiles 2873 // 2874 // the max len of the returned data is 8 (header) + 4 (feature) + 255 (additional length) 2875 // 2876 cmd[2] = FEATURE_PROFILE_LIST>>8; 2877 cmd[3] = FEATURE_PROFILE_LIST; 2878 cmd[8] = 12; // get the number of returned profiles first 2879 if( !cmd.transport( TR_DIR_READ, header, 12 ) ) { 2880 unsigned int len = from4Byte( header ) + 4; 2881 if( len >= 12 ) { 2882 cmd[7] = len>>8; 2883 cmd[8] = len; 2884 if( !cmd.transport( TR_DIR_READ, header, len ) ) { 2885 int featureLen( header[11] ); 2886 for( int j = 0; j < featureLen; j+=4 ) { 2887 short profile = from2Byte( &header[12+j] ); 2888 2889 switch (profile) { 2890 case 0x08: 2891 d->supportedProfiles |= MEDIA_CD_ROM; 2892 break; 2893 case 0x09: 2894 d->supportedProfiles |= MEDIA_CD_R; 2895 break; 2896 case 0x0A: 2897 d->supportedProfiles |= MEDIA_CD_RW; 2898 break; 2899 case 0x10: 2900 d->supportedProfiles |= MEDIA_DVD_ROM; 2901 // d->readCapabilities |= MEDIA_DVD_ROM; 2902 break; 2903 case 0x11: 2904 d->supportedProfiles |= MEDIA_DVD_R_SEQ; 2905 // d->writeCapabilities |= (MEDIA_DVD_R|MEDIA_DVD_R_SEQ); 2906 break; 2907 case 0x12: 2908 d->supportedProfiles |= MEDIA_DVD_RAM; 2909 // d->readCapabilities |= (MEDIA_DVD_RAM|MEDIA_DVD_ROM); 2910 // d->writeCapabilities |= MEDIA_DVD_RAM; 2911 break; 2912 case 0x13: 2913 d->supportedProfiles |= MEDIA_DVD_RW_OVWR; 2914 // d->writeCapabilities |= (MEDIA_DVD_RW|MEDIA_DVD_RW_OVWR); 2915 break; 2916 case 0x14: 2917 d->supportedProfiles |= MEDIA_DVD_RW_SEQ; 2918 // d->writeCapabilities |= (MEDIA_DVD_RW|MEDIA_DVD_R|MEDIA_DVD_RW_SEQ|MEDIA_DVD_R_SEQ); 2919 break; 2920 case 0x15: 2921 d->supportedProfiles |= MEDIA_DVD_R_DL_SEQ; 2922 // d->writeCapabilities |= (MEDIA_DVD_R|MEDIA_DVD_R_DL|MEDIA_DVD_R_SEQ|MEDIA_DVD_R_DL_SEQ); 2923 break; 2924 case 0x16: 2925 d->supportedProfiles |= MEDIA_DVD_R_DL_JUMP; 2926 // d->writeCapabilities |= (MEDIA_DVD_R|MEDIA_DVD_R_DL||MEDIA_DVD_R_DL_JUMP); 2927 break; 2928 case 0x1A: 2929 d->supportedProfiles |= MEDIA_DVD_PLUS_RW; 2930 // d->writeCapabilities |= MEDIA_DVD_PLUS_RW; 2931 break; 2932 case 0x1B: 2933 d->supportedProfiles |= MEDIA_DVD_PLUS_R; 2934 // d->writeCapabilities |= MEDIA_DVD_PLUS_R; 2935 break; 2936 case 0x2A: 2937 d->supportedProfiles |= MEDIA_DVD_PLUS_RW_DL; 2938 // d->writeCapabilities |= MEDIA_DVD_PLUS_RW_DL; 2939 break; 2940 case 0x2B: 2941 d->supportedProfiles |= MEDIA_DVD_PLUS_R_DL; 2942 // d->writeCapabilities |= MEDIA_DVD_PLUS_R_DL; 2943 break; 2944 case 0x40: 2945 d->supportedProfiles |= MEDIA_BD_ROM; 2946 break; 2947 case 0x41: 2948 d->supportedProfiles |= MEDIA_BD_R_SRM; 2949 break; 2950 case 0x42: 2951 d->supportedProfiles |= MEDIA_BD_R_RRM; 2952 break; 2953 case 0x43: 2954 d->supportedProfiles |= MEDIA_BD_RE; 2955 break; 2956 case 0x50: 2957 d->supportedProfiles |= MEDIA_HD_DVD_ROM; 2958 break; 2959 case 0x51: 2960 d->supportedProfiles |= MEDIA_HD_DVD_R; 2961 break; 2962 case 0x52: 2963 d->supportedProfiles |= MEDIA_HD_DVD_RAM; 2964 break; 2965 default: 2966 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " unknown profile: " 2967 << profile << Qt::endl; 2968 } 2969 } 2970 2971 // some older DVD-ROM drives claim to support DVD+R DL 2972 if( !(d->supportedProfiles & MEDIA_DVD_PLUS_R) ) { 2973 // remove DVD+R DL capability 2974 // d->writeCapabilities &= ~MEDIA_DVD_PLUS_R_DL; 2975 d->supportedProfiles &= ~MEDIA_DVD_PLUS_R_DL; 2976 } 2977 } 2978 } 2979 } 2980 } 2981 2982 2983 void K3b::Device::Device::checkFor2AFeatures() 2984 { 2985 UByteArray mm_cap_buffer; 2986 2987 if( modeSense( mm_cap_buffer, 0x2A ) ) { 2988 mm_cap_page_2A* mm_p = (mm_cap_page_2A*)(mm_cap_buffer.data()+8); 2989 if( mm_p->BUF ) 2990 d->burnfree = true; 2991 2992 if( mm_p->cd_r_write ) 2993 d->writeCapabilities |= MEDIA_CD_R; 2994 else 2995 d->writeCapabilities &= ~MEDIA_CD_R; 2996 2997 if( mm_p->cd_rw_write ) 2998 d->writeCapabilities |= MEDIA_CD_RW; 2999 else 3000 d->writeCapabilities &= ~MEDIA_CD_RW; 3001 3002 if( mm_p->dvd_r_write ) 3003 d->writeCapabilities |= MEDIA_DVD_R; 3004 else 3005 d->writeCapabilities &= ~MEDIA_DVD_R; 3006 3007 if( mm_p->dvd_rom_read || mm_p->dvd_r_read ) 3008 d->readCapabilities |= MEDIA_DVD_ROM; 3009 3010 d->maxReadSpeed = from2Byte(mm_p->max_read_speed); 3011 d->bufferSize = from2Byte( mm_p->buffer_size ); 3012 } 3013 else { 3014 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": read mode page 2A failed!"; 3015 } 3016 } 3017 3018 3019 void K3b::Device::Device::checkWritingModes() 3020 { 3021 // if the device is already opened we do not close it 3022 // to allow fast multiple method calls in a row 3023 bool needToClose = !isOpen(); 3024 3025 if( !open() ) 3026 return; 3027 3028 // header size is 8 3029 UByteArray buffer; 3030 3031 if( !modeSense( buffer, 0x05 ) ) { 3032 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": modeSense 0x05 failed!" << Qt::endl 3033 << "(K3b::Device::Device) " << blockDeviceName() << ": Cannot check write modes." << Qt::endl; 3034 } 3035 else if( buffer.size() < 18 ) { // 8 bytes header + 10 bytes used modepage 3036 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": Missing modepage 0x05 data." << Qt::endl 3037 << "(K3b::Device::Device) " << blockDeviceName() << ": Cannot check write modes." << Qt::endl; 3038 } 3039 else { 3040 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": buffer.size(): " << buffer.size(); 3041 3042 wr_param_page_05* mp = (struct wr_param_page_05*)(buffer.data()+8); 3043 3044 // reset some stuff to be on the safe side 3045 mp->PS = 0; 3046 mp->BUFE = 0; 3047 mp->multi_session = 0; 3048 mp->test_write = 0; 3049 mp->LS_V = 0; 3050 mp->copy = 0; 3051 mp->fp = 0; 3052 mp->host_appl_code= 0; 3053 mp->session_format = 0; 3054 mp->audio_pause_len[0] = 0; 3055 mp->audio_pause_len[1] = 150; 3056 3057 // WRITINGMODE_TAO 3058 mp->write_type = 0x01; // Track-at-once 3059 mp->track_mode = 4; // MMC-4 says: 5, cdrecord uses 4 ? 3060 mp->dbtype = 8; // Mode 1 3061 3062 // qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": modeselect WRITINGMODE_TAO data: "; 3063 // debugBitfield( buffer.data(), buffer.size() ); 3064 3065 3066 // 3067 // if a writer does not support WRITINGMODE_TAO it surely does not support WRITINGMODE_SAO or WRITINGMODE_RAW writing since WRITINGMODE_TAO is the minimal 3068 // requirement 3069 // 3070 3071 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": checking for TAO"; 3072 if( modeSelect( buffer, 1, 0 ) ) { 3073 d->writeModes |= WRITINGMODE_TAO; 3074 d->writeCapabilities |= MEDIA_CD_R; 3075 3076 // WRITINGMODE_SAO 3077 mp->write_type = 0x02; // Session-at-once 3078 3079 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": checking for SAO"; 3080 if( modeSelect( buffer, 1, 0 ) ) 3081 d->writeModes |= WRITINGMODE_SAO; 3082 3083 // mp->dbtype = 1; // Raw data with P and Q Sub-channel (2368 bytes) 3084 // if( modeSelect( buffer, 1, 0 ) ) { 3085 // d->writeModes |= WRITINGMODE_RAW_R16; 3086 // } 3087 3088 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": checking for SAO_R96P"; 3089 mp->dbtype = 2; // Raw data with P-W Sub-channel (2448 bytes) 3090 if( modeSelect( buffer, 1, 0 ) ) { 3091 d->writeModes |= WRITINGMODE_SAO_R96P; 3092 } 3093 3094 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": checking for SAO_R96R"; 3095 mp->dbtype = 3; // Raw data with P-W raw Sub-channel (2448 bytes) 3096 if( modeSelect( buffer, 1, 0 ) ) { 3097 d->writeModes |= WRITINGMODE_SAO_R96R; 3098 } 3099 3100 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": checking for RAW_R16"; 3101 // WRITINGMODE_RAW 3102 mp->write_type = 0x03; // WRITINGMODE_RAW 3103 mp->dbtype = 1; // Raw data with P and Q Sub-channel (2368 bytes) 3104 if( modeSelect( buffer, 1, 0 ) ) { 3105 d->writeModes |= WRITINGMODE_RAW; 3106 d->writeModes |= WRITINGMODE_RAW_R16; 3107 } 3108 3109 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": checking for RAW_R96P"; 3110 mp->dbtype = 2; // Raw data with P-W Sub-channel (2448 bytes) 3111 if( modeSelect( buffer, 1, 0 ) ) { 3112 d->writeModes |= WRITINGMODE_RAW; 3113 d->writeModes |= WRITINGMODE_RAW_R96P; 3114 } 3115 3116 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": checking for RAW_R96R"; 3117 mp->dbtype = 3; // Raw data with P-W raw Sub-channel (2448 bytes) 3118 if( modeSelect( buffer, 1, 0 ) ) { 3119 d->writeModes |= WRITINGMODE_RAW; 3120 d->writeModes |= WRITINGMODE_RAW_R96R; 3121 } 3122 } 3123 else { 3124 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": modeSelect with WRITINGMODE_TAO failed. No writer"; 3125 } 3126 } 3127 3128 if( needToClose ) 3129 close(); 3130 } 3131 3132 3133 int K3b::Device::Device::getMaxWriteSpeedVia2A() const 3134 { 3135 int ret = 0; 3136 3137 UByteArray data; 3138 3139 if( modeSense( data, 0x2A ) ) { 3140 mm_cap_page_2A* mm = (mm_cap_page_2A*)&data[8]; 3141 3142 // MMC1 used byte 18 and 19 for the max write speed 3143 if( data.size() > 19 ) 3144 ret = from2Byte( mm->max_write_speed ); 3145 } 3146 3147 return ret; 3148 } 3149 3150 3151 int K3b::Device::Device::determineMaximalWriteSpeed() const 3152 { 3153 int ret = 0; 3154 3155 if( mediaType() & MEDIA_CD_ALL ) { 3156 ret = getMaxWriteSpeedVia2A(); 3157 if ( ret > 0 ) 3158 return ret; 3159 } 3160 3161 QList<int> list = determineSupportedWriteSpeeds(); 3162 if( !list.isEmpty() ) { 3163 for( QList<int>::const_iterator it = list.constBegin(); it != list.constEnd(); ++it ) 3164 ret = qMax( ret, *it ); 3165 } 3166 3167 if( ret > 0 ) 3168 return ret; 3169 else 3170 return d->maxWriteSpeed; 3171 } 3172 3173 3174 QList<int> K3b::Device::Device::determineSupportedWriteSpeeds() const 3175 { 3176 QList<int> ret; 3177 3178 if( burner() ) { 3179 // 3180 // Tests with all my drives resulted in 2A for CD and GET PERFORMANCE for DVD media 3181 // as the valid method of speed detection. 3182 // 3183 MediaType m = mediaType(); 3184 if( m & MEDIA_CD_ALL ) { 3185 if( !getSupportedWriteSpeedsVia2A( ret, m ) ) 3186 getSupportedWriteSpeedsViaGP( ret, m ); 3187 3188 // restrict to max speed, although deprecated in MMC3 is still used everywhere and 3189 // cdrecord also uses it as the max writing speed. 3190 int max = 0; 3191 UByteArray data; 3192 if( modeSense( data, 0x2A ) && data.size() >= 8 ) { 3193 const mm_cap_page_2A* mm = (mm_cap_page_2A const*)&data.at(8); 3194 3195 // MMC1 used byte 18 and 19 for the max write speed 3196 if( data.size() > 19 ) 3197 max = from2Byte( mm->max_write_speed ); 3198 3199 if( max > 0 ) { 3200 while( !ret.isEmpty() && ret.last() > max ) { 3201 qDebug() << "(K3b::Device::Device) " << blockDeviceName() 3202 << " writing speed " << ret.last() << " higher than max " << max << Qt::endl; 3203 ret.pop_back(); 3204 } 3205 } 3206 } 3207 } 3208 else { 3209 if( !getSupportedWriteSpeedsViaGP( ret, m ) ) 3210 getSupportedWriteSpeedsVia2A( ret, m ); 3211 } 3212 3213 // construct writing speeds for old devices 3214 if ( ret.isEmpty() && K3b::Device::isCdMedia( m ) ) { 3215 int max = getMaxWriteSpeedVia2A(); 3216 for ( int i = 1; i <= max/SPEED_FACTOR_CD; i *= 2 ) { 3217 ret.append( i * SPEED_FACTOR_CD ); 3218 } 3219 } 3220 } 3221 3222 return ret; 3223 } 3224 3225 3226 bool K3b::Device::Device::getSupportedWriteSpeedsVia2A(QList<int>& list, 3227 MediaType mediaType) const 3228 { 3229 UByteArray/* QVarLengthArray<unsigned char> */ data; 3230 if (modeSense(data, 0x2A)) { 3231 mm_cap_page_2A* mm = (mm_cap_page_2A*)&data[8]; 3232 3233 // 8 bytes of MODE SENSE(10) header 3234 // 32 bytes offset of speed descriptor list in Mode page 2Ah 3235 // (MMC-3, table 361. Pages of MMC-1 and MMC-2 are smaller.) 3236 if (data.size() > 32 + 8/* replyLen */) { 3237 // we have descriptors 3238 unsigned int numDesc = from2Byte(mm->num_wr_speed_des); 3239 3240 // Ensure number of descriptors claimed actually fits in the data 3241 // returned by the mode sense command. 3242 if (static_cast<int>(numDesc) > ((data.size() - 32 - 8) / 4)) 3243 numDesc = (data.size() - 32 - 8) / 4; 3244 3245 cd_wr_speed_performance* wr = 3246 (cd_wr_speed_performance*)mm->wr_speed_des; 3247 3248 qDebug() << "(K3b::Device::Device) " << blockDeviceName() 3249 << ": Number of supported write speeds via 2A: " 3250 << numDesc << Qt::endl; 3251 3252 for (unsigned int i = 0; i < numDesc; ++i) { 3253 int s = (int)from2Byte(wr[i].wr_speed_supp); 3254 // 3255 // some DVD writers report CD writing speeds here 3256 // If that is the case we cannot rely on the reported speeds 3257 // and need to use the values gained from GET PERFORMANCE. 3258 // 3259 if( isDvdMedia( mediaType ) && s < 1352 ) { 3260 qDebug() << "(K3b::Device::Device) " << blockDeviceName() 3261 << " Invalid DVD speed: " << s << " KB/s" << Qt::endl; 3262 list.clear(); 3263 break; 3264 } 3265 else { 3266 qDebug() << "(K3b::Device::Device) " << blockDeviceName() 3267 << " : " << s << " KB/s" << Qt::endl; 3268 3269 if( isDvdMedia( mediaType ) ) 3270 s = fixupDvdWritingSpeed( s ); 3271 3272 // sort the list 3273 QList<int>::iterator it = list.begin(); 3274 while( it != list.end() && *it < s ) 3275 ++it; 3276 list.insert( it, s ); 3277 } 3278 } 3279 } 3280 } 3281 3282 return !list.isEmpty(); 3283 } 3284 3285 3286 bool K3b::Device::Device::getSupportedWriteSpeedsViaGP( QList<int>& list, MediaType mediaType ) const 3287 { 3288 UByteArray data; 3289 if( getPerformance( data, 0x3, 0x0 ) && data.size() >= 8 ) { 3290 int numDesc = (data.size() - 8)/16; 3291 qDebug() << "(K3b::Device::Device) " << blockDeviceName() 3292 << ": Number of supported write speeds via GET PERFORMANCE: " 3293 << numDesc << Qt::endl; 3294 3295 for( int i = 0; i < numDesc; ++i ) { 3296 int s = from4Byte( &data[20+i*16] ); 3297 3298 // Looks as if the code below does not make sense with most drives 3299 // if( !( data[4+i*16] & 0x2 ) ) { 3300 // qDebug() << "(K3b::Device::Device) " << blockDeviceName() 3301 // << " No write speed: " << s << " KB/s" << Qt::endl; 3302 // continue; 3303 // } 3304 3305 if( isDvdMedia( mediaType ) && s < 1352 ) { 3306 // 3307 // Does this ever happen? 3308 // 3309 qDebug() << "(K3b::Device::Device) " << blockDeviceName() 3310 << " Invalid DVD speed: " << s << " KB/s" << Qt::endl; 3311 } 3312 else { 3313 qDebug() << "(K3b::Device::Device) " << blockDeviceName() 3314 << " : " << s << " KB/s" << Qt::endl; 3315 3316 if( isDvdMedia( mediaType ) ) 3317 s = fixupDvdWritingSpeed( s ); 3318 3319 QList<int>::iterator it = list.begin(); 3320 while( it != list.end() && *it < s ) 3321 ++it; 3322 // the speed might already have been found in the 2a modepage 3323 if( it == list.end() || *it != s ) 3324 list.insert( it, s ); 3325 } 3326 } 3327 } 3328 3329 return !list.isEmpty(); 3330 } 3331 3332 3333 int K3b::Device::Device::getIndex( unsigned long lba ) const 3334 { 3335 // if the device is already opened we do not close it 3336 // to allow fast multiple method calls in a row 3337 bool needToClose = !isOpen(); 3338 3339 if( !open() ) 3340 return -1; 3341 3342 int ret = -1; 3343 3344 // 3345 // first try readCd 3346 // 3347 unsigned char readData[16]; 3348 ::memset( readData, 0, 16 ); 3349 3350 // 3351 // The index is found in the Mode-1 Q which occupies at least 9 out of 10 successive CD frames 3352 // It can be identified by ADR == 1 3353 // 3354 // So if the current sector does not provide Mode-1 Q subchannel we try the previous. 3355 // 3356 3357 if( readCd( readData, 3358 16, 3359 1, // CD-DA 3360 0, // no DAP 3361 lba, 3362 1, 3363 false, 3364 false, 3365 false, 3366 false, 3367 false, 3368 0, 3369 2 // Q-Subchannel 3370 ) ) { 3371 // byte 0: 4 bits CONTROL (MSB) + 4 bits ADR (LSB) 3372 if( (readData[0]&0x0f) == 0x1 ) 3373 ret = readData[2]; 3374 3375 // search previous sector for Mode1 Q Subchannel 3376 else if( readCd( readData, 3377 16, 3378 1, // CD-DA 3379 0, // no DAP 3380 lba-1, 3381 1, 3382 false, 3383 false, 3384 false, 3385 false, 3386 false, 3387 0, 3388 2 // Q-Subchannel 3389 ) ) { 3390 if( (readData[0]&0x0f) == 0x1 ) 3391 ret = readData[2]; 3392 else 3393 ret = -2; 3394 } 3395 } 3396 3397 else { 3398 qDebug() << "(K3b::Device::Device::getIndex) readCd failed. Trying seek."; 3399 3400 UByteArray data; 3401 if( seek( lba ) && readSubChannel( data, 1, 0 ) ) { 3402 // byte 5: 4 bits ADR (MSB) + 4 bits CONTROL (LSB) 3403 if( data.size() > 7 && (data[5]>>4 & 0x0F) == 0x1 ) { 3404 ret = data[7]; 3405 } 3406 else if( seek( lba-1 ) && readSubChannel( data, 1, 0 ) ) { 3407 if( data.size() > 7 && (data[5]>>4 & 0x0F) == 0x1 ) 3408 ret = data[7]; 3409 else 3410 ret = -2; 3411 } 3412 } 3413 else 3414 qDebug() << "(K3b::Device::Device::getIndex) seek or readSubChannel failed."; 3415 } 3416 3417 if( needToClose ) 3418 close(); 3419 3420 return ret; 3421 } 3422 3423 3424 bool K3b::Device::Device::searchIndex0( unsigned long startSec, 3425 unsigned long endSec, 3426 long& pregapStart ) const 3427 { 3428 // if the device is already opened we do not close it 3429 // to allow fast multiple method calls in a row 3430 bool needToClose = !isOpen(); 3431 3432 if( !open() ) 3433 return false; 3434 3435 bool ret = false; 3436 3437 int lastIndex = getIndex( endSec ); 3438 if( lastIndex == 0 ) { 3439 // there is a pregap 3440 // let's find the position where the index turns to 0 3441 // we jump in 1 sec steps backwards until we find an index > 0 3442 unsigned long sector = endSec; 3443 while( lastIndex == 0 && sector > startSec ) { 3444 sector -= 75; 3445 if( sector < startSec ) 3446 sector = startSec; 3447 lastIndex = getIndex(sector); 3448 } 3449 3450 if( lastIndex == 0 ) { 3451 qDebug() << "(K3b::Device::Device) warning: no index != 0 found."; 3452 } 3453 else { 3454 // search forward to the first index = 0 3455 while( getIndex( sector ) != 0 && sector < endSec ) 3456 sector++; 3457 3458 pregapStart = sector; 3459 ret = true; 3460 } 3461 } 3462 else if( lastIndex > 0 ) { 3463 // no pregap 3464 pregapStart = -1; 3465 ret = true; 3466 } 3467 3468 if( needToClose ) 3469 close(); 3470 3471 return ret; 3472 } 3473 3474 3475 bool K3b::Device::Device::indexScan( K3b::Device::Toc& toc ) const 3476 { 3477 // if the device is already opened we do not close it 3478 // to allow fast multiple method calls in a row 3479 bool needToClose = !isOpen(); 3480 3481 if( !open() ) 3482 return false; 3483 3484 bool ret = true; 3485 3486 for( Toc::iterator it = toc.begin(); it != toc.end(); ++it ) { 3487 Track& track = *it; 3488 if( track.type() == Track::TYPE_AUDIO ) { 3489 track.setIndices( QList<K3b::Msf>() ); 3490 long index0 = -1; 3491 if( searchIndex0( track.firstSector().lba(), track.lastSector().lba(), index0 ) ) { 3492 qDebug() << "(K3b::Device::Device) found index 0: " << index0; 3493 } 3494 if( index0 > 0 ) 3495 track.setIndex0( K3b::Msf( index0 - track.firstSector().lba() ) ); 3496 else 3497 track.setIndex0( 0 ); 3498 3499 if( index0 > 0 ) 3500 searchIndexTransitions( track.firstSector().lba(), index0-1, track ); 3501 else 3502 searchIndexTransitions( track.firstSector().lba(), track.lastSector().lba(), track ); 3503 } 3504 } 3505 3506 if( needToClose ) 3507 close(); 3508 3509 return ret; 3510 } 3511 3512 3513 void K3b::Device::Device::searchIndexTransitions( long start, long end, K3b::Device::Track& track ) const 3514 { 3515 qDebug() << "(K3b::Device::Device) searching for index transitions between " 3516 << start << " and " << end << Qt::endl; 3517 int startIndex = getIndex( start ); 3518 int endIndex = getIndex( end ); 3519 3520 if( startIndex < 0 || endIndex < 0 ) { 3521 qDebug() << "(K3b::Device::Device) could not retrieve index values."; 3522 } 3523 else { 3524 qDebug() << "(K3b::Device::Device) indices: " << start << " - " << startIndex 3525 << " and " << end << " - " << endIndex << Qt::endl; 3526 3527 if( startIndex != endIndex ) { 3528 if( start+1 == end ) { 3529 QList<K3b::Msf> indices = track.indices(); 3530 qDebug() << "(K3b::Device::Device) found index transition: " << endIndex << " " << end; 3531 while ( indices.count() < endIndex ) 3532 indices.append( K3b::Msf() ); 3533 // we save the index relative to the first sector 3534 if (endIndex > 0 && endIndex < indices.size() + 1) 3535 indices[endIndex - 1] = K3b::Msf(end) - track.firstSector(); 3536 track.setIndices( indices ); // FIXME: better API 3537 } 3538 else { 3539 searchIndexTransitions( start, start+(end-start)/2, track ); 3540 searchIndexTransitions( start+(end-start)/2, end, track ); 3541 } 3542 } 3543 } 3544 } 3545 3546 3547 int K3b::Device::Device::copyrightProtectionSystemType() const 3548 { 3549 UByteArray dvdheader; 3550 if( readDvdStructure( dvdheader, 0x1 ) ) { 3551 int ret = -1; 3552 if( dvdheader.size() >= 6 ) 3553 ret = dvdheader[4]; 3554 return ret; 3555 } 3556 else 3557 return -1; 3558 } 3559 3560 3561 bool K3b::Device::Device::getNextWritableAdress( unsigned int& lastSessionStart, unsigned int& nextWritableAdress ) const 3562 { 3563 bool success = false; 3564 3565 // FIXME: add CD media handling 3566 int m = mediaType(); 3567 if( m & MEDIA_DVD_ALL ) { 3568 // DVD+RW always returns complete 3569 if( m & (K3b::Device::MEDIA_DVD_PLUS_RW|K3b::Device::MEDIA_DVD_RW_OVWR) ) 3570 return false; 3571 3572 UByteArray data; 3573 3574 if( readDiscInformation( data ) ) { 3575 disc_info_t* inf = (disc_info_t*)data.data(); 3576 3577 // 3578 // The state of the last session has to be "empty" (0x0) or "incomplete" (0x1) 3579 // The procedure here is taken from the dvd+rw-tools 3580 // 3581 if( !(inf->border & 0x2) ) { 3582 // the incomplete track number is the first track in the last session (the empty session) 3583 int nextTrack; 3584 if (m == MEDIA_BD_R_SRM_POW) 3585 nextTrack = inf->last_track_l | inf->last_track_m << 8; 3586 else 3587 nextTrack = inf->first_track_l | inf->first_track_m << 8; 3588 3589 UByteArray trackData; 3590 3591 // Read start address of the incomplete track 3592 if( readTrackInformation( trackData, 0x1, nextTrack ) ) { 3593 if (m == MEDIA_BD_R_SRM_POW && (trackData[7] & 1)) 3594 nextWritableAdress = from4Byte(&trackData[12]); 3595 else 3596 nextWritableAdress = from4Byte( &trackData[8] ); 3597 3598 if (m == MEDIA_BD_R_SRM_POW) { 3599 lastSessionStart = 0; 3600 success = true; 3601 } else { 3602 // Read start address of the first track in the last session 3603 if (readTocPmaAtip(trackData, 0x1, false, 0x0)) { 3604 lastSessionStart = from4Byte(&trackData[8]); 3605 success = true; 3606 } 3607 } 3608 } 3609 } 3610 } 3611 } 3612 3613 return success; 3614 } 3615 3616 3617 int K3b::Device::Device::nextWritableAddress() const 3618 { 3619 UByteArray data; 3620 int nwa = -1; 3621 3622 if( readDiscInformation( data ) ) { 3623 disc_info_t* inf = (disc_info_t*)data.data(); 3624 3625 // 3626 // The state of the last session has to be "empty" (0x0) or "incomplete" (0x1) 3627 // The procedure here is taken from the dvd+rw-tools 3628 // 3629 if( !(inf->border & 0x2) ) { 3630 // the incomplete track number is the first track in the last session (the empty session) 3631 int nextTrack = inf->first_track_l|inf->first_track_m<<8; 3632 3633 UByteArray trackData; 3634 3635 // Read start address of the incomplete track 3636 if( readTrackInformation( trackData, 0x1, nextTrack ) ) { 3637 nwa = from4Byte( &trackData[8] ); 3638 } 3639 3640 // Read start address of the invisible track 3641 else if ( readTrackInformation( trackData, 0x1, 0xff ) ) { 3642 nwa = from4Byte( &trackData[8] ); 3643 } 3644 } 3645 } 3646 3647 return nwa; 3648 } 3649 3650 3651 QByteArray K3b::Device::Device::mediaId( int mediaType ) const 3652 { 3653 QString id; 3654 3655 if( mediaType & MEDIA_CD_ALL ) { 3656 // FIXME: 3657 } 3658 3659 else if( mediaType & MEDIA_DVD_MINUS_ALL ) { 3660 UByteArray data; 3661 if( readDvdStructure( data, 0x0E ) ) { 3662 if( data[4+16] == 3 && data[4+24] == 4 ) { 3663 id = QString::asprintf( "%6.6s%-6.6s", data.data()+4+17, data.data()+4+25 ); 3664 } 3665 } 3666 } 3667 3668 else if( mediaType & MEDIA_DVD_PLUS_ALL ) { 3669 UByteArray data; 3670 if( readDvdStructure( data, 0x11 ) || 3671 readDvdStructure( data, 0x0 ) ) { 3672 id = QString::asprintf( "%8.8s/%3.3s", data.data()+23, data.data()+31 ); 3673 } 3674 } 3675 3676 else if( mediaType & MEDIA_BD_ALL ) { 3677 UByteArray data; 3678 if( readDiscStructure( data, 1, 0 ) ) { 3679 if( data[4+0] == 'D' && data[4+1] == 'I' ) 3680 id = QString::asprintf ("%6.6s/%-3.3s", data.data()+4+100, data.data()+4+106 ); 3681 } 3682 } 3683 3684 return id.toLatin1(); 3685 } 3686 3687 3688 // int K3b::Device::Device::ioctl( int request, ... ) const 3689 // { 3690 // int r = -1; 3691 // #if defined(Q_OS_LINUX) || defined(Q_OS_NETBSD) 3692 // d->mutex.lock(); 3693 3694 // va_list ap; 3695 // va_start( ap, request ); 3696 // r = ::ioctl( d->deviceFd, request, ap ); 3697 // va_end( ap ); 3698 3699 // d->mutex.unlock(); 3700 // #endif 3701 // return r; 3702 // } 3703 3704 3705 void K3b::Device::Device::usageLock() const 3706 { 3707 d->mutex.lock(); 3708 } 3709 3710 3711 void K3b::Device::Device::usageUnlock() const 3712 { 3713 d->mutex.unlock(); 3714 }