1 /*
2     SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org>
3     SPDX-License-Identifier: GPL-2.0-or-later
4 */
5 #include "k3bdevice.h"
6 #include "k3bdeviceglobals.h"
7 #include "k3btrack.h"
8 #include "k3btoc.h"
9 #include "k3bdiskinfo.h"
10 #include "k3bdiskinfo_p.h"
11 #include "k3bmmc.h"
12 #include "k3bscsicommand.h"
13 #include "k3bcrc.h"
14 
15 #include "config-k3b.h"
16 
17 #include <Solid/Device>
18 #include <Solid/OpticalDrive>
19 #include <Solid/Block>
20 #include <Solid/StorageAccess>
21 #ifdef Q_OS_NETBSD
22 #include <Solid/GenericInterface>
23 #endif
24 
25 #include <qglobal.h>
26 #include <QDebug>
27 #include <QFile>
28 #include <QMutex>
29 #include <QStringList>
30 
31 #include <sys/types.h>
32 #include <sys/ioctl.h>
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <sys/stat.h>
40 #include <math.h>
41 #include <stdarg.h>
42 #include <limits.h>
43 
44 
45 #ifdef Q_OS_LINUX
46 
47 #include <linux/version.h>
48 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,70)
49 typedef unsigned char u8;
50 #endif
51 
52 #undef __STRICT_ANSI__
53 #include <linux/cdrom.h>
54 #define __STRICT_ANSI__
55 
56 #endif // Q_OS_LINUX
57 
58 #ifdef Q_OS_FREEBSD
59 #include <stdio.h>
60 #include <camlib.h>
61 #define CD_FRAMESIZE_RAW 2352
62 #endif
63 
64 #ifdef Q_OS_NETBSD
65 #include <sys/cdio.h>
66 #endif
67 
68 #ifdef HAVE_RESMGR
69 extern "C" {
70 #include <resmgr.h>
71 }
72 #endif
73 
74 #ifdef Q_OS_FREEBSD
75 #define HANDLE_DEFAULT_VALUE 0
76 #endif
77 #ifdef Q_OS_WIN32
78 #define HANDLE_DEFAULT_VALUE INVALID_HANDLE_VALUE
79 #endif
80 #ifdef Q_OS_LINUX
81 #define HANDLE_DEFAULT_VALUE -1
82 #endif
83 #ifdef Q_OS_NETBSD
84 #define HANDLE_DEFAULT_VALUE -1
85 #endif
86 
87 //
88 // Very evil hacking: force the speed values to be accurate
89 // as long as "they" do not introduce other "broken" DVD
90 // speeds like 2.4 this works fine
91 //
92 namespace {
fixupDvdWritingSpeed(int speed)93     int fixupDvdWritingSpeed( int speed )
94     {
95         //
96         // Some writers report their speeds in 1000 bytes per second instead of 1024.
97         //
98         if( speed % K3b::Device::SPEED_FACTOR_DVD == 0 )
99             return speed;
100 
101         else if( speed % 1352 == 0 )
102             return speed*K3b::Device::SPEED_FACTOR_DVD/1352;
103 
104         // has to be 2.4x speed
105         else
106             return 3324;
107     }
108 }
109 
110 class K3b::Device::Device::Private
111 {
112 public:
Private()113     Private()
114         : supportedProfiles(0),
115           deviceHandle(HANDLE_DEFAULT_VALUE),
116           openedReadWrite(false),
117           burnfree(false) {
118     }
119 
120     Solid::Device solidDevice;
121 
122     QString vendor;
123     QString description;
124     QString version;
125     int maxReadSpeed;
126     int maxWriteSpeed;
127     int currentWriteSpeed;
128 
129     bool dvdMinusTestwrite;
130 
131     int bufferSize;
132 
133     WritingModes writeModes;
134 
135     QString blockDevice;
136     QString genericDevice;
137 
138     MediaTypes readCapabilities;
139     MediaTypes writeCapabilities;
140     MediaTypes supportedProfiles;
141     Handle deviceHandle;
142     bool openedReadWrite;
143     bool burnfree;
144 
145     QMutex mutex;
146     QMutex openCloseMutex;
147 };
148 
149 #ifdef Q_OS_FREEBSD
openDevice(const char * name,bool write)150 K3b::Device::Device::Handle K3b::Device::openDevice( const char* name, bool write )
151 {
152     K3b::Device::Device::Handle handle = cam_open_device (name, O_RDWR);
153         qDebug() << "(K3b::Device::openDevice) open device " << name
154                  << ((handle)?" succeeded.":" failed.") << endl;
155     return handle;
156 }
157 #endif
158 
159 
160 #if defined(Q_OS_LINUX) || defined(Q_OS_NETBSD)
openDevice(const char * name,bool write)161 K3b::Device::Device::Handle K3b::Device::openDevice( const char* name, bool write )
162 {
163     K3b::Device::Device::Handle fd = HANDLE_DEFAULT_VALUE;
164     int flags = O_NONBLOCK | O_CLOEXEC;
165     if( write )
166         flags |= O_RDWR;
167     else
168         flags |= O_RDONLY;
169 
170 #ifdef HAVE_RESMGR
171     // first try resmgr
172     fd = ::rsm_open_device( name, flags );
173     //  qDebug() << "(K3b::Device::Device) resmgr open: " << fd;
174 #endif
175 
176     if( fd < 0 )
177         fd = ::open( name, flags );
178 
179     if( fd < 0 ) {
180         qDebug() << "(K3b::Device::Device) could not open device "
181                  << name << ( write ? " for writing" : " for reading" ) << endl;
182         qDebug() << "                    (" << QString::fromLocal8Bit( ::strerror(errno) ) << ")";
183         fd = HANDLE_DEFAULT_VALUE;
184 
185         // at least open it read-only (which is sufficient for kernels < 2.6.8 anyway)
186         if( write )
187             return openDevice( name, false );
188     }
189 
190     return fd;
191 }
192 #endif
193 
194 #ifdef Q_OS_WIN32
195 #define NAME_COUNT  25
196 
openDevice(const char * name,bool write)197 K3b::Device::Device::Handle K3b::Device::openDevice( const char* name, bool write )
198 {
199     bool status = false;
200     K3b::Device::Device::Handle deviceHandle = HANDLE_DEFAULT_VALUE;
201     char string[NAME_COUNT + 1];
202     // check if name is already a device name
203     if (name[0] == '\\')
204         strncpy(string, name, NAME_COUNT);
205     else
206         _snprintf(string, NAME_COUNT, "\\\\.\\%s", name);
207     deviceHandle = CreateFileA(string,
208         GENERIC_READ | GENERIC_WRITE , // at least inquiry needs write access
209         FILE_SHARE_READ | (write ? FILE_SHARE_WRITE : 0),
210         NULL,
211         OPEN_EXISTING,
212         0,
213         NULL);
214 
215     if( deviceHandle == INVALID_HANDLE_VALUE )
216         deviceHandle = CreateFileA(string,
217             GENERIC_READ,
218             FILE_SHARE_READ,
219             NULL,
220             OPEN_EXISTING,
221             0,
222             NULL);
223 
224     if (deviceHandle == INVALID_HANDLE_VALUE) {
225         int errorCode = GetLastError();
226         qDebug() << "Error opening " << string << "Error:" << errorCode << endl;
227         return HANDLE_DEFAULT_VALUE;
228     }
229 
230     return deviceHandle;
231 }
232 #endif
233 
234 
Device(const Solid::Device & dev)235 K3b::Device::Device::Device( const Solid::Device& dev )
236 {
237 #ifdef Q_OS_NETBSD
238     const Solid::GenericInterface *gi = dev.as<Solid::GenericInterface>();
239 #endif
240     d = new Private;
241     d->solidDevice = dev;
242     // TODO: block device address might not be "stdio:/path"
243 #ifndef Q_OS_NETBSD
244     d->blockDevice = dev.as<Solid::Block>()->device();
245 #else
246     if (gi->propertyExists("block.netbsd.raw_device"))
247         d->blockDevice = gi->property("block.netbsd.raw_device").toString();
248     else
249         d->blockDevice = dev.as<Solid::Block>()->device();
250 #endif
251     d->writeModes = {};
252     d->maxWriteSpeed = 0;
253     d->maxReadSpeed = 0;
254     d->burnfree = false;
255     d->dvdMinusTestwrite = true;
256     d->bufferSize = 0;
257 }
258 
259 
~Device()260 K3b::Device::Device::~Device()
261 {
262     close();
263     delete d;
264 }
265 
266 
vendor() const267 QString K3b::Device::Device::vendor() const
268 {
269     return d->vendor;
270 }
271 
272 
description() const273 QString K3b::Device::Device::description() const
274 {
275     return d->description;
276 }
277 
278 
version() const279 QString K3b::Device::Device::version() const
280 {
281     return d->version;
282 }
283 
284 
dvdMinusTestwrite() const285 bool K3b::Device::Device::dvdMinusTestwrite() const
286 {
287     return d->dvdMinusTestwrite;
288 }
289 
290 
maxReadSpeed() const291 int K3b::Device::Device::maxReadSpeed() const
292 {
293     return d->maxReadSpeed;
294 }
295 
296 
currentWriteSpeed() const297 int K3b::Device::Device::currentWriteSpeed() const
298 {
299     return d->currentWriteSpeed;
300 }
301 
302 
bufferSize() const303 int K3b::Device::Device::bufferSize() const
304 {
305     return d->bufferSize;
306 }
307 
308 
blockDeviceName() const309 QString K3b::Device::Device::blockDeviceName() const
310 {
311     return d->blockDevice;
312 }
313 
314 
maxWriteSpeed() const315 int K3b::Device::Device::maxWriteSpeed() const
316 {
317     return d->maxWriteSpeed;
318 }
319 
320 
setCurrentWriteSpeed(int s)321 void K3b::Device::Device::setCurrentWriteSpeed( int s )
322 {
323     d->currentWriteSpeed = s;
324 }
325 
326 
setMaxReadSpeed(int s)327 void K3b::Device::Device::setMaxReadSpeed( int s )
328 {
329     d->maxReadSpeed = s;
330 }
331 
332 
setMaxWriteSpeed(int s)333 void K3b::Device::Device::setMaxWriteSpeed( int s )
334 {
335     d->maxWriteSpeed = s;
336 }
337 
338 
solidDevice() const339 Solid::Device K3b::Device::Device::solidDevice() const
340 {
341     return d->solidDevice;
342 }
343 
344 
solidStorage() const345 Solid::StorageAccess* K3b::Device::Device::solidStorage() const
346 {
347      QList<Solid::Device> storages = Solid::Device::listFromType( Solid::DeviceInterface::StorageAccess, d->solidDevice.udi() );
348      if( storages.isEmpty() )
349          return nullptr;
350      else
351          return storages.first().as<Solid::StorageAccess>();
352 }
353 
354 
init(bool bCheckWritingModes)355 bool K3b::Device::Device::init( bool bCheckWritingModes )
356 {
357     qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": init()";
358 
359     //
360     // they all should read CD-ROM.
361     //
362     d->readCapabilities = MEDIA_CD_ROM;
363     d->writeCapabilities = {};
364     d->supportedProfiles = {};
365 
366     if( !open() )
367         return false;
368 
369     //
370     // inquiry
371     // use a 36 bytes buffer since not all devices return the full inquiry struct
372     //
373     ScsiCommand cmd( this );
374     unsigned char buf[36];
375     cmd.clear();
376     ::memset( buf, 0, sizeof(buf) );
377     struct inquiry* inq = (struct inquiry*)buf;
378     cmd[0] = MMC_INQUIRY;
379     cmd[4] = sizeof(buf);
380     cmd[5] = 0;
381     if( cmd.transport( TR_DIR_READ, buf, sizeof(buf) ) ) {
382         qCritical() << "(K3b::Device::Device) Unable to do inquiry." << endl;
383         close();
384         return false;
385     }
386     else {
387         d->vendor = QString::fromLatin1( (char*)(inq->vendor), 8 ).trimmed();
388         d->description = QString::fromLatin1( (char*)(inq->product), 16 ).trimmed();
389         d->version = QString::fromLatin1( (char*)(inq->revision), 4 ).trimmed();
390     }
391 
392     if( d->vendor.isEmpty() )
393         d->vendor = "UNKNOWN";
394     if( d->description.isEmpty() )
395         d->description = "UNKNOWN";
396 
397     //
398     // We probe all features of the device. Since not all devices support the GET CONFIGURATION command
399     // we also query the mode page 2A and use the cdrom.h stuff to get as much information as possible
400     //
401     checkFeatures();
402 
403     //
404     // Check the supported write modes (WRITINGMODE_TAO, WRITINGMODE_SAO, WRITINGMODE_RAW) by trying to set them
405     // We do this before checking mode page 2A in case some readers allow changing
406     // the write parameter page
407     //
408     if( bCheckWritingModes )
409         checkWritingModes();
410 
411     //
412     // Most current drives support the 2A mode page
413     // Here we can get some more information (cdrecord -prcap does exactly this)
414     //
415     checkFor2AFeatures();
416 
417     d->maxWriteSpeed = determineMaximalWriteSpeed();
418 
419     //
420     // Check Just-Link via Ricoh mode page 0x30
421     //
422     if( !d->burnfree )
423         checkForJustLink();
424 
425     //
426     // Support for some very old drives
427     //
428     checkForAncientWriters();
429 
430     //
431     // If it can be written it can also be read
432     //
433     d->readCapabilities |= d->writeCapabilities;
434 
435     close();
436 
437     return furtherInit();
438 }
439 
440 
furtherInit()441 bool K3b::Device::Device::furtherInit()
442 {
443 #ifdef Q_OS_LINUX
444 
445     //
446     // Since all CDR drives at least support WRITINGMODE_TAO, all CDRW drives should support
447     // mode page 2a and all DVD writer should support mode page 2a or the GET CONFIGURATION
448     // command this is redundant and may be removed for BSD ports or even completely
449     //
450     // We just keep it here because of the "should" in the sentence above. If someone can tell me
451     // that the linux driver does nothing more we can remove it completely.
452     //
453     open();
454     int drivetype = ::ioctl( handle(), CDROM_GET_CAPABILITY, CDSL_CURRENT );
455     if( drivetype < 0 ) {
456         qDebug() << "Error while retrieving capabilities.";
457         close();
458         return false;
459     }
460 
461     d->readCapabilities |= MEDIA_CD_ROM;
462 
463     if( drivetype & CDC_CD_R )
464         d->writeCapabilities |= MEDIA_CD_R;
465     if( drivetype & CDC_CD_RW )
466         d->writeCapabilities |= MEDIA_CD_RW;
467     if( drivetype & CDC_DVD_R )
468         d->writeCapabilities |= MEDIA_DVD_R;
469     if( drivetype & CDC_DVD )
470         d->readCapabilities |= MEDIA_DVD_ROM;
471 
472     close();
473 
474 #endif // Q_OS_LINUX
475 #ifdef Q_OS_WIN32
476     qDebug() << __FUNCTION__ << "to be implemented";
477 #endif
478     return true;
479 }
480 
481 
checkForAncientWriters()482 void K3b::Device::Device::checkForAncientWriters()
483 {
484     // TODO: add a boolean which determines if this device is non-MMC so we may warn the user at K3b startup about it
485 
486     //
487     // There are a lot writers out there which behave like the TEAC R5XS
488     //
489     if( ( vendor().startsWith("TEAC") && ( description().startsWith("CD-R50S") ||
490                                            description().startsWith("CD-R55S") ) )
491         ||
492         ( vendor().startsWith("SAF") && ( description().startsWith("CD-R2006PLUS") ||
493                                           description().startsWith("CD-RW226") ||
494                                           description().startsWith("CD-R4012") ) )
495         ||
496         ( vendor().startsWith("JVC") && ( description().startsWith("XR-W2001") ||
497                                           description().startsWith("XR-W2010") ||
498                                           description().startsWith("R2626") ) )
499         ||
500         ( vendor().startsWith("PINNACLE") && ( description().startsWith("RCD-1000") ||
501                                                description().startsWith("RCD5020") ||
502                                                description().startsWith("RCD5040") ||
503                                                description().startsWith("RCD 4X4") ) )
504         ||
505         ( vendor().startsWith("Traxdata") && description().startsWith("CDR4120") ) ) {
506         d->writeModes = WRITINGMODE_TAO;
507         d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R;
508         d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R;
509         d->maxWriteSpeed = 4;
510         d->maxReadSpeed = 12;
511         d->bufferSize = 1024;
512         d->burnfree = false;
513     }
514     else if( vendor().startsWith("TEAC") ) {
515         if( description().startsWith("CD-R56S") ) {
516             d->writeModes |= WRITINGMODE_TAO;
517             d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R;
518             d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R;
519             d->maxWriteSpeed = 6;
520             d->maxReadSpeed = 24;
521             d->bufferSize = 1302;
522             d->burnfree = false;
523         }
524         if( description().startsWith("CD-R58S") ) {
525             d->writeModes |= WRITINGMODE_TAO;
526             d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R;
527             d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R;
528             d->maxWriteSpeed = 8;
529             d->maxReadSpeed = 24;
530             d->bufferSize = 4096;
531             d->burnfree = false;
532         }
533     }
534     else if( vendor().startsWith("MATSHITA") ) {
535         if( description().startsWith("CD-R   CW-7501") ) {
536             d->writeModes = WRITINGMODE_TAO|WRITINGMODE_SAO;
537             d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R;
538             d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R;
539             d->maxWriteSpeed = 2;
540             d->maxReadSpeed = 4;
541             d->bufferSize = 1024;
542             d->burnfree = false;
543         }
544         if( description().startsWith("CD-R   CW-7502") ) {
545             d->writeModes = WRITINGMODE_TAO|WRITINGMODE_SAO;
546             d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R;
547             d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R;
548             d->maxWriteSpeed = 4;
549             d->maxReadSpeed = 8;
550             d->bufferSize = 1024;
551             d->burnfree = false;
552         }
553         else if( description().startsWith("CD-R56S") ) {
554             d->writeModes |= WRITINGMODE_TAO;
555             d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R;
556             d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R;
557             d->maxWriteSpeed = 6;
558             d->maxReadSpeed = 24;
559             d->bufferSize = 1302;
560             d->burnfree = false;
561         }
562     }
563     else if( vendor().startsWith("HP") ) {
564         if( description().startsWith("CD-Writer 6020") ) {
565             d->writeModes = WRITINGMODE_TAO;
566             d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R;
567             d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R;
568             d->maxWriteSpeed = 2;
569             d->maxReadSpeed = 6;
570             d->bufferSize = 1024;
571             d->burnfree = false;
572         }
573     }
574     else if( vendor().startsWith( "PHILIPS" ) ) {
575         if( description().startsWith( "CDD2600" ) ) {
576             d->writeModes = WRITINGMODE_TAO|WRITINGMODE_SAO;
577             d->readCapabilities = MEDIA_CD_ROM|MEDIA_CD_R;
578             d->writeCapabilities = MEDIA_CD_ROM|MEDIA_CD_R;
579             d->maxWriteSpeed = 2;
580             d->maxReadSpeed = 6;
581             d->bufferSize = 1024;
582             d->burnfree = false;
583         }
584     }
585 }
586 
587 
dao() const588 bool K3b::Device::Device::dao() const
589 {
590     return d->writeModes & WRITINGMODE_SAO;
591 }
592 
593 
supportsRawWriting() const594 bool K3b::Device::Device::supportsRawWriting() const
595 {
596     return( writingModes() & (WRITINGMODE_RAW|WRITINGMODE_RAW_R16|WRITINGMODE_RAW_R96P|WRITINGMODE_RAW_R96R) );
597 }
598 
599 
writesCd() const600 bool K3b::Device::Device::writesCd() const
601 {
602     return ( d->writeCapabilities & MEDIA_CD_R ) && ( d->writeModes & WRITINGMODE_TAO );
603 }
604 
605 
burner() const606 bool K3b::Device::Device::burner() const
607 {
608     return ( writesCd() || writesDvd() );
609 }
610 
611 
writesCdrw() const612 bool K3b::Device::Device::writesCdrw() const
613 {
614     return d->writeCapabilities & MEDIA_CD_RW;
615 }
616 
617 
writesDvd() const618 bool K3b::Device::Device::writesDvd() const
619 {
620     return ( writesDvdPlus() || writesDvdMinus() );
621 }
622 
623 
writesDvdPlus() const624 bool K3b::Device::Device::writesDvdPlus() const
625 {
626     return d->writeCapabilities & (MEDIA_DVD_PLUS_R|MEDIA_DVD_PLUS_RW);
627 }
628 
629 
writesDvdMinus() const630 bool K3b::Device::Device::writesDvdMinus() const
631 {
632     return d->writeCapabilities & (MEDIA_DVD_R|MEDIA_DVD_RW);
633 }
634 
635 
readsDvd() const636 bool K3b::Device::Device::readsDvd() const
637 {
638     return d->readCapabilities & MEDIA_DVD_ROM;
639 }
640 
641 
type() const642 K3b::Device::DeviceTypes K3b::Device::Device::type() const
643 {
644     DeviceTypes r = {};
645     if( readCapabilities() & MEDIA_CD_ROM )
646         r |= DEVICE_CD_ROM;
647     if( writeCapabilities() & MEDIA_CD_R )
648         r |= DEVICE_CD_R;
649     if( writeCapabilities() & MEDIA_CD_RW )
650         r |= DEVICE_CD_RW;
651     if( readCapabilities() & MEDIA_DVD_ROM )
652         r |= DEVICE_DVD_ROM;
653     if( writeCapabilities() & MEDIA_DVD_RAM )
654         r |= DEVICE_DVD_RAM;
655     if( writeCapabilities() & MEDIA_DVD_R )
656         r |= DEVICE_DVD_R;
657     if( writeCapabilities() & MEDIA_DVD_RW )
658         r |= DEVICE_DVD_RW;
659     if( writeCapabilities() & MEDIA_DVD_R_DL )
660         r |= DEVICE_DVD_R_DL;
661     if( writeCapabilities() & MEDIA_DVD_PLUS_R )
662         r |= DEVICE_DVD_PLUS_R;
663     if( writeCapabilities() & MEDIA_DVD_PLUS_RW )
664         r |= DEVICE_DVD_PLUS_RW;
665     if( writeCapabilities() & MEDIA_DVD_PLUS_R_DL )
666         r |= DEVICE_DVD_PLUS_R_DL;
667     if( readCapabilities() & MEDIA_HD_DVD_ROM )
668         r |= DEVICE_HD_DVD_ROM;
669     if( writeCapabilities() & MEDIA_HD_DVD_R )
670         r |= DEVICE_HD_DVD_R;
671     if( writeCapabilities() & MEDIA_HD_DVD_RAM )
672         r |= DEVICE_HD_DVD_RAM;
673     if( readCapabilities() & MEDIA_BD_ROM )
674         r |= DEVICE_BD_ROM;
675     if( writeCapabilities() & MEDIA_BD_R )
676         r |= DEVICE_BD_R;
677     if( writeCapabilities() & MEDIA_BD_RE )
678         r |= DEVICE_BD_RE;
679 
680     return r;
681 }
682 
683 
readCapabilities() const684 K3b::Device::MediaTypes K3b::Device::Device::readCapabilities() const
685 {
686     return d->readCapabilities;
687 }
688 
689 
writeCapabilities() const690 K3b::Device::MediaTypes K3b::Device::Device::writeCapabilities() const
691 {
692     return d->writeCapabilities;
693 }
694 
695 
writingModes() const696 K3b::Device::WritingModes K3b::Device::Device::writingModes() const
697 {
698     return d->writeModes;
699 }
700 
701 
burnproof() const702 bool K3b::Device::Device::burnproof() const
703 {
704     return burnfree();
705 }
706 
707 
burnfree() const708 bool K3b::Device::Device::burnfree() const
709 {
710     return d->burnfree;
711 }
712 
713 
isDVD() const714 bool K3b::Device::Device::isDVD() const
715 {
716     if( readsDvd() )
717         return( mediaType() & MEDIA_DVD_ALL );
718     else
719         return false;
720 }
721 
722 
isEmpty() const723 int K3b::Device::Device::isEmpty() const
724 {
725     // if the device is already opened we do not close it
726     // to allow fast multiple method calls in a row
727     bool needToClose = !isOpen();
728 
729     int ret = STATE_UNKNOWN;
730     if( !open() )
731         return STATE_UNKNOWN;
732 
733     if( !testUnitReady() )
734         return STATE_NO_MEDIA;
735 
736     UByteArray data;
737 
738     if( readDiscInformation( data ) ) {
739         disc_info_t* inf = (disc_info_t*)data.data();
740         switch( inf->status ) {
741         case 0:
742             ret = STATE_EMPTY;
743             break;
744         case 1:
745             ret = STATE_INCOMPLETE;
746             break;
747         case 2:
748             ret = STATE_COMPLETE;
749             break;
750         default:
751             ret = STATE_UNKNOWN;
752             break;
753         }
754     }
755 
756     if( needToClose )
757         close();
758 
759     return ret;
760 }
761 
762 
numSessions() const763 int K3b::Device::Device::numSessions() const
764 {
765     //
766     // Session Info
767     // ============
768     // Byte 0-1: Data Length
769     // Byte   2: First Complete Session Number (Hex) - always 1
770     // Byte   3: Last Complete Session Number (Hex)
771     //
772 
773     int ret = -1;
774 
775     UByteArray data;
776 
777     int m = mediaType();
778     if( m & MEDIA_CD_ALL ) {
779         //
780         // Although disk_info should get the real value without ide-scsi
781         // I keep getting wrong values (the value is too high. I think the leadout
782         // gets counted as session sometimes :()
783         //
784         if( readTocPmaAtip( data, 1, 0, 0 ) ) {
785             ret = data[3];
786         }
787         else {
788             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": could not get session info !";
789         }
790     }
791     else if ( m & ( MEDIA_DVD_PLUS_RW|MEDIA_DVD_RW_OVWR|MEDIA_BD_RE ) ) {
792         // fabricate value
793         int e = isEmpty();
794         return ( e == STATE_COMPLETE || e == STATE_COMPLETE ? 1 : 0 );
795     }
796     else {
797         if( readDiscInformation( data ) ) {
798             ret = (int)( data[9]<<8 | data[4] );
799 
800             // do only count complete sessions
801             if( (data[2]>>2) != 3 )
802                 ret--;
803         }
804     }
805 
806     return ret;
807 }
808 
809 
getDataMode(const K3b::Msf & sector) const810 K3b::Device::Track::DataMode K3b::Device::Device::getDataMode( const K3b::Msf& sector ) const
811 {
812     bool needToClose = !isOpen();
813 
814     Track::DataMode ret = Track::UNKNOWN;
815 
816     if( !open() )
817         return ret;
818 
819     // we use readCdMsf here since it's defined mandatory in MMC1 and
820     // we only use this method for CDs anyway
821     unsigned char data[2352];
822     bool readSuccess = readCdMsf( data, 2352,
823                                   0,      // all sector types
824                                   false,  // no dap
825                                   sector,
826                                   sector+1,
827                                   true, // SYNC
828                                   true, // HEADER
829                                   true, // SUBHEADER
830                                   true, // USER DATA
831                                   true, // EDC/ECC
832                                   0,    // no c2 info
833                                   0 );
834 
835     if( readSuccess ) {
836         if ( data[15] == 0x1 )
837             ret = Track::MODE1;
838         else if ( data[15] == 0x2 )
839             ret = Track::MODE2;
840         if ( ret == Track::MODE2 ) {
841             if ( data[16] == data[20] &&
842                  data[17] == data[21] &&
843                  data[18] == data[22] &&
844                  data[19] == data[23] ) {
845                 if ( data[18] & 0x20 )
846                     ret = Track::XA_FORM2;
847                 else
848                     ret = Track::XA_FORM1;
849             }
850         }
851     }
852 
853     if( needToClose )
854         close();
855 
856     return ret;
857 }
858 
859 
860 
getTrackDataMode(const K3b::Device::Track & track) const861 K3b::Device::Track::DataMode K3b::Device::Device::getTrackDataMode( const K3b::Device::Track& track ) const
862 {
863     return getDataMode( track.firstSector() );
864 }
865 
866 
readToc() const867 K3b::Device::Toc K3b::Device::Device::readToc() const
868 {
869     // if the device is already opened we do not close it
870     // to allow fast multiple method calls in a row
871     bool needToClose = !isOpen();
872 
873     Toc toc;
874 
875     if( !open() )
876         return toc;
877 
878     int mt = mediaType();
879 
880     //
881     // Use the profile if available because DVD-ROM units need to treat DVD+-R(W) media as DVD-ROM
882     // if supported at all
883     //
884     if( currentProfile() == MEDIA_DVD_ROM )
885         mt = MEDIA_DVD_ROM;
886 
887     if( mt & (MEDIA_DVD_MINUS_ALL|MEDIA_DVD_PLUS_RW|MEDIA_DVD_ROM) ) {
888         if( !readFormattedToc( toc, mt ) ) {
889             K3b::Msf size;
890             if( readCapacity( size ) ) {
891                 Track track;
892                 track.setFirstSector( 0 );
893                 track.setLastSector( size.lba() );
894                 track.setSession( 1 );
895                 track.setType( Track::TYPE_DATA );
896                 track.setMode( Track::DVD );
897                 track.setCopyPermitted( mt != MEDIA_DVD_ROM );
898                 track.setPreEmphasis( mt != MEDIA_DVD_ROM );
899 
900                 toc.append( track );
901             }
902             else
903                 qDebug() << "(K3b::Device::Device) " << blockDeviceName()
904                          << "READ CAPACITY for toc failed." << endl;
905         }
906     }
907 
908     else if( mt & (MEDIA_DVD_PLUS_R|MEDIA_DVD_PLUS_R_DL) ) {
909         //
910         // a DVD+R disk may have multiple sessions
911         // every session may contain up to 16 fragments
912         // if the disk is open there is one open session
913         // every closed session is viewed as a track whereas
914         // every fragment of the open session is viewed as a track
915         //
916         // We may use
917         // READ DISK INFORMATION
918         // READ TRACK INFORMATION: track number FFh, however, does not refer to the invisible track
919         // READ TOC/PMA/ATIP: form 0 refers to all closed sessions
920         //                    form 1 refers to the last closed session
921         //
922         readFormattedToc( toc, mt );
923     }
924 
925     else if( mt & MEDIA_BD_ALL ) {
926         readFormattedToc( toc, mt );
927     }
928 
929     else if( mt == MEDIA_DVD_RAM ) {
930         qDebug() << "(K3b::Device::readDvdToc) no dvdram support";
931     }
932 
933 
934     else if( mt & MEDIA_CD_ALL ) {
935         bool success = readRawToc( toc );
936         if( !success ) {
937             success = readFormattedToc( toc, mt );
938 
939 #ifdef Q_OS_LINUX
940             if( !success ) {
941                 qDebug() << "(K3b::Device::Device) MMC READ TOC failed. falling back to cdrom.h.";
942                 readTocLinux(toc);
943             }
944 #endif
945 
946             if( success )
947                 fixupToc( toc );
948         }
949     }
950 
951     if( needToClose )
952         close();
953 
954     return toc;
955 }
956 
957 
readIsrcMcn(K3b::Device::Toc & toc) const958 void K3b::Device::Device::readIsrcMcn( K3b::Device::Toc& toc ) const
959 {
960     // read MCN and ISRC of all tracks
961     QByteArray mcn;
962     if( readMcn( mcn ) ) {
963         toc.setMcn( mcn );
964         qDebug() << "(K3b::Device::Device) found MCN: " << mcn;
965     }
966     else
967         qDebug() << "(K3b::Device::Device) no MCN found.";
968 
969     for( int i = 1; i <= toc.count(); ++i ) {
970         QByteArray isrc;
971         if( toc[i-1].type() == Track::TYPE_AUDIO ) {
972             if( readIsrc( i, isrc ) ) {
973                 qDebug() << "(K3b::Device::Device) found ISRC for track " << i << ": " << isrc;
974                 toc[i-1].setIsrc( isrc );
975             }
976             else
977                 qDebug() << "(K3b::Device::Device) no ISRC found for track " << i;
978         }
979     }
980 }
981 
982 
readFormattedToc(K3b::Device::Toc & toc,int mt) const983 bool K3b::Device::Device::readFormattedToc( K3b::Device::Toc& toc, int mt ) const
984 {
985     // if the device is already opened we do not close it
986     // to allow fast multiple method calls in a row
987     bool needToClose = !isOpen();
988 
989     bool success = false;
990 
991     toc.clear();
992 
993     int lastTrack = 0;
994 
995     UByteArray data;
996     if( !(mt & MEDIA_CD_ALL) ) {
997         //
998         // on DVD-R(W) multisession disks only two sessions are represented as tracks in the readTocPmaAtip
999         // response (fabricated TOC). Thus, we use readDiscInformation for DVD media to get the proper number of tracks
1000         //
1001         if( readDiscInformation( data ) ) {
1002             lastTrack = (int)( data[11]<<8 | data[6] );
1003 
1004             if( readTrackInformation( data, 1, lastTrack ) ) {
1005                 track_info_t* trackInfo = (track_info_t*)data.data();
1006 
1007                 if( trackInfo->blank ) {
1008                     lastTrack--;
1009                 }
1010 
1011                 success = true;
1012             }
1013             else
1014                 return false;
1015         }
1016         else
1017             return false;
1018     }
1019     else {
1020         if( readTocPmaAtip( data, 0, 0, 1 ) ) {
1021 
1022             if( data.size() < 4 ) {
1023                 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": formatted toc data too small.";
1024             }
1025             else if( data.size() != ( (int)sizeof(toc_track_descriptor) * ((int)data[3]+1) ) + 4 ) {
1026                 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": invalid formatted toc data length: "
1027                          << (data.size()-2) << endl;
1028             }
1029             else {
1030                 lastTrack = data[3];
1031                 toc_track_descriptor* td = (toc_track_descriptor*)&data[4];
1032                 for( int i = 0; i < lastTrack; ++i ) {
1033 
1034                     Track track;
1035                     unsigned int control = 0;
1036 
1037                     //
1038                     // In case READ TRACK INFORMATION fails:
1039                     // no session number info
1040                     // no track length and thus possibly incorrect last sector for
1041                     // multisession disks
1042                     //
1043                     track.setFirstSector( from4Byte( td[i].start_adr ) );
1044                     track.setLastSector( from4Byte( td[i+1].start_adr ) - 1 );
1045                     control = td[i].control;
1046 
1047                     track.setType( (control & 0x4) ? Track::TYPE_DATA : Track::TYPE_AUDIO );
1048                     track.setMode( getTrackDataMode( track ) );
1049                     track.setCopyPermitted( control & 0x2 );
1050                     track.setPreEmphasis( control & 0x1 );
1051 
1052                     toc.append( track );
1053                 }
1054 
1055                 success = true;
1056             }
1057         }
1058     }
1059 
1060 
1061     //
1062     // Try to get information for all the tracks
1063     //
1064     for( int i = 0; i < lastTrack; ++i ) {
1065         if( toc.count() < i+1 )
1066             toc.append( Track() );
1067 
1068         UByteArray trackData;
1069         if( readTrackInformation( trackData, 1, i+1 ) ) {
1070             track_info_t* trackInfo = (track_info_t*)trackData.data();
1071 
1072             toc[i].setFirstSector( from4Byte( trackInfo->track_start ) );
1073 
1074             if( i > 0 && toc[i-1].lastSector() == 0 )
1075                 toc[i-1].setLastSector( toc[i].firstSector() - 1 );
1076 
1077             // There are drives that return 0 track length here!
1078             // Some drives even return an invalid length here. :(
1079             if( from4Byte( trackInfo->track_size ) > 0 )
1080                 toc[i].setLastSector( toc[i].firstSector() + from4Byte( trackInfo->track_size ) - 1 );
1081 
1082             if( trackInfo->nwa_v ) {
1083                 toc[i].setNextWritableAddress( from4Byte( trackInfo->next_writable ) );
1084                 toc[i].setFreeBlocks( from4Byte( trackInfo->free_blocks ) );
1085             }
1086 
1087             toc[i].setSession( (int)((trackInfo->session_number_m<<8 & 0xf0) |
1088                                      (trackInfo->session_number_l & 0x0f)) );  //FIXME: is this BCD?
1089 
1090             int control = trackInfo->track_mode;
1091 
1092             if( mt & MEDIA_CD_ALL ) {
1093                 toc[i].setType( (control & 0x4) ? Track::TYPE_DATA : Track::TYPE_AUDIO );
1094                 toc[i].setMode( getTrackDataMode( toc[i] ) );
1095             }
1096             else {
1097                 toc[i].setType( Track::TYPE_DATA );
1098                 toc[i].setMode( Track::DVD );
1099             }
1100             toc[i].setCopyPermitted( control & 0x2 );
1101             toc[i].setPreEmphasis( control & 0x1 );
1102         }
1103         else if( !(mt & MEDIA_CD_ALL) ) {
1104             success = false;
1105         }
1106     }
1107 
1108     // this can only happen with DVD media
1109     if( !toc.isEmpty() && toc.last().lastSector() == 0 ) {
1110         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " no track length for the last non-empty track.";
1111         UByteArray trackData;
1112         if( readTrackInformation( trackData, 1, lastTrack+1 ) ) {
1113             track_info_t* trackInfo = (track_info_t*)trackData.data();
1114 
1115             toc.last().setLastSector( from4Byte( trackInfo->track_start ) - 1 );
1116         }
1117     }
1118 
1119 
1120     if( needToClose )
1121         close();
1122 
1123     return success;
1124 }
1125 
1126 
readRawToc(K3b::Device::Toc & toc) const1127 bool K3b::Device::Device::readRawToc( K3b::Device::Toc& toc ) const
1128 {
1129     // if the device is already opened we do not close it
1130     // to allow fast multiple method calls in a row
1131     bool needToClose = !isOpen();
1132 
1133     bool success = false;
1134 
1135     toc.clear();
1136 
1137     if( open() ) {
1138         //
1139         // Read Raw TOC (format: 0010b)
1140         //
1141         // For POINT from 01h-63h we get all the tracks
1142         // POINT a1h gices us the last track number in the session in PMIN
1143         // POINT a2h gives the start of the session lead-out in PMIN,PSEC,PFRAME
1144         //
1145 
1146         UByteArray data;
1147 
1148         if( readTocPmaAtip( data, 2, false, 1 ) ) {
1149             if( data.size() > 4 ) {
1150                 success = true;
1151 
1152                 toc_raw_track_descriptor* tr = (toc_raw_track_descriptor*)&data[4];
1153 
1154                 //
1155                 // debug the raw toc data
1156                 //
1157                 qDebug() << "Session |  ADR   | CONTROL|  TNO   | POINT  |  Min   |  Sec   | Frame  |  Zero  |  PMIN  |  PSEC  | PFRAME |";
1158                 for( int i = 0; i < (data.size()-4)/(int)sizeof(toc_raw_track_descriptor); ++i ) {
1159                     QString s;
1160                     s += QString( " %1 |" ).arg( (int)tr[i].session_number, 6 );
1161                     s += QString( " %1 |" ).arg( (int)tr[i].adr, 6 );
1162                     s += QString( " %1 |" ).arg( (int)tr[i].control, 6 );
1163                     s += QString( " %1 |" ).arg( (int)tr[i].tno, 6 );
1164                     s += QString( " %1 |" ).arg( (int)tr[i].point, 6, 16 );
1165                     s += QString( " %1 |" ).arg( (int)tr[i].min, 6 );
1166                     s += QString( " %1 |" ).arg( (int)tr[i].sec, 6 );
1167                     s += QString( " %1 |" ).arg( (int)tr[i].frame, 6 );
1168                     s += QString( " %1 |" ).arg( (int)tr[i].zero, 6, 16 );
1169                     s += QString( " %1 |" ).arg( (int)tr[i].p_min, 6 );
1170                     s += QString( " %1 |" ).arg( (int)tr[i].p_sec, 6 );
1171                     s += QString( " %1 |" ).arg( (int)tr[i].p_frame, 6 );
1172                     qDebug() << s;
1173                 }
1174 
1175                 //
1176                 // First we try to determine if the raw toc data uses BCD values
1177                 //
1178                 int isBcd = rawTocDataWithBcdValues( data );
1179                 if( isBcd == -1 ) {
1180                     return false;
1181                 }
1182 
1183                 K3b::Msf sessionLeadOut;
1184 
1185                 for( unsigned int i = 0; i < (data.size()-4)/(unsigned int)sizeof(toc_raw_track_descriptor); ++i ) {
1186                     if( tr[i].adr == 1 && tr[i].point <= 0x63 ) {
1187                         // track
1188                         Track track;
1189                         track.setSession( tr[i].session_number );
1190 
1191                         // :( We use 00:00:00 == 0 lba)
1192                         if( isBcd )
1193                             track.setFirstSector( K3b::Msf( K3b::Device::fromBcd(tr[i].p_min),
1194                                                             K3b::Device::fromBcd(tr[i].p_sec),
1195                                                             K3b::Device::fromBcd(tr[i].p_frame) ) - 150 );
1196                         else
1197                             track.setFirstSector( K3b::Msf( tr[i].p_min, tr[i].p_sec, tr[i].p_frame ) - 150 );
1198 
1199                         track.setType( tr[i].control & 0x4 ? Track::TYPE_DATA : Track::TYPE_AUDIO );
1200                         track.setMode( track.type() == Track::TYPE_DATA ? getTrackDataMode(track) : Track::UNKNOWN );
1201                         track.setCopyPermitted( tr[i].control & 0x2 );
1202                         track.setPreEmphasis( tr[i].control & 0x1 );
1203 
1204                         //
1205                         // only do this within a session because otherwise we already set the last sector with the session leadout
1206                         //
1207                         if( !toc.isEmpty() )
1208                             if( toc[toc.count()-1].session() == track.session() )
1209                                 toc[toc.count()-1].setLastSector( track.firstSector() - 1 );
1210 
1211                         toc.append(track);
1212                     }
1213                     else if( tr[i].point == 0xa2 ) {
1214                         //
1215                         // since the session is always reported before the tracks this is where we do this:
1216                         // set the previous session's last tracks's last sector to the first sector of the
1217                         // session leadout (which was reported before the tracks)
1218                         //
1219                         // This only happens on multisession CDs
1220                         //
1221                         if( !toc.isEmpty() )
1222                             toc[toc.count()-1].setLastSector( sessionLeadOut - 1 );
1223 
1224                         // this is save since the descriptors are reported in ascending order of the session number
1225                         // :( We use 00:00:00 == 0 lba)
1226                         if( isBcd )
1227                             sessionLeadOut = K3b::Msf( K3b::Device::fromBcd(tr[i].p_min),
1228                                                        K3b::Device::fromBcd(tr[i].p_sec),
1229                                                        K3b::Device::fromBcd(tr[i].p_frame) ) - 150;
1230                         else
1231                             sessionLeadOut = K3b::Msf( tr[i].p_min, tr[i].p_sec, tr[i].p_frame ) - 150;
1232                     }
1233                 }
1234 
1235                 qDebug() << blockDeviceName() << ": setting last sector of last track to " << (sessionLeadOut-1).lba();
1236 
1237                 // set the last track's last sector
1238                 if( !toc.isEmpty() )
1239                     toc[toc.count()-1].setLastSector( sessionLeadOut - 1 );
1240             }
1241             else
1242                 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " empty raw toc.";
1243         }
1244     }
1245 
1246     if( needToClose )
1247         close();
1248 
1249     return success;
1250 }
1251 
1252 
rawTocDataWithBcdValues(const UByteArray & data) const1253 int K3b::Device::Device::rawTocDataWithBcdValues( const UByteArray& data ) const
1254 {
1255     toc_raw_track_descriptor* tr = (toc_raw_track_descriptor*)&data[4];
1256 
1257     bool notBcd = false;
1258     bool notHex = false;
1259 
1260     //
1261     // in most cases this will already tell us if a drive does not provide bcd numbers
1262     // (which should be all newer MMC drives)
1263     //
1264     for( unsigned int i = 0; i < (data.size()-4)/(unsigned int)sizeof(toc_raw_track_descriptor); ++i ) {
1265         if( tr[i].adr == 1 && tr[i].point <= 0xa2) {
1266             if( !K3b::Device::isValidBcd(tr[i].p_min) ||
1267                 !K3b::Device::isValidBcd(tr[i].p_sec) ||
1268                 !K3b::Device::isValidBcd(tr[i].p_frame) ) {
1269                 notBcd = true;
1270                 break;
1271             }
1272 
1273             // we only need to check sec and frame since min needs to be <= 99
1274             // and bcd values are never bigger than 99.
1275             else if( (int)K3b::Device::fromBcd(tr[i].p_sec) >= 60 ||
1276                      (int)K3b::Device::fromBcd(tr[i].p_frame) >= 75 ) {
1277                 notBcd = true;
1278                 break;
1279             }
1280         }
1281     }
1282 
1283 
1284     //
1285     // all values are valid bcd values but we still don't know for sure if they are really
1286     // used as bcd. So we also check the HEX values.
1287     //
1288     for( unsigned int i = 0; i < (data.size()-4)/(unsigned int)sizeof(toc_raw_track_descriptor); ++i ) {
1289         if( tr[i].adr == 1 && tr[i].point <= 0xa2 ) {
1290             if( (int)tr[i].p_min > 99 ||
1291                 (int)tr[i].p_sec >= 60 ||
1292                 (int)tr[i].p_frame >= 75 ) {
1293                 notHex = true;
1294                 break;
1295             }
1296         }
1297     }
1298 
1299 
1300     //
1301     // If all values are valid bcd and valid hex we check the start sectors of the tracks.
1302     //
1303     if( !notHex || !notBcd ) {
1304         K3b::Msf sessionLeadOutHex, sessionLeadOutBcd;
1305         K3b::Msf lastTrackHex, lastTrackBcd;
1306 
1307         for( unsigned int i = 0; i < (data.size()-4)/(unsigned int)sizeof(toc_raw_track_descriptor); ++i ) {
1308 
1309             if( tr[i].adr == 1 ) {
1310                 if( tr[i].point < 0x64 ) {
1311 
1312                     // check hex values
1313                     if( K3b::Msf( tr[i].p_min, tr[i].p_sec, tr[i].p_frame ) <
1314                         lastTrackHex )
1315                         notHex = true;
1316 
1317                     // check bcd values
1318                     if( K3b::Msf( K3b::Device::fromBcd(tr[i].p_min), K3b::Device::fromBcd(tr[i].p_sec), K3b::Device::fromBcd(tr[i].p_frame) ) <
1319                         lastTrackBcd )
1320                         notBcd = true;
1321 
1322                     lastTrackBcd = K3b::Msf( K3b::Device::fromBcd(tr[i].p_min), K3b::Device::fromBcd(tr[i].p_sec), K3b::Device::fromBcd(tr[i].p_frame) );
1323                     lastTrackHex = K3b::Msf( tr[i].p_min, tr[i].p_sec, tr[i].p_frame );
1324                 }
1325                 else if( tr[i].point == 0xa2 ) {
1326                     if( sessionLeadOutHex < lastTrackHex )
1327                         notHex = true;
1328                     if( sessionLeadOutBcd < lastTrackBcd )
1329                         notBcd = true;
1330 
1331                     sessionLeadOutHex = K3b::Msf( tr[i].p_min, tr[i].p_sec, tr[i].p_frame );
1332                     sessionLeadOutBcd = K3b::Msf( K3b::Device::fromBcd(tr[i].p_min), K3b::Device::fromBcd(tr[i].p_sec), K3b::Device::fromBcd(tr[i].p_frame) );
1333                 }
1334             }
1335         }
1336 
1337         // check the last track
1338         if( sessionLeadOutHex < lastTrackHex )
1339             notHex = true;
1340         if( sessionLeadOutBcd < lastTrackBcd )
1341             notBcd = true;
1342     }
1343 
1344 
1345     if( !notBcd && !notHex ) {
1346         qDebug() << "(K3b::Device::Device) need to compare raw toc to formatted toc. :(";
1347         //
1348         // All values are valid bcd and valid HEX values so we compare with the formatted toc.
1349         // This slows us down a lot but in most cases this should not be reached anyway.
1350         //
1351         // TODO: also check the bcd values
1352         //
1353         K3b::Device::Toc formattedToc;
1354         if( readFormattedToc( formattedToc, MEDIA_CD_ROM ) ) {
1355             for( unsigned int i = 0; i < (data.size()-4)/(unsigned int)sizeof(toc_raw_track_descriptor); ++i ) {
1356                 if( tr[i].adr == 1 && tr[i].point < 0x64 ) {
1357                     unsigned int track = (int)tr[i].point;
1358 
1359                     // FIXME: do bcd drive also encode the track number in bcd? If so test it, too.
1360 
1361                     if( ( int )track > formattedToc.count() ) {
1362                         notHex = true;
1363                         break;
1364                     }
1365 
1366                     K3b::Msf posHex( tr[i].p_min,
1367                                      tr[i].p_sec,
1368                                      tr[i].p_frame );
1369                     K3b::Msf posBcd( K3b::Device::fromBcd(tr[i].p_min),
1370                                      K3b::Device::fromBcd(tr[i].p_sec),
1371                                      K3b::Device::fromBcd(tr[i].p_frame) );
1372                     posHex -= 150;
1373                     posBcd -= 150;
1374                     if( posHex != formattedToc[track-1].firstSector() )
1375                         notHex = true;
1376                     if( posBcd != formattedToc[track-1].firstSector() )
1377                         notBcd = true;
1378                 }
1379             }
1380         }
1381     }
1382 
1383     if( notBcd )
1384         qDebug() << "(K3b::Device::Device) found invalid bcd values. No bcd toc.";
1385     if( notHex )
1386         qDebug() << "(K3b::Device::Device) found invalid hex values. No hex toc.";
1387 
1388     if( notBcd == notHex ) {
1389         qDebug() << "(K3b::Device::Device) unable to determine if hex (" << notHex << ") or bcd (" << notBcd << ").";
1390         if( !notHex ) {
1391             qDebug() << "Assuming hex encoding in favor of newer drives and the more reliable raw toc.";
1392             return 0;
1393         }
1394         return -1;
1395     }
1396     else if( notBcd )
1397         return 0;
1398     else
1399         return 1;
1400 }
1401 
1402 
readCdText() const1403 K3b::Device::CdText K3b::Device::Device::readCdText() const
1404 {
1405     return CdText( readRawCdText() );
1406 }
1407 
1408 
readRawCdText(bool * success) const1409 QByteArray K3b::Device::Device::readRawCdText( bool* success ) const
1410 {
1411     // if the device is already opened we do not close it
1412     // to allow fast multiple method calls in a row
1413     bool needToClose = !isOpen();
1414 
1415     QByteArray textData;
1416 
1417     if ( success )
1418         *success = false;
1419 
1420     if( open() ) {
1421         UByteArray data;
1422 
1423         if( readTocPmaAtip( data, 5, false, 0 ) ) {
1424             // we need more than the header and a multiple of 18 bytes to have valid CD-TEXT
1425             if( data.size() > 4 && data.size()%18 == 4 ) {
1426                 textData.append( QByteArray( reinterpret_cast<char*>(data.data()), data.size() ) );
1427                 if ( success )
1428                     *success = true;
1429             }
1430             else {
1431                 qDebug() << "invalid CD-TEXT length: " << data.size();
1432             }
1433         }
1434 
1435         if( needToClose )
1436             close();
1437     }
1438 
1439     return textData;
1440 }
1441 
1442 
1443 #ifdef Q_OS_LINUX
1444 // fallback
readTocLinux(K3b::Device::Toc & toc) const1445 bool K3b::Device::Device::readTocLinux( K3b::Device::Toc& toc ) const
1446 {
1447     // if the device is already opened we do not close it
1448     // to allow fast multiple method calls in a row
1449     bool needToClose = !isOpen();
1450 
1451     bool success = true;
1452 
1453     toc.clear();
1454 
1455     struct cdrom_tochdr tochdr;
1456     struct cdrom_tocentry tocentry;
1457 
1458     usageLock();
1459     if( open() ) {
1460         //
1461         // CDROMREADTOCHDR ioctl returns:
1462         // cdth_trk0: First Track Number
1463         // cdth_trk1: Last Track Number
1464         //
1465         if( ::ioctl( d->deviceHandle, CDROMREADTOCHDR, &tochdr ) ) {
1466             qDebug() << "(K3b::Device::Device) could not get toc header !";
1467             success = false;
1468         }
1469         else {
1470             Track lastTrack;
1471             for (int i = tochdr.cdth_trk0; i <= tochdr.cdth_trk1 + 1; i++) {
1472                 ::memset(&tocentry,0,sizeof (struct cdrom_tocentry));
1473                 // get Lead-Out Information too
1474                 tocentry.cdte_track = (i<=tochdr.cdth_trk1) ? i : CDROM_LEADOUT;
1475                 tocentry.cdte_format = CDROM_LBA;
1476                 //
1477                 // CDROMREADTOCENTRY ioctl returns:
1478                 // cdte_addr.lba: Start Sector Number (LBA Format requested)
1479                 // cdte_ctrl:     4 ctrl bits
1480                 //                   00x0b: 2 audio Channels(no pre-emphasis)
1481                 //                   00x1b: 2 audio Channels(pre-emphasis)
1482                 //                   10x0b: audio Channels(no pre-emphasis),reserved in cd-rw
1483                 //                   10x1b: audio Channels(pre-emphasis),reserved in cd-rw
1484                 //                   01x0b: data track, recorded uninterrupted
1485                 //                   01x1b: data track, recorded incremental
1486                 //                   11xxb: reserved
1487                 //                   xx0xb: digital copy prohibited
1488                 //                   xx1xb: digital copy permitted
1489                 // cdte_addr:     4 addr bits (type of Q-Subchannel data)
1490                 //                   0000b: no Information
1491                 //                   0001b: current position data
1492                 //                   0010b: MCN
1493                 //                   0011b: ISRC
1494                 //                   0100b-1111b:  reserved
1495                 // cdte_datamode:  0: Data Mode1
1496                 //                 1: CD-I
1497                 //                 2: CD-XA Mode2
1498                 //
1499 
1500                 if( ::ioctl( d->deviceHandle, CDROMREADTOCENTRY, &tocentry ) ) {
1501                     qDebug() << "(K3b::Device::Device) error reading tocentry " << i;
1502                     success = false;
1503                     break;
1504                 }
1505 
1506                 int startSec = tocentry.cdte_addr.lba;
1507                 int control  = tocentry.cdte_ctrl & 0x0f;
1508                 int mode     = tocentry.cdte_datamode;
1509                 if( i > tochdr.cdth_trk0 ) {
1510                     Track track( lastTrack.firstSector(), startSec-1, lastTrack.type(), lastTrack.mode() );
1511                     track.setPreEmphasis( control & 0x1 );
1512                     track.setCopyPermitted( control & 0x2 );
1513                     toc.append( track );
1514                 }
1515                 Track::TrackType trackType = Track::TYPE_UNKNOWN;
1516                 Track::DataMode trackMode = Track::UNKNOWN;
1517                 if( (control & 0x04 ) && (tocentry.cdte_track != CDROM_LEADOUT) ) {
1518                     trackType = Track::TYPE_DATA;
1519                     if( mode == 1 )
1520                         trackMode = Track::MODE1;
1521                     else if( mode == 2 )
1522                         trackMode = Track::MODE2;
1523 
1524                     Track::DataMode tm = getDataMode(startSec);
1525                     if( tm != Track::UNKNOWN )
1526                         trackMode = tm;
1527                 }
1528                 else
1529                     trackType = Track::TYPE_AUDIO;
1530 
1531                 lastTrack = Track( startSec, startSec, trackType, trackMode );
1532             }
1533         }
1534 
1535         if( needToClose )
1536             close();
1537     }
1538     else
1539         success = false;
1540 
1541     usageUnlock();
1542 
1543     return success;
1544 }
1545 #endif // Q_OS_LINUX
1546 
1547 
fixupToc(K3b::Device::Toc & toc) const1548 bool K3b::Device::Device::fixupToc( K3b::Device::Toc& toc ) const
1549 {
1550     bool success = false;
1551 
1552     //
1553     // This is a very lame method of fixing the TOC of an Advanced Audio CD
1554     // (a CD with two sessions: one with audio tracks and one with the data track)
1555     // If a drive does not support reading raw toc or reading track info we only
1556     // get every track's first sector. But between sessions there is a gap which is used
1557     // for ms stuff. In this case it's 11400 sectors in size. When ripping ausio we would
1558     // include these 11400 sectors which would result in a strange ending audio file.
1559     //
1560     if( numSessions() > 1 || toc.contentType() == MIXED ) {
1561         qDebug() << "(K3b::Device::Device) fixup multisession toc...";
1562 
1563         //
1564         // we need to update the last sector of every last track in every session
1565         // for now we only update the track before the last session...
1566         // This is the most often case: Advanced Audio CD
1567         //
1568 
1569         UByteArray data;
1570         if( readTocPmaAtip( data, 1, false, 0 ) ) {
1571 
1572             //
1573             // data[6]    - first track number in last complete session
1574             // data[8-11] - start address of first track in last session
1575             //
1576 
1577             toc[(unsigned int)data[6]-2].setLastSector( from4Byte( &data[8] ) - 11400 - 1 );
1578 
1579             success = true;
1580         }
1581         else
1582             qDebug() << "(K3b::Device::Device) FIXUP TOC failed.";
1583     }
1584 
1585     return success;
1586 }
1587 
1588 
block(bool b) const1589 bool K3b::Device::Device::block( bool b ) const
1590 {
1591     //
1592     // For some reason the Scsi Command does not work here.
1593     // So we use the ioctl on Linux systems
1594     //
1595 #if defined(Q_OS_LINUX)
1596     bool success = false;
1597     bool needToClose = !isOpen();
1598     usageLock();
1599     if( open() ) {
1600         success = ( ::ioctl( d->deviceHandle, CDROM_LOCKDOOR, b ? 1 : 0 ) == 0 );
1601         if( needToClose )
1602             close();
1603     }
1604     usageUnlock();
1605     if ( success )
1606         return success;
1607 #elif defined(Q_OS_NETBSD)
1608     bool success = false;
1609     bool needToClose = !isOpen();
1610     int arg = b ? 1 : 0;
1611     usageLock();
1612     if( open() ) {
1613         success = ( ::ioctl( d->deviceHandle, DIOCLOCK, &arg ) == 0 );
1614         if( needToClose )
1615             close();
1616     }
1617     usageUnlock();
1618     if ( success )
1619         return success;
1620 #endif
1621 
1622     ScsiCommand cmd( this );
1623     cmd[0] = MMC_PREVENT_ALLOW_MEDIUM_REMOVAL;
1624     cmd[5] = 0; // Necessary to set the proper command length
1625     if( b )
1626         cmd[4] = 0x01;
1627     int r = cmd.transport( TR_DIR_WRITE );
1628 
1629     if( r )
1630         qDebug() << "(K3b::Device::Device) MMC ALLOW MEDIA REMOVAL failed.";
1631 
1632     return ( r == 0 );
1633 }
1634 
rewritable() const1635 bool K3b::Device::Device::rewritable() const
1636 {
1637     UByteArray data;
1638 
1639     if( readDiscInformation( data ) ) {
1640         disc_info_t* inf = (disc_info_t*)data.data();
1641         bool e = inf->erasable;
1642 
1643         return e;
1644     }
1645     else
1646         return false;
1647 }
1648 
1649 
eject() const1650 bool K3b::Device::Device::eject() const
1651 {
1652 #ifdef Q_OS_NETBSD
1653     bool success = false;
1654     bool needToClose = !isOpen();
1655     int arg = 0;
1656 
1657     usageLock();
1658     if( open() ) {
1659         if ( ::ioctl( d->deviceHandle, DIOCEJECT, &arg ) >= 0)
1660             success = true;
1661         if( needToClose )
1662             close();
1663     }
1664     usageUnlock();
1665     if ( success )
1666         return success;
1667 #elif defined(Q_OS_LINUX)
1668     bool success = false;
1669     bool needToClose = !isOpen();
1670 
1671     usageLock();
1672     if( open() ) {
1673         if( ::ioctl( d->deviceHandle, CDROMEJECT ) >= 0 )
1674             success = true;
1675         if( needToClose )
1676             close();
1677     }
1678     usageUnlock();
1679     if ( success )
1680         return success;
1681 #endif
1682 
1683     ScsiCommand cmd( this );
1684     cmd[0] = MMC_PREVENT_ALLOW_MEDIUM_REMOVAL;
1685     cmd[5] = 0; // Necessary to set the proper command length
1686     cmd.transport( TR_DIR_WRITE );
1687 
1688     cmd[0] = MMC_START_STOP_UNIT;
1689     cmd[5] = 0; // Necessary to set the proper command length
1690     cmd[4] = 0x2;      // eject medium LoEj = 1, Start = 0
1691     return !cmd.transport( TR_DIR_WRITE );
1692 }
1693 
1694 
load() const1695 bool K3b::Device::Device::load() const
1696 {
1697 #ifdef Q_OS_NETBSD
1698     bool success = false;
1699     bool needToClose = !isOpen();
1700     int arg = 0;
1701 
1702     usageLock();
1703     if( open() ) {
1704         if ( ::ioctl( d->deviceHandle, CDIOCCLOSE, &arg ) >= 0)
1705             success = true;
1706         if( needToClose )
1707             close();
1708     }
1709     usageUnlock();
1710     if ( success )
1711         return success;
1712 #elif defined(Q_OS_LINUX)
1713     bool success = false;
1714     bool needToClose = !isOpen();
1715 
1716     usageLock();
1717     if( open() ) {
1718         if( ::ioctl( d->deviceHandle, CDROMCLOSETRAY ) >= 0 )
1719             success = true;
1720         if( needToClose )
1721             close();
1722     }
1723     usageUnlock();
1724     if ( success )
1725         return success;
1726 #endif
1727 
1728     ScsiCommand cmd( this );
1729     cmd[0] = MMC_START_STOP_UNIT;
1730     cmd[4] = 0x3;    // LoEj = 1, Start = 1
1731     cmd[5] = 0;      // Necessary to set the proper command length
1732     return !cmd.transport();
1733 }
1734 
1735 
setAutoEjectEnabled(bool enabled) const1736 bool K3b::Device::Device::setAutoEjectEnabled( bool enabled ) const
1737 {
1738     bool success = false;
1739 #ifdef Q_OS_LINUX
1740 
1741     bool needToClose = !isOpen();
1742     usageLock();
1743     if ( open() ) {
1744         success = ( ::ioctl( d->deviceHandle, CDROMEJECT_SW, enabled ? 1 : 0 ) == 0 );
1745         if ( needToClose ) {
1746             close();
1747         }
1748     }
1749     usageUnlock();
1750 #endif
1751     return success;
1752 }
1753 
1754 
handle() const1755 K3b::Device::Device::Handle K3b::Device::Device::handle() const
1756 {
1757     return d->deviceHandle;
1758 }
1759 
1760 
open(bool write) const1761 bool K3b::Device::Device::open( bool write ) const
1762 {
1763     if( d->openedReadWrite != write )
1764         close();
1765 
1766     QMutexLocker ml( &d->openCloseMutex );
1767 
1768     d->openedReadWrite = write;
1769 
1770     if( d->deviceHandle == HANDLE_DEFAULT_VALUE)
1771         d->deviceHandle = openDevice( QFile::encodeName(blockDeviceName()), write );
1772 
1773     return ( d->deviceHandle != HANDLE_DEFAULT_VALUE);
1774 }
1775 
1776 
close() const1777 void K3b::Device::Device::close() const
1778 {
1779     QMutexLocker ml( &d->openCloseMutex );
1780 
1781     if( d->deviceHandle == HANDLE_DEFAULT_VALUE)
1782         return;
1783 
1784 #if defined(Q_OS_FREEBSD)
1785     cam_close_device(d->deviceHandle);
1786 #elif defined(Q_OS_WIN32)
1787     CloseHandle(d->deviceHandle);
1788 #else
1789     ::close( d->deviceHandle );
1790 #endif
1791     d->deviceHandle = HANDLE_DEFAULT_VALUE;
1792 }
1793 
1794 
isOpen() const1795 bool K3b::Device::Device::isOpen() const
1796 {
1797     return ( d->deviceHandle != HANDLE_DEFAULT_VALUE);
1798 }
1799 
1800 
supportedProfiles() const1801 int K3b::Device::Device::supportedProfiles() const
1802 {
1803     return d->supportedProfiles;
1804 }
1805 
1806 
currentProfile() const1807 int K3b::Device::Device::currentProfile() const
1808 {
1809     unsigned char profileBuf[8];
1810     ::memset( profileBuf, 0, 8 );
1811 
1812     ScsiCommand cmd( this );
1813     cmd[0] = MMC_GET_CONFIGURATION;
1814     cmd[1] = 1;
1815     cmd[8] = 8;
1816     cmd[9] = 0;      // Necessary to set the proper command length
1817 
1818     if( cmd.transport( TR_DIR_READ, profileBuf, 8 ) ) {
1819         qDebug() << "(K3b::Device::Device) " << blockDeviceName()
1820                  << " GET_CONFIGURATION failed." << endl;
1821         return MEDIA_UNKNOWN;
1822     }
1823     else {
1824         short profile = from2Byte( &profileBuf[6] );
1825 
1826         //
1827         // Plextor drives might not set a current profile
1828         // In that case we get the list of all current profiles
1829         // and simply use the first one in that list.
1830         //
1831         if( profile == 0x00 ) {
1832             qDebug() << "(K3b::Device::Device) " << blockDeviceName()
1833                      << " current profile 0. Checking current profile list instead." << endl;
1834             UByteArray data;
1835             if( getFeature( data, FEATURE_PROFILE_LIST ) ) {
1836                 int featureLen( data[11] );
1837                 for( int j = 0; j < featureLen; j+=4 ) {
1838                     // use the first current profile we encounter
1839                     if( data[12+j+2] & 0x1 ) {
1840                         profile = from2Byte( &data[12+j] );
1841                         break;
1842                     }
1843                 }
1844             }
1845         }
1846 
1847         switch (profile) {
1848         case 0x00: return MEDIA_NONE;
1849         case 0x08: return MEDIA_CD_ROM;
1850         case 0x09: return MEDIA_CD_R;
1851         case 0x0A: return MEDIA_CD_RW;
1852         case 0x10: return MEDIA_DVD_ROM;
1853         case 0x11: return MEDIA_DVD_R_SEQ;
1854         case 0x12: return MEDIA_DVD_RAM;
1855         case 0x13: return MEDIA_DVD_RW_OVWR;
1856         case 0x14: return MEDIA_DVD_RW_SEQ;
1857         case 0x15: return MEDIA_DVD_R_DL_SEQ;
1858         case 0x16: return MEDIA_DVD_R_DL_JUMP;
1859         case 0x1A: return MEDIA_DVD_PLUS_RW;
1860         case 0x1B: return MEDIA_DVD_PLUS_R;
1861         case 0x2B: return MEDIA_DVD_PLUS_R_DL;
1862         case 0x40: return MEDIA_BD_ROM;
1863         case 0x41: {
1864             if( featureCurrent( FEATURE_BD_PSEUDO_OVERWRITE ) == 1 )
1865                 return MEDIA_BD_R_SRM_POW;
1866             else
1867                 return MEDIA_BD_R_SRM;
1868         }
1869         case 0x42: return MEDIA_BD_R_RRM;
1870         case 0x43: return MEDIA_BD_RE;
1871         case 0x50: return MEDIA_HD_DVD_ROM;
1872         case 0x51: return MEDIA_HD_DVD_R;
1873         case 0x52: return MEDIA_HD_DVD_RAM;
1874         default: return MEDIA_UNKNOWN;
1875         }
1876     }
1877 }
1878 
1879 
diskInfo() const1880 K3b::Device::DiskInfo K3b::Device::Device::diskInfo() const
1881 {
1882     DiskInfo inf;
1883 
1884     // if the device is already opened we do not close it
1885     // to allow fast multiple method calls in a row
1886     bool needToClose = !isOpen();
1887 
1888     if( open() ) {
1889 
1890         UByteArray data;
1891 
1892         //
1893         // The first thing to do should be: checking if a media is loaded
1894         // We cannot rely on the profile here since at least some Plextor
1895         // drives return the NO MEDIUM profile for CD media
1896         //
1897         if( !testUnitReady() ) {
1898             // no disk or tray open
1899             inf.d->diskState = STATE_NO_MEDIA;
1900             inf.d->mediaType = MEDIA_NONE;
1901             inf.d->currentProfile = MEDIA_NONE;
1902         }
1903         else
1904             inf.d->currentProfile = currentProfile();
1905 
1906         if( inf.diskState() != STATE_NO_MEDIA ) {
1907 
1908             if( readDiscInformation( data ) ) {
1909                 disc_info_t* dInf = (disc_info_t*)data.data();
1910                 //
1911                 // Copy the needed values from the disk_info struct
1912                 //
1913                 switch( dInf->status ) {
1914                 case 0:
1915                     inf.d->diskState = STATE_EMPTY;
1916                     break;
1917                 case 1:
1918                     inf.d->diskState = STATE_INCOMPLETE;
1919                     break;
1920                 case 2:
1921                     inf.d->diskState = STATE_COMPLETE;
1922                     break;
1923                 default:
1924                     inf.d->diskState = STATE_UNKNOWN;
1925                     break;
1926                 }
1927 
1928                 switch( dInf->border ) {
1929                 case 0:
1930                     inf.d->lastSessionState = STATE_EMPTY;
1931                     break;
1932                 case 1:
1933                     inf.d->lastSessionState = STATE_INCOMPLETE;
1934                     break;
1935                 case 2:
1936                     inf.d->lastSessionState = STATE_COMPLETE;
1937                     break;
1938                 default:
1939                     inf.d->lastSessionState = STATE_UNKNOWN;
1940                     break;
1941                 }
1942 
1943                 switch( dInf->bg_f_status&0x3 ) {
1944                 case 0x0:
1945                     inf.d->bgFormatState = BG_FORMAT_NONE;
1946                     break;
1947                 case 0x1:
1948                     inf.d->bgFormatState = BG_FORMAT_INCOMPLETE;
1949                     break;
1950                 case 0x2:
1951                     inf.d->bgFormatState = BG_FORMAT_IN_PROGRESS;
1952                     break;
1953                 case 0x3:
1954                     inf.d->bgFormatState = BG_FORMAT_COMPLETE;
1955                     break;
1956                 }
1957 
1958                 inf.d->numTracks = (dInf->last_track_l & 0xff) | (dInf->last_track_m<<8 & 0xff00);
1959                 if( inf.diskState() == STATE_EMPTY )
1960                     inf.d->numTracks = 0;
1961 
1962                 // FIXME: I am not sure if this is accurate. Better test the last track's RT field
1963                 else if( inf.diskState() == STATE_INCOMPLETE )
1964                     inf.d->numTracks--;  // do not count the invisible track
1965 
1966                 inf.d->rewritable = dInf->erasable;
1967 
1968                 //
1969                 // This is the Last Possible Lead-Out Start Address in HMSF format
1970                 // This is only valid for CD-R(W) and DVD+R media.
1971                 // For complete media this shall be filled with 0xff
1972                 //
1973                 if( dInf->lead_out_m != 0xff &&
1974                     dInf->lead_out_r != 0xff &&
1975                     dInf->lead_out_s != 0xff &&
1976                     dInf->lead_out_f != 0xff )
1977                     inf.d->capacity = K3b::Msf( dInf->lead_out_m + dInf->lead_out_r*60,
1978                                                 dInf->lead_out_s,
1979                                                 dInf->lead_out_f ) - 150;
1980 
1981                 //
1982                 // This is the position where the next Session shall be recorded in HMSF format
1983                 // This is only valid for CD-R(W) and DVD+R media.
1984                 // For complete media this shall be filled with 0xff
1985                 //
1986                 if( dInf->lead_in_m != 0xff &&
1987                     dInf->lead_in_r != 0xff &&
1988                     dInf->lead_in_s != 0xff &&
1989                     dInf->lead_in_f != 0xff )
1990                     inf.d->usedCapacity = K3b::Msf( dInf->lead_in_m + dInf->lead_in_r*60,
1991                                                     dInf->lead_in_s,
1992                                                     dInf->lead_in_f ) - 4500;
1993             }
1994             else {
1995                 qDebug() << "(K3b::Device::Device) " << blockDeviceName()
1996                          << " fabricating disk information for a stupid device." << endl;
1997                 Toc toc = readToc();
1998                 if( !toc.isEmpty() ) {
1999                     inf.d->diskState = STATE_COMPLETE;
2000                     inf.d->lastSessionState = STATE_COMPLETE;
2001                     inf.d->numTracks = toc.count();
2002                     inf.d->capacity = inf.d->usedCapacity = toc.length();
2003                 }
2004             }
2005 
2006 
2007             //
2008             // The mediatype needs to be set
2009             //
2010             inf.d->mediaType = mediaType();
2011 
2012             // At least some Plextor drives return profile NONE for CD media
2013             // or CD_ROM for writable media
2014             if( inf.d->mediaType & (MEDIA_UNKNOWN|MEDIA_NONE|MEDIA_CD_ROM) ) {
2015                 // probably it is a CD
2016                 if( inf.rewritable() )
2017                     inf.d->mediaType = MEDIA_CD_RW;
2018                 else if( inf.empty() || inf.appendable() )
2019                     inf.d->mediaType = MEDIA_CD_R;
2020                 else
2021                     inf.d->mediaType = MEDIA_CD_ROM;
2022             }
2023 
2024             if( inf.d->mediaType & MEDIA_DVD_ALL ) {
2025                 if( readDvdStructure( data ) ) {
2026                     // some debugging stuff
2027                     K3b::Msf sda, eda, ea0;
2028                     sda = ( data[4+5]<<16 | data[4+6] << 8 | data[4+7] );
2029                     eda = ( data[4+9]<<16 | data[4+10] << 8 | data[4+11] );
2030                     ea0 = ( data[4+13]<<16 | data[4+14] << 8 | data[4+15] );
2031 
2032                     qDebug() << "First sec data area: " << sda.toString()
2033                              << " (LBA " << QString::number(sda.lba())
2034                              << ") (" << QString::number(sda.mode1Bytes()) << endl;
2035                     qDebug() << "Last sec data area: " << eda.toString()
2036                              << " (LBA " << QString::number(eda.lba())
2037                              << ") (" << QString::number(eda.mode1Bytes()) << " Bytes)" << endl;
2038                     qDebug() << "Last sec layer 1: " << ea0.toString()
2039                              << " (LBA " << QString::number(ea0.lba())
2040                              << ") (" << QString::number(ea0.mode1Bytes()) << " Bytes)" << endl;
2041 
2042 
2043                     K3b::Msf da0 = ea0 - sda + 1;
2044                     K3b::Msf da1 = eda - ea0;
2045                     qDebug() << "Layer 1 length: " << da0.toString()
2046                              << " (LBA " << QString::number(da0.lba())
2047                              << ") (" << QString::number(da0.mode1Bytes()) << " Bytes)" << endl;
2048                     qDebug() << "Layer 2 length: " << da1.toString()
2049                              << " (LBA " << QString::number(da1.lba())
2050                              << ") (" << QString::number(da1.mode1Bytes()) << " Bytes)" << endl;
2051 
2052                     inf.d->numLayers = ((data[6]&0x60) == 0 ? 1 : 2);
2053 
2054                     bool otp = (data[4+2] & 0xF);
2055 
2056                     // ea0 is 0 if the medium does not use Opposite track path
2057                     if( otp && ea0 > 0 )
2058                         inf.d->firstLayerSize = da0;
2059                     else
2060                         inf.d->firstLayerSize = 0;
2061                 }
2062                 else {
2063                     qDebug() << "(K3b::Device::Device) Unable to read DVD structure for num of layers.";
2064                     inf.d->numLayers = ( (inf.d->mediaType & MEDIA_WRITABLE_DVD_DL) ? 2 : 1 );
2065                 }
2066             }
2067 
2068 
2069             //
2070             // Number of sessions for non-empty disks
2071             //
2072             if( inf.diskState() != STATE_EMPTY ) {
2073                 int sessions = numSessions();
2074                 if( sessions >= 0 )
2075                     inf.d->numSessions = sessions;
2076                 else
2077                     qDebug() << "(K3b::Device::Device) could not get session info via READ TOC/PMA/ATIP.";
2078             }
2079             else
2080                 inf.d->numSessions = 0;
2081 
2082             inf.d->mediaId = mediaId( inf.mediaType() );
2083 
2084             //
2085             // Now we determine the size:
2086 
2087             // for all empty and appendable media READ FORMAT CAPACITIES should return the proper unformatted size
2088             // for complete disks we may use the READ_CAPACITY command or the start sector from the leadout
2089             //
2090             int media = inf.mediaType();
2091             //
2092             // Use the profile if available because DVD-ROM units need to treat DVD+-R(W) media as DVD-ROM
2093             // if supported at all
2094             //
2095             if( inf.currentProfile() == MEDIA_DVD_ROM )
2096                 media = MEDIA_DVD_ROM;
2097 
2098             switch( media ) {
2099             case MEDIA_CD_R:
2100             case MEDIA_CD_RW:
2101                 if( inf.d->capacity == 0 ) {
2102                     if( readTocPmaAtip( data, 0x4, true, 0 ) ) {
2103 
2104                         struct atip_descriptor* atip = (struct atip_descriptor*)data.data();
2105 
2106                         if( data.size() >= 11 ) {
2107                             inf.d->capacity = K3b::Msf( atip->lead_out_m, atip->lead_out_s, atip->lead_out_f ) - 150;
2108                             debugBitfield( &atip->lead_out_m, 3 );
2109                             qDebug() << blockDeviceName() << ": ATIP capacity: " << inf.d->capacity.toString();
2110                         }
2111                     }
2112                 }
2113 
2114                 //
2115                 // for empty and appendable media capacity and usedCapacity should be filled in from
2116                 // diskinfo above. If not they are both still 0
2117                 //
2118                 if( inf.d->capacity != 0 &&
2119                     ( inf.diskState() == STATE_EMPTY || inf.d->usedCapacity != 0 ) ) {
2120                     // done.
2121                     break;
2122                 }
2123                 Q_FALLTHROUGH();
2124 
2125             default:
2126             case MEDIA_CD_ROM:
2127                 if( inf.d->capacity > 0 && inf.d->usedCapacity == 0 )
2128                     inf.d->usedCapacity = inf.d->capacity;
2129 
2130                 if( inf.d->usedCapacity == 0 ) {
2131                     K3b::Msf readCap;
2132                     if( readCapacity( readCap ) ) {
2133                         qDebug() << "(K3b::Device::Device) READ CAPACITY: " << readCap.toString()
2134                                  << " other capacity: " << inf.d->capacity.toString() << endl;
2135                         //
2136                         // READ CAPACITY returns the last written sector
2137                         // that means the size is actually readCap + 1
2138                         //
2139                         inf.d->usedCapacity = readCap + 1;
2140                     }
2141                     else {
2142                         qDebug() << "(K3b::Device::Device) " << blockDeviceName()
2143                                  << " Falling back to readToc for capacity." << endl;
2144                         inf.d->usedCapacity = readToc().length();
2145                     }
2146                 }
2147                 break;
2148 
2149             case MEDIA_DVD_ROM: {
2150                 K3b::Msf readCap;
2151                 if( readCapacity( readCap ) ) {
2152                     qDebug() << "(K3b::Device::Device) READ CAPACITY: " << readCap.toString()
2153                              << " other capacity: " << inf.d->capacity.toString() << endl;
2154                     //
2155                     // READ CAPACITY returns the last written sector
2156                     // that means the size is actually readCap + 1
2157                     //
2158                     inf.d->usedCapacity = readCap + 1;
2159                 }
2160                 else {
2161                     //
2162                     // Only one track, use it's size
2163                     //
2164                     if( readTrackInformation( data, 0x1, 0x1 ) ) {
2165                         track_info_t* trackInfo = (track_info_t*)data.data();
2166                         inf.d->usedCapacity = from4Byte( trackInfo->track_size );
2167                     }
2168                     else
2169                         qDebug() << "(K3b::Device::Device) " << blockDeviceName()
2170                                  << "READ TRACK INFORMATION for DVD-ROM failed." << endl;
2171                 }
2172 
2173                 break;
2174             }
2175 
2176             case MEDIA_DVD_PLUS_R:
2177             case MEDIA_DVD_PLUS_R_DL:
2178                 if( inf.appendable() || inf.empty() ) {
2179                     //
2180                     // get remaining space via the invisible track
2181                     //
2182                     if( readTrackInformation( data, 0x1, /*0xff*/ inf.numTracks()+1 ) ) {
2183                         track_info_t* trackInfo = (track_info_t*)data.data();
2184                         inf.d->usedCapacity = from4Byte( trackInfo->track_start );
2185                         inf.d->capacity = from4Byte( trackInfo->track_start ) + from4Byte( trackInfo->track_size );
2186                     }
2187                 }
2188                 else {
2189                     if( readTrackInformation( data, 0x1, inf.numTracks() ) ) {
2190                         track_info_t* trackInfo = (track_info_t*)data.data();
2191                         inf.d->capacity = inf.d->usedCapacity
2192                                         = from4Byte( trackInfo->track_start ) + from4Byte( trackInfo->track_size );
2193                     }
2194                 }
2195                 break;
2196 
2197             case MEDIA_DVD_R:
2198             case MEDIA_DVD_R_SEQ:
2199             case MEDIA_DVD_R_DL:
2200             case MEDIA_DVD_R_DL_JUMP:
2201             case MEDIA_DVD_R_DL_SEQ:
2202                 //
2203                 // get data from the incomplete track (which is NOT the invisible track 0xff)
2204                 // This will fail in case the media is complete!
2205                 //
2206                 if( readTrackInformation( data, 0x1, inf.numTracks()+1 ) ) {
2207                     track_info_t* trackInfo = (track_info_t*)data.data();
2208                     inf.d->usedCapacity = from4Byte( trackInfo->track_start );
2209                     inf.d->capacity = from4Byte( trackInfo->free_blocks ) + from4Byte( trackInfo->track_start );
2210                 }
2211 
2212                 //
2213                 // Get the "really" used space without border-out
2214                 //
2215                 if( !inf.empty() ) {
2216                     K3b::Msf readCap;
2217                     if( readCapacity( readCap ) ) {
2218                         //
2219                         // READ CAPACITY returns the last written sector
2220                         // that means the size is actually readCap + 1
2221                         //
2222                         inf.d->usedCapacity = readCap + 1;
2223                     }
2224                     else
2225                         qDebug() << "(K3b::Device::Device) " << blockDeviceName()
2226                                  << " READ CAPACITY for DVD-R failed." << endl;
2227                 }
2228 
2229                 break;
2230 
2231             case MEDIA_DVD_RW_OVWR:
2232                 inf.d->numSessions = 1;
2233                 Q_FALLTHROUGH();
2234             case MEDIA_DVD_RW:
2235             case MEDIA_DVD_RW_SEQ:
2236                 // only one track on a DVD-RW media
2237                 if( readTrackInformation( data, 0x1, 0x1 ) ) {
2238                     track_info_t* trackInfo = (track_info_t*)data.data();
2239                     inf.d->capacity = from4Byte( trackInfo->track_size );
2240                     if( !inf.empty() ) {
2241                         if( readFormatCapacity( 0x10, inf.d->capacity ) )
2242                             qDebug() << blockDeviceName() << ": Format capacity 0x10: " << inf.d->capacity.toString();
2243 
2244                         inf.d->usedCapacity = from4Byte( trackInfo->track_size );
2245                     }
2246                 }
2247                 break;
2248 
2249             case MEDIA_DVD_PLUS_RW: {
2250                 K3b::Msf currentMax;
2251                 int currentMaxFormat = 0;
2252                 if( readFormatCapacity( 0x26, inf.d->capacity, &currentMax, &currentMaxFormat ) ) {
2253                     if( currentMaxFormat == 0x1 ) { // unformatted or blank media
2254                         inf.d->usedCapacity = 0;
2255                         inf.d->capacity = currentMax;
2256                     }
2257                     else {
2258                         inf.d->usedCapacity = currentMax;
2259                         // Plextor drives tend to screw things up and report invalid values
2260                         // for the max format capacity of 1.4 GB DVD media
2261                         if ( inf.bgFormatState() == BG_FORMAT_COMPLETE ) {
2262                             inf.d->capacity = currentMax;
2263                         }
2264                     }
2265                 }
2266                 else
2267                     qDebug() << "(K3b::Device::Device) " << blockDeviceName()
2268                              << " READ FORMAT CAPACITIES for DVD+RW failed." << endl;
2269 
2270                 break;
2271             }
2272 
2273             case MEDIA_BD_R:
2274             case MEDIA_BD_R_SRM:
2275             case MEDIA_BD_R_SRM_POW:
2276             case MEDIA_BD_R_RRM:
2277                 //
2278                 // get the invisible track's first sector
2279                 // or the next writable address of the last open track
2280                 //
2281                 if( readDiscInformation( data ) ) {
2282                     int lastTrack = (int)( data[11]<<8 | data[6] );
2283 
2284                     if( readTrackInformation( data, 1, lastTrack ) ) {
2285 
2286                         // capacity: last track's start address + last track's size
2287                         inf.d->capacity = from4Byte( &data[8] ) + from4Byte( &data[24] );
2288 
2289                         if( data[6] & 0x80 )
2290                             inf.d->usedCapacity = from4Byte( &data[8] );
2291                         else if( data[7] & 0x1 )
2292                             inf.d->usedCapacity = from4Byte( &data[12] );
2293                         else
2294                             inf.d->usedCapacity = inf.d->capacity;
2295                     }
2296                 }
2297                 break;
2298 
2299             case MEDIA_BD_RE: {
2300                 K3b::Msf currentMax;
2301                 int currentMaxFormat = 0;
2302                 if ( readFormatCapacity( 0x00, inf.d->capacity, &currentMax, &currentMaxFormat ) ) {
2303                     if( currentMaxFormat == 0x1 ) { // unformatted or blank media
2304                         inf.d->usedCapacity = 0;
2305                         inf.d->capacity = currentMax;
2306                     }
2307                     else {
2308                         inf.d->usedCapacity = currentMax;
2309                     }
2310                 }
2311                 else
2312                     qDebug() << "(K3b::Device::Device) " << blockDeviceName()
2313                              << " READ FORMAT CAPACITIES for BD-RE failed." << endl;
2314                 break;
2315             }
2316 
2317             case MEDIA_BD_ROM: {
2318                 K3b::Msf readCap;
2319                 if( readCapacity( readCap ) ) {
2320                     //
2321                     // READ CAPACITY returns the last written sector
2322                     // that means the size is actually readCap + 1
2323                     //
2324                     inf.d->usedCapacity = readCap + 1;
2325                 }
2326 
2327                 break;
2328             }
2329             }
2330         }
2331 
2332         if( needToClose )
2333             close();
2334     }
2335 
2336     return inf;
2337 }
2338 
2339 
mediaType() const2340 K3b::Device::MediaType K3b::Device::Device::mediaType() const
2341 {
2342     K3b::Device::MediaType m = MEDIA_UNKNOWN;
2343 
2344     if( testUnitReady() ) {
2345 
2346         int p = currentProfile();
2347         if ( p != -1 )
2348             m = ( MediaType )p;
2349 
2350         if( m & (MEDIA_UNKNOWN|MEDIA_DVD_ROM|MEDIA_HD_DVD_ROM) ) {
2351             //
2352             // We prefer the mediatype as reported by the media since this way
2353             // even ROM drives may report the correct type of writable media.
2354             //
2355 
2356             // 4 bytes header + 2048 bytes layer descriptor
2357             UByteArray data;
2358             if( readDvdStructure( data ) ) {
2359                 switch( data[4]&0xF0 ) {
2360                 case 0x00: m = MEDIA_DVD_ROM; break;
2361                 case 0x10: m = MEDIA_DVD_RAM; break;
2362                 case 0x20: m = MEDIA_DVD_R; break; // there seems to be no value for DVD-R DL, it reports DVD-R
2363                 case 0x30: m = MEDIA_DVD_RW; break;
2364                 case 0x40: m = MEDIA_HD_DVD_ROM; break;
2365                 case 0x50: m = MEDIA_HD_DVD_R; break;
2366                 case 0x60: m = MEDIA_HD_DVD_RAM; break;
2367                 case 0x90: m = MEDIA_DVD_PLUS_RW; break;
2368                 case 0xA0: m = MEDIA_DVD_PLUS_R; break;
2369                 case 0xE0: m = MEDIA_DVD_PLUS_R_DL; break;
2370                 default:
2371                     qDebug() << "(K3b::Device::Device) unknown dvd media type: " << QString::number(data[4]&0xF0, 8);
2372                     break; // unknown
2373                 }
2374             }
2375         }
2376 
2377         if( m & (MEDIA_UNKNOWN|MEDIA_BD_ROM) ) {
2378             //
2379             // We prefer the mediatype as reported by the media since this way
2380             // even ROM drives may report the correct type of writable media.
2381             //
2382 
2383             UByteArray data;
2384             if( readDiscStructure( data, 1, 0 ) ) {
2385                 if( data.size() > 4+12 &&
2386                     data[4+8] == 'B' &&  data[4+9] == 'D' ) {
2387                     switch( data[4+10] ) {
2388                     case 'O': m = MEDIA_BD_ROM; break;
2389                     case 'W': m = MEDIA_BD_RE; break;
2390                     case 'R': m = MEDIA_BD_R; break;
2391                     }
2392                 }
2393             }
2394         }
2395 
2396         //
2397         // Only old CD or DVD devices do not report a current profile
2398         // or report CD-ROM profile for all CD types
2399         //
2400         if( m & (MEDIA_UNKNOWN|MEDIA_CD_ROM) ) {
2401             UByteArray data;
2402             if( readTocPmaAtip( data, 4, false, 0 ) ) {
2403                 if( (data[6]>>6)&1 )
2404                     m = MEDIA_CD_RW;
2405                 else
2406                     m = MEDIA_CD_R;
2407             }
2408             else
2409                 m = MEDIA_CD_ROM;
2410         }
2411     }
2412 
2413     return m;
2414 }
2415 
2416 
readSectorsRaw(unsigned char * buf,int start,int count) const2417 bool K3b::Device::Device::readSectorsRaw( unsigned char *buf, int start, int count ) const
2418 {
2419     return readCd( buf, count*2352,
2420                    0,      // all sector types
2421                    false,  // no dap
2422                    start,
2423                    count,
2424                    true, // SYNC
2425                    true, // HEADER
2426                    true, // SUBHEADER
2427                    true, // USER DATA
2428                    true, // EDC/ECC
2429                    0,    // no c2 info
2430                    0 );
2431 }
2432 
2433 
2434 
checkForJustLink()2435 void K3b::Device::Device::checkForJustLink()
2436 {
2437     UByteArray ricoh;
2438     if( modeSense( ricoh, 0x30 ) ) {
2439 
2440         //
2441         // 8 byte mode header + 6 byte page data
2442         //
2443 
2444         if( ricoh.size() >= 14 ) {
2445             ricoh_mode_page_30* rp = (ricoh_mode_page_30*)(ricoh.data()+8);
2446             d->burnfree = rp->BUEFS;
2447         }
2448     }
2449 }
2450 
2451 
checkFeatures()2452 void K3b::Device::Device::checkFeatures()
2453 {
2454     unsigned char header[1024];
2455     ::memset( header, 0, 1024 );
2456 
2457     ScsiCommand cmd( this );
2458     cmd[0] = MMC_GET_CONFIGURATION;
2459     cmd[1] = 2;
2460     cmd[9] = 0;      // Necessary to set the proper command length
2461 
2462 
2463     //
2464     // CD writing features
2465     //
2466     cmd[2] = FEATURE_CD_MASTERING>>8;
2467     cmd[3] = FEATURE_CD_MASTERING;
2468     cmd[8] = 8+8;
2469     if( !cmd.transport( TR_DIR_READ, header, 16 ) ) {
2470         unsigned int len = from4Byte( header );
2471         if( len >= 12 ) {
2472             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "CD Mastering";
2473 #ifdef WORDS_BIGENDIAN
2474             struct cd_mastering_feature {
2475                 unsigned char reserved1 : 1;
2476                 unsigned char BUF       : 1;  // Burnfree
2477                 unsigned char SAO       : 1;  // Session At Once writing
2478                 unsigned char raw_ms    : 1;  // Writing Multisession in Raw Writing Mode
2479                 unsigned char raw       : 1;  // Writing in WRITINGMODE_RAW mode
2480                 unsigned char testwrite : 1;  // Simulation write support
2481                 unsigned char cd_rw     : 1;  // CD-RW support
2482                 unsigned char rw_sub    : 1;  // Write R-W sub channels with user data
2483                 unsigned char max_cue_length[3];
2484             };
2485 #else
2486             struct cd_mastering_feature {
2487                 unsigned char rw_sub    : 1;  // Write R-W sub channels with user data
2488                 unsigned char cd_rw     : 1;  // CD-RW support
2489                 unsigned char testwrite : 1;  // Simulation write support
2490                 unsigned char raw       : 1;  // Writing in WRITINGMODE_RAW mode
2491                 unsigned char raw_ms    : 1;  // Writing Multisession in Raw Writing Mode
2492                 unsigned char SAO       : 1;  // Session At Once writing
2493                 unsigned char BUF       : 1;  // Burnfree
2494                 unsigned char reserved1 : 1;
2495                 unsigned char max_cue_length[3];
2496             };
2497 #endif
2498 
2499             struct cd_mastering_feature* p = (struct cd_mastering_feature*)&header[12];
2500             if( p->BUF ) d->burnfree = true;
2501             d->writeCapabilities |= MEDIA_CD_R;
2502             if( p->cd_rw )
2503                 d->writeCapabilities |= MEDIA_CD_RW;
2504 //       if( p->WRITINGMODE_SAO ) d->writeModes |= WRITINGMODE_SAO;
2505 //       if( p->raw || p->raw_ms ) d->writeModes |= WRITINGMODE_RAW;  // WRITINGMODE_RAW16 always supported when raw is supported?
2506         }
2507     }
2508 
2509     cmd[2] = FEATURE_CD_TRACK_AT_ONCE>>8;
2510     cmd[3] = FEATURE_CD_TRACK_AT_ONCE;
2511     cmd[8] = 8+8;
2512     if( !cmd.transport( TR_DIR_READ, header, 16 ) ) {
2513         unsigned int len = from4Byte( header );
2514         if( len >= 12 ) {
2515             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "CD Track At Once";
2516 #ifdef WORDS_BIGENDIAN
2517             struct cd_track_at_once_feature {
2518                 unsigned char reserved1 : 1;
2519                 unsigned char BUF       : 1;  // Burnfree
2520                 unsigned char reserved2 : 1;
2521                 unsigned char rw_raw    : 1;  // Writing R-W subcode in Raw mode
2522                 unsigned char rw_pack   : 1;  // Writing R-W subcode in Packet mode
2523                 unsigned char testwrite : 1;  // Simulation write support
2524                 unsigned char cd_rw     : 1;  // CD-RW support
2525                 unsigned char rw_sub    : 1;  // Write R-W sub channels with user data
2526                 unsigned char reserved3;
2527                 unsigned char data_type[2];
2528             };
2529 #else
2530             struct cd_track_at_once_feature {
2531                 unsigned char rw_sub    : 1;  // Write R-W sub channels with user data
2532                 unsigned char cd_rw     : 1;  // CD-RW support
2533                 unsigned char testwrite : 1;  // Simulation write support
2534                 unsigned char rw_pack   : 1;  // Writing R-W subcode in Packet mode
2535                 unsigned char rw_raw    : 1;  // Writing R-W subcode in Raw mode
2536                 unsigned char reserved2 : 1;
2537                 unsigned char BUF       : 1;  // Burnfree
2538                 unsigned char reserved1 : 1;
2539                 unsigned char reserved3;
2540                 unsigned char data_type[2];
2541             };
2542 #endif
2543 
2544             struct cd_track_at_once_feature* p = (struct cd_track_at_once_feature*)&header[12];
2545             d->writeModes |= WRITINGMODE_TAO;
2546             if( p->BUF ) d->burnfree = true;
2547             d->writeCapabilities |= MEDIA_CD_R;
2548             if( p->cd_rw )
2549                 d->writeCapabilities |= MEDIA_CD_RW;
2550 
2551             // is the following correct? What exactly does rw_sub tell us?
2552 //       if( d->writeModes & WRITINGMODE_RAW ) {
2553 //  if( p->rw_raw ) d->writeModes |= WRITINGMODE_RAW_R96R;
2554 //  if( p->rw_pack ) d->writeModes |= WRITINGMODE_RAW_R96P;
2555 //       }
2556 
2557 //       // check the data types for 1, 2, and 3 (raw16, raw96p, and raw96r)
2558 //        debugBitfield( p->data_type, 2 );
2559 //       if( d->writeModes & WRITINGMODE_RAW ) {
2560 //  if( p->data_type[1] & 0x20 ) d->writeModes |= WRITINGMODE_RAW_R16;
2561 //  if( p->data_type[1] & 0x40 ) d->writeModes |= WRITINGMODE_RAW_R96P;
2562 //  if( p->data_type[1] & 0x80 ) d->writeModes |= WRITINGMODE_RAW_R96R;
2563 //       }
2564         }
2565     }
2566 
2567     cmd[2] = FEATURE_CD_RW_MEDIA_WRITE_SUPPORT>>8;
2568     cmd[3] = FEATURE_CD_RW_MEDIA_WRITE_SUPPORT;
2569     cmd[8] = 8+8;
2570     if( !cmd.transport( TR_DIR_READ, header, 16 ) ) {
2571         unsigned int len = from4Byte( header );
2572         if( len >= 12 ) {
2573             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "CD-RW Media Write Support";
2574             d->writeCapabilities |= (MEDIA_CD_R|MEDIA_CD_RW);
2575         }
2576     }
2577 
2578 
2579     //
2580     // DVD-ROM
2581     //
2582     // FIXME: since MMC5 the feature descr. is 8 bytes in length including a dvd dl read bit at byte 6
2583     cmd[2] = FEATURE_DVD_READ>>8;
2584     cmd[3] = FEATURE_DVD_READ;
2585     cmd[8] = 8+8;
2586     if( !cmd.transport( TR_DIR_READ, header, 16 ) ) {
2587         unsigned int len = from4Byte( header );
2588         if( len >= 12 ) {
2589             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "DVD Read (MMC5)";
2590             d->readCapabilities |= MEDIA_DVD_ROM;
2591             if( header[8+6] & 0x1 )
2592                 d->readCapabilities |= MEDIA_WRITABLE_DVD_DL;
2593         }
2594     }
2595     else {
2596         // retry with pre-MMC5 length
2597         cmd[8] = 8+4;
2598         if( !cmd.transport( TR_DIR_READ, header, 12 ) ) {
2599             unsigned int len = from4Byte( header );
2600             if( len >= 8 ) {
2601                 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "DVD Read (pre-MMC5)";
2602                 d->readCapabilities |= MEDIA_DVD_ROM;
2603             }
2604         }
2605     }
2606 
2607     //
2608     // DVD+R(W) writing features
2609     //
2610     cmd[2] = FEATURE_DVD_PLUS_R>>8;
2611     cmd[3] = FEATURE_DVD_PLUS_R;
2612     cmd[8] = 8+8;
2613     if( !cmd.transport( TR_DIR_READ, header, 16 ) ) {
2614         unsigned int len = from4Byte( header );
2615         if( len >= 12 ) {
2616             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "DVD+R";
2617             d->readCapabilities |= MEDIA_DVD_PLUS_R;
2618             if( header[12] & 0x1 )
2619                 d->writeCapabilities |= MEDIA_DVD_PLUS_R;
2620         }
2621     }
2622 
2623     cmd[2] = FEATURE_DVD_PLUS_RW>>8;
2624     cmd[3] = FEATURE_DVD_PLUS_RW;
2625     cmd[8] = 8+8;
2626     if( !cmd.transport( TR_DIR_READ, header, 16 ) ) {
2627         unsigned int len = from4Byte( header );
2628         if( len >= 12 ) {
2629             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "DVD+RW";
2630 #ifdef WORDS_BIGENDIAN
2631             struct dvd_plus_rw_feature {
2632                 unsigned char reserved1   : 7;
2633                 unsigned char write       : 1;
2634                 unsigned char reserved2   : 6;
2635                 unsigned char quick_start : 1;
2636                 unsigned char close_only  : 1;
2637                 // and some stuff we do not use here...
2638             };
2639 #else
2640             struct dvd_plus_rw_feature {
2641                 unsigned char write       : 1;
2642                 unsigned char reserved1   : 7;
2643                 unsigned char close_only  : 1;
2644                 unsigned char quick_start : 1;
2645                 unsigned char reserved2   : 6;
2646                 // and some stuff we do not use here...
2647             };
2648 #endif
2649 
2650             struct dvd_plus_rw_feature* p = (struct dvd_plus_rw_feature*)&header[12];
2651             d->readCapabilities |= MEDIA_DVD_PLUS_RW;
2652             if( p->write )
2653                 d->writeCapabilities |= MEDIA_DVD_PLUS_RW;
2654         }
2655     }
2656 
2657 
2658     // some older DVD-ROM drives claim to support DVD+R DL
2659     if( d->writeCapabilities & MEDIA_DVD_PLUS_R ) {
2660         cmd[2] = FEATURE_DVD_PLUS_RW_DUAL_LAYER>>8;
2661         cmd[3] = FEATURE_DVD_PLUS_RW_DUAL_LAYER;
2662         cmd[8] = 8+8;
2663         if( !cmd.transport( TR_DIR_READ, header, 16 ) ) {
2664             unsigned int len = from4Byte( header );
2665             if( len >= 12 ) {
2666                 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "DVD+RW Double Layer";
2667                 d->readCapabilities |= MEDIA_DVD_PLUS_RW_DL;
2668                 if( header[12] & 0x1 )
2669                     d->writeCapabilities |= MEDIA_DVD_PLUS_RW_DL;
2670             }
2671         }
2672 
2673         cmd[2] = FEATURE_DVD_PLUS_R_DUAL_LAYER>>8;
2674         cmd[3] = FEATURE_DVD_PLUS_R_DUAL_LAYER;
2675         cmd[8] = 8+8;
2676         if( !cmd.transport( TR_DIR_READ, header, 16 ) ) {
2677             unsigned int len = from4Byte( header );
2678             if( len >= 12 ) {
2679                 qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "DVD+R Double Layer";
2680                 d->readCapabilities |= MEDIA_DVD_PLUS_R_DL;
2681                 if( header[12] & 0x1 )
2682                     d->writeCapabilities |= MEDIA_DVD_PLUS_R_DL;
2683             }
2684         }
2685     }
2686 
2687 
2688     //
2689     // Blue Ray
2690     //
2691     // We do not care for the different BD classes and versions here
2692     //
2693     cmd[2] = FEATURE_BD_READ>>8;
2694     cmd[3] = FEATURE_BD_READ;
2695     cmd[8] = 8+32;
2696     if( !cmd.transport( TR_DIR_READ, header, 40 ) ) {
2697         unsigned int len = from4Byte( header );
2698         if( len >= 36 ) {
2699             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "BD Read";
2700             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] )
2701                 d->readCapabilities |= MEDIA_BD_RE;
2702             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] )
2703                 d->readCapabilities |= MEDIA_BD_R;
2704             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] )
2705                 d->readCapabilities |= MEDIA_BD_ROM;
2706         }
2707     }
2708 
2709     cmd[2] = FEATURE_BD_WRITE>>8;
2710     cmd[3] = FEATURE_BD_WRITE;
2711     cmd[8] = 8+24;
2712     if( !cmd.transport( TR_DIR_READ, header, 32 ) ) {
2713         unsigned int len = from4Byte( header );
2714         if( len >= 28 ) {
2715             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "BD Write";
2716             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] )
2717                 d->writeCapabilities |= MEDIA_BD_RE;
2718             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] ) {
2719                 d->writeCapabilities |= (MEDIA_BD_R|MEDIA_BD_R_SRM);
2720                 d->writeModes |= WRITINGMODE_SRM;
2721 
2722                 cmd[2] = FEATURE_BD_PSEUDO_OVERWRITE>>8;
2723                 cmd[3] = FEATURE_BD_PSEUDO_OVERWRITE;
2724                 cmd[8] = 8+8;
2725                 if( !cmd.transport( TR_DIR_READ, header, 8+8 ) ) {
2726                     unsigned int len = from4Byte( header );
2727                     if( len >= 4+8 ) {
2728                         d->writeCapabilities |= MEDIA_BD_R_SRM_POW;
2729                         d->writeModes |= WRITINGMODE_SRM_POW;
2730                     }
2731                 }
2732 
2733                 cmd[2] = FEATURE_RANDOM_WRITABLE>>8;
2734                 cmd[3] = FEATURE_RANDOM_WRITABLE;
2735                 cmd[8] = 8+16;
2736                 if( !cmd.transport( TR_DIR_READ, header, 8+16 ) ) {
2737                     unsigned int len = from4Byte( header );
2738                     if( len >= 4+16 ) {
2739                         d->writeCapabilities |= MEDIA_BD_R_RRM;
2740                         d->writeModes |= WRITINGMODE_RRM;
2741                     }
2742                 }
2743             }
2744         }
2745     }
2746 
2747 
2748 
2749     //
2750     // DVD-R(W)
2751     //
2752     cmd[2] = FEATURE_DVD_R_RW_WRITE>>8;
2753     cmd[3] = FEATURE_DVD_R_RW_WRITE;
2754     cmd[8] = 16;
2755     if( !cmd.transport( TR_DIR_READ, header, 16 ) ) {
2756         unsigned int len = from4Byte( header );
2757         if( len >= 12 ) {
2758             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "DVD-R/-RW Write";
2759 #ifdef WORDS_BIGENDIAN
2760             struct dvd_r_rw_write_feature {
2761                 unsigned char reserved1 : 1;
2762                 unsigned char BUF       : 1;  // Burnfree
2763                 unsigned char reserved2 : 2;
2764                 unsigned char RDL       : 1;
2765                 unsigned char testwrite : 1;  // Simulation write support
2766                 unsigned char dvd_rw    : 1;  // DVD-RW Writing
2767                 unsigned char reserved3 : 1;
2768                 unsigned char reserved4[3];
2769             };
2770 #else
2771             struct dvd_r_rw_write_feature {
2772                 unsigned char reserved3 : 1;
2773                 unsigned char dvd_rw    : 1;  // DVD-RW Writing
2774                 unsigned char testwrite : 1;  // Simulation write support
2775                 unsigned char RDL       : 1;
2776                 unsigned char reserved2 : 2;
2777                 unsigned char BUF       : 1;  // Burnfree
2778                 unsigned char reserved1 : 1;
2779                 unsigned char reserved4[3];
2780             };
2781 #endif
2782 
2783             struct dvd_r_rw_write_feature* p = (struct dvd_r_rw_write_feature*)&header[12];
2784             if( p->BUF ) d->burnfree = true;
2785             d->writeCapabilities |= (MEDIA_DVD_R|MEDIA_DVD_R_SEQ);
2786             if( p->dvd_rw )
2787                 d->writeCapabilities |= (MEDIA_DVD_RW|MEDIA_DVD_RW_SEQ);
2788             if( p->RDL )
2789                 d->writeCapabilities |= (MEDIA_DVD_R_DL|MEDIA_DVD_R_DL_SEQ);
2790 
2791             d->dvdMinusTestwrite = p->testwrite;
2792         }
2793     }
2794 
2795 
2796     //
2797     // DVD-RW restricted overwrite check
2798     //
2799     cmd[2] = FEATURE_RIGID_RESTRICTED_OVERWRITE>>8;
2800     cmd[3] = FEATURE_RIGID_RESTRICTED_OVERWRITE;
2801     cmd[8] = 16;
2802     if( !cmd.transport( TR_DIR_READ, header, 16 ) ) {
2803         unsigned int len = from4Byte( header );
2804         if( len >= 12 ) {
2805             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "Rigid Restricted Overwrite";
2806             d->writeModes |= WRITINGMODE_RES_OVWR;
2807             d->writeCapabilities |= (MEDIA_DVD_RW|MEDIA_DVD_RW_OVWR);
2808         }
2809     }
2810 
2811 
2812     //
2813     // DVD-R Dual Layer Layer
2814     //
2815     cmd[2] = FEATURE_LAYER_JUMP_RECORDING>>8;
2816     cmd[3] = FEATURE_LAYER_JUMP_RECORDING;
2817     cmd[8] = 12;
2818     if( !cmd.transport( TR_DIR_READ, header, 12 ) ) {
2819         // Now the jump feature is longer than 4 bytes but we don't need the link sizes.
2820         unsigned int len = from4Byte( header );
2821         if( len >= 8 ) {
2822             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "Layer Jump Recording";
2823             d->writeCapabilities |= (MEDIA_DVD_R_DL|MEDIA_DVD_R_DL_JUMP);
2824             d->writeModes |= WRITINGMODE_LAYER_JUMP;
2825         }
2826     }
2827 
2828 
2829     //
2830     // HD-DVD-ROM
2831     //
2832     cmd[2] = FEATURE_HD_DVD_READ>>8;
2833     cmd[3] = FEATURE_HD_DVD_READ;
2834     cmd[8] = 16;
2835     if( !cmd.transport( TR_DIR_READ, header, 16 ) ) {
2836         unsigned int len = from4Byte( header );
2837         if( len >= 12 ) {
2838             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "HD-DVD Read";
2839             d->readCapabilities |= MEDIA_HD_DVD_ROM;
2840             if( header[8+4] & 0x1 )
2841                 d->readCapabilities |= MEDIA_HD_DVD_R;
2842             if( header[8+6] & 0x1 )
2843                 d->readCapabilities |= MEDIA_HD_DVD_RAM;
2844         }
2845     }
2846 
2847 
2848     //
2849     // HD-DVD-R(AM)
2850     //
2851     cmd[2] = FEATURE_HD_DVD_WRITE>>8;
2852     cmd[3] = FEATURE_HD_DVD_WRITE;
2853     cmd[8] = 16;
2854     if( !cmd.transport( TR_DIR_READ, header, 16 ) ) {
2855         unsigned int len = from4Byte( header );
2856         if( len >= 12 ) {
2857             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " feature: " << "HD-DVD Write";
2858             if( header[8+4] & 0x1 )
2859                 d->writeCapabilities |= MEDIA_HD_DVD_R;
2860             if( header[8+6] & 0x1 )
2861                 d->writeCapabilities |= MEDIA_HD_DVD_RAM;
2862         }
2863     }
2864 
2865 
2866 
2867     //
2868     // Get the profiles
2869     //
2870     // the max len of the returned data is 8 (header) + 4 (feature) + 255 (additional length)
2871     //
2872     cmd[2] = FEATURE_PROFILE_LIST>>8;
2873     cmd[3] = FEATURE_PROFILE_LIST;
2874     cmd[8] = 12; // get the number of returned profiles first
2875     if( !cmd.transport( TR_DIR_READ, header, 12 ) ) {
2876         unsigned int len = from4Byte( header ) + 4;
2877         if( len >= 12 ) {
2878             cmd[7] = len>>8;
2879             cmd[8] = len;
2880             if( !cmd.transport( TR_DIR_READ, header, len ) ) {
2881                 int featureLen( header[11] );
2882                 for( int j = 0; j < featureLen; j+=4 ) {
2883                     short profile = from2Byte( &header[12+j] );
2884 
2885                     switch (profile) {
2886                     case 0x08:
2887                         d->supportedProfiles |= MEDIA_CD_ROM;
2888                         break;
2889                     case 0x09:
2890                         d->supportedProfiles |= MEDIA_CD_R;
2891                         break;
2892                     case 0x0A:
2893                         d->supportedProfiles |= MEDIA_CD_RW;
2894                         break;
2895                     case 0x10:
2896                         d->supportedProfiles |= MEDIA_DVD_ROM;
2897                         //      d->readCapabilities |= MEDIA_DVD_ROM;
2898                         break;
2899                     case 0x11:
2900                         d->supportedProfiles |= MEDIA_DVD_R_SEQ;
2901                         //      d->writeCapabilities |= (MEDIA_DVD_R|MEDIA_DVD_R_SEQ);
2902                         break;
2903                     case 0x12:
2904                         d->supportedProfiles |= MEDIA_DVD_RAM;
2905 //          d->readCapabilities |= (MEDIA_DVD_RAM|MEDIA_DVD_ROM);
2906 //          d->writeCapabilities |= MEDIA_DVD_RAM;
2907                         break;
2908                     case 0x13:
2909                         d->supportedProfiles |= MEDIA_DVD_RW_OVWR;
2910                         //      d->writeCapabilities |= (MEDIA_DVD_RW|MEDIA_DVD_RW_OVWR);
2911                         break;
2912                     case 0x14:
2913                         d->supportedProfiles |= MEDIA_DVD_RW_SEQ;
2914                         //      d->writeCapabilities |= (MEDIA_DVD_RW|MEDIA_DVD_R|MEDIA_DVD_RW_SEQ|MEDIA_DVD_R_SEQ);
2915                         break;
2916                     case 0x15:
2917                         d->supportedProfiles |= MEDIA_DVD_R_DL_SEQ;
2918                         //      d->writeCapabilities |= (MEDIA_DVD_R|MEDIA_DVD_R_DL|MEDIA_DVD_R_SEQ|MEDIA_DVD_R_DL_SEQ);
2919                         break;
2920                     case 0x16:
2921                         d->supportedProfiles |= MEDIA_DVD_R_DL_JUMP;
2922                         //      d->writeCapabilities |= (MEDIA_DVD_R|MEDIA_DVD_R_DL||MEDIA_DVD_R_DL_JUMP);
2923                         break;
2924                     case 0x1A:
2925                         d->supportedProfiles |= MEDIA_DVD_PLUS_RW;
2926                         //      d->writeCapabilities |= MEDIA_DVD_PLUS_RW;
2927                         break;
2928                     case 0x1B:
2929                         d->supportedProfiles |= MEDIA_DVD_PLUS_R;
2930                         //      d->writeCapabilities |= MEDIA_DVD_PLUS_R;
2931                         break;
2932                     case 0x2A:
2933                         d->supportedProfiles |= MEDIA_DVD_PLUS_RW_DL;
2934                         //      d->writeCapabilities |= MEDIA_DVD_PLUS_RW_DL;
2935                         break;
2936                     case 0x2B:
2937                         d->supportedProfiles |= MEDIA_DVD_PLUS_R_DL;
2938                         //      d->writeCapabilities |= MEDIA_DVD_PLUS_R_DL;
2939                         break;
2940                     case 0x40:
2941                         d->supportedProfiles |= MEDIA_BD_ROM;
2942                         break;
2943                     case 0x41:
2944                         d->supportedProfiles |= MEDIA_BD_R_SRM;
2945                         break;
2946                     case 0x42:
2947                         d->supportedProfiles |= MEDIA_BD_R_RRM;
2948                         break;
2949                     case 0x43:
2950                         d->supportedProfiles |= MEDIA_BD_RE;
2951                         break;
2952                     case 0x50:
2953                         d->supportedProfiles |= MEDIA_HD_DVD_ROM;
2954                         break;
2955                     case 0x51:
2956                         d->supportedProfiles |= MEDIA_HD_DVD_R;
2957                         break;
2958                     case 0x52:
2959                         d->supportedProfiles |= MEDIA_HD_DVD_RAM;
2960                         break;
2961                     default:
2962                         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " unknown profile: "
2963                                  << profile << endl;
2964                     }
2965                 }
2966 
2967                 // some older DVD-ROM drives claim to support DVD+R DL
2968                 if( !(d->supportedProfiles & MEDIA_DVD_PLUS_R) ) {
2969                     // remove DVD+R DL capability
2970                     //    d->writeCapabilities &= ~MEDIA_DVD_PLUS_R_DL;
2971                     d->supportedProfiles &= ~MEDIA_DVD_PLUS_R_DL;
2972                 }
2973             }
2974         }
2975     }
2976 }
2977 
2978 
checkFor2AFeatures()2979 void K3b::Device::Device::checkFor2AFeatures()
2980 {
2981     UByteArray mm_cap_buffer;
2982 
2983     if( modeSense( mm_cap_buffer, 0x2A ) ) {
2984         mm_cap_page_2A* mm_p = (mm_cap_page_2A*)(mm_cap_buffer.data()+8);
2985         if( mm_p->BUF )
2986             d->burnfree = true;
2987 
2988         if( mm_p->cd_r_write )
2989             d->writeCapabilities |= MEDIA_CD_R;
2990         else
2991             d->writeCapabilities &= ~MEDIA_CD_R;
2992 
2993         if( mm_p->cd_rw_write )
2994             d->writeCapabilities |= MEDIA_CD_RW;
2995         else
2996             d->writeCapabilities &= ~MEDIA_CD_RW;
2997 
2998         if( mm_p->dvd_r_write )
2999             d->writeCapabilities |= MEDIA_DVD_R;
3000         else
3001             d->writeCapabilities &= ~MEDIA_DVD_R;
3002 
3003         if( mm_p->dvd_rom_read || mm_p->dvd_r_read )
3004             d->readCapabilities |= MEDIA_DVD_ROM;
3005 
3006         d->maxReadSpeed = from2Byte(mm_p->max_read_speed);
3007         d->bufferSize = from2Byte( mm_p->buffer_size );
3008     }
3009     else {
3010         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": read mode page 2A failed!";
3011     }
3012 }
3013 
3014 
checkWritingModes()3015 void K3b::Device::Device::checkWritingModes()
3016 {
3017     // if the device is already opened we do not close it
3018     // to allow fast multiple method calls in a row
3019     bool needToClose = !isOpen();
3020 
3021     if( !open() )
3022         return;
3023 
3024     // header size is 8
3025     UByteArray buffer;
3026 
3027     if( !modeSense( buffer, 0x05 ) ) {
3028         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": modeSense 0x05 failed!" << endl
3029                  << "(K3b::Device::Device) " << blockDeviceName() << ": Cannot check write modes." << endl;
3030     }
3031     else if( buffer.size() < 18 ) { // 8 bytes header + 10 bytes used modepage
3032         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": Missing modepage 0x05 data." << endl
3033                  << "(K3b::Device::Device) " << blockDeviceName() << ": Cannot check write modes." << endl;
3034     }
3035     else {
3036         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": buffer.size(): " << buffer.size();
3037 
3038         wr_param_page_05* mp = (struct wr_param_page_05*)(buffer.data()+8);
3039 
3040         // reset some stuff to be on the safe side
3041         mp->PS = 0;
3042         mp->BUFE = 0;
3043         mp->multi_session = 0;
3044         mp->test_write = 0;
3045         mp->LS_V = 0;
3046         mp->copy = 0;
3047         mp->fp = 0;
3048         mp->host_appl_code= 0;
3049         mp->session_format = 0;
3050         mp->audio_pause_len[0] = 0;
3051         mp->audio_pause_len[1] = 150;
3052 
3053         // WRITINGMODE_TAO
3054         mp->write_type = 0x01;  // Track-at-once
3055         mp->track_mode = 4;     // MMC-4 says: 5, cdrecord uses 4 ?
3056         mp->dbtype = 8;         // Mode 1
3057 
3058         //    qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": modeselect WRITINGMODE_TAO data: ";
3059         //    debugBitfield( buffer.data(), buffer.size() );
3060 
3061 
3062         //
3063         // 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
3064         // requirement
3065         //
3066 
3067         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": checking for TAO";
3068         if( modeSelect( buffer, 1, 0 ) ) {
3069             d->writeModes |= WRITINGMODE_TAO;
3070             d->writeCapabilities |= MEDIA_CD_R;
3071 
3072             // WRITINGMODE_SAO
3073             mp->write_type = 0x02; // Session-at-once
3074 
3075             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": checking for SAO";
3076             if( modeSelect( buffer, 1, 0 ) )
3077                 d->writeModes |= WRITINGMODE_SAO;
3078 
3079 //       mp->dbtype = 1;        // Raw data with P and Q Sub-channel (2368 bytes)
3080 //       if( modeSelect( buffer, 1, 0 ) ) {
3081 //  d->writeModes |= WRITINGMODE_RAW_R16;
3082 //       }
3083 
3084             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": checking for SAO_R96P";
3085             mp->dbtype = 2;        // Raw data with P-W Sub-channel (2448 bytes)
3086             if( modeSelect( buffer, 1, 0 ) ) {
3087                 d->writeModes |= WRITINGMODE_SAO_R96P;
3088             }
3089 
3090             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": checking for SAO_R96R";
3091             mp->dbtype = 3;        // Raw data with P-W raw Sub-channel (2448 bytes)
3092             if( modeSelect( buffer, 1, 0 ) ) {
3093                 d->writeModes |= WRITINGMODE_SAO_R96R;
3094             }
3095 
3096             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": checking for RAW_R16";
3097             // WRITINGMODE_RAW
3098             mp->write_type = 0x03; // WRITINGMODE_RAW
3099             mp->dbtype = 1;        // Raw data with P and Q Sub-channel (2368 bytes)
3100             if( modeSelect( buffer, 1, 0 ) ) {
3101                 d->writeModes |= WRITINGMODE_RAW;
3102                 d->writeModes |= WRITINGMODE_RAW_R16;
3103             }
3104 
3105             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": checking for RAW_R96P";
3106             mp->dbtype = 2;        // Raw data with P-W Sub-channel (2448 bytes)
3107             if( modeSelect( buffer, 1, 0 ) ) {
3108                 d->writeModes |= WRITINGMODE_RAW;
3109                 d->writeModes |= WRITINGMODE_RAW_R96P;
3110             }
3111 
3112             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": checking for RAW_R96R";
3113             mp->dbtype = 3;        // Raw data with P-W raw Sub-channel (2448 bytes)
3114             if( modeSelect( buffer, 1, 0 ) ) {
3115                 d->writeModes |= WRITINGMODE_RAW;
3116                 d->writeModes |= WRITINGMODE_RAW_R96R;
3117             }
3118         }
3119         else {
3120             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": modeSelect with WRITINGMODE_TAO failed. No writer";
3121         }
3122     }
3123 
3124     if( needToClose )
3125         close();
3126 }
3127 
3128 
getMaxWriteSpeedVia2A() const3129 int K3b::Device::Device::getMaxWriteSpeedVia2A() const
3130 {
3131     int ret = 0;
3132 
3133     UByteArray data;
3134 
3135     if( modeSense( data, 0x2A ) ) {
3136         mm_cap_page_2A* mm = (mm_cap_page_2A*)&data[8];
3137 
3138         // MMC1 used byte 18 and 19 for the max write speed
3139         if( data.size() > 19 )
3140             ret = from2Byte( mm->max_write_speed );
3141     }
3142 
3143     return ret;
3144 }
3145 
3146 
determineMaximalWriteSpeed() const3147 int K3b::Device::Device::determineMaximalWriteSpeed() const
3148 {
3149     int ret = 0;
3150 
3151     if( mediaType() & MEDIA_CD_ALL ) {
3152         ret = getMaxWriteSpeedVia2A();
3153         if ( ret > 0 )
3154             return ret;
3155     }
3156 
3157     QList<int> list = determineSupportedWriteSpeeds();
3158     if( !list.isEmpty() ) {
3159         for( QList<int>::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
3160             ret = qMax( ret, *it );
3161     }
3162 
3163     if( ret > 0 )
3164         return ret;
3165     else
3166         return d->maxWriteSpeed;
3167 }
3168 
3169 
determineSupportedWriteSpeeds() const3170 QList<int> K3b::Device::Device::determineSupportedWriteSpeeds() const
3171 {
3172     QList<int> ret;
3173 
3174     if( burner() ) {
3175         //
3176         // Tests with all my drives resulted in 2A for CD and GET PERFORMANCE for DVD media
3177         // as the valid method of speed detection.
3178         //
3179         MediaType m = mediaType();
3180         if( m & MEDIA_CD_ALL ) {
3181             if( !getSupportedWriteSpeedsVia2A( ret, m ) )
3182                 getSupportedWriteSpeedsViaGP( ret, m );
3183 
3184             // restrict to max speed, although deprecated in MMC3 is still used everywhere and
3185             // cdrecord also uses it as the max writing speed.
3186             int max = 0;
3187             UByteArray data;
3188             if( modeSense( data, 0x2A ) && data.size() >= 8 ) {
3189                 const mm_cap_page_2A* mm = (mm_cap_page_2A const*)&data.at(8);
3190 
3191                 // MMC1 used byte 18 and 19 for the max write speed
3192                 if( data.size() > 19 )
3193                     max = from2Byte( mm->max_write_speed );
3194 
3195                 if( max > 0 ) {
3196                     while( !ret.isEmpty() && ret.last() > max ) {
3197                         qDebug() << "(K3b::Device::Device) " << blockDeviceName()
3198                                  << " writing speed " << ret.last() << " higher than max " << max << endl;
3199                         ret.pop_back();
3200                     }
3201                 }
3202             }
3203         }
3204         else {
3205             if( !getSupportedWriteSpeedsViaGP( ret, m ) )
3206                 getSupportedWriteSpeedsVia2A( ret, m );
3207         }
3208 
3209         // construct writing speeds for old devices
3210         if ( ret.isEmpty() && K3b::Device::isCdMedia( m ) ) {
3211             int max = getMaxWriteSpeedVia2A();
3212             for ( int i = 1; i <= max/SPEED_FACTOR_CD; i *= 2 ) {
3213                 ret.append( i * SPEED_FACTOR_CD );
3214             }
3215         }
3216     }
3217 
3218     return ret;
3219 }
3220 
3221 
getSupportedWriteSpeedsVia2A(QList<int> & list,MediaType mediaType) const3222 bool K3b::Device::Device::getSupportedWriteSpeedsVia2A(QList<int>& list,
3223                                                     MediaType mediaType) const
3224 {
3225     UByteArray/* QVarLengthArray<unsigned char> */ data;
3226     if (modeSense(data, 0x2A)) {
3227         mm_cap_page_2A* mm = (mm_cap_page_2A*)&data[8];
3228 
3229         // 8 bytes of MODE SENSE(10) header
3230         // 32 bytes offset of speed descriptor list in Mode page 2Ah
3231         // (MMC-3, table 361. Pages of MMC-1 and MMC-2 are smaller.)
3232         if (data.size() > 32 + 8/* replyLen */) {
3233             // we have descriptors
3234             unsigned int numDesc = from2Byte(mm->num_wr_speed_des);
3235 
3236             // Ensure number of descriptors claimed actually fits in the data
3237             // returned by the mode sense command.
3238             if (static_cast<int>(numDesc) > ((data.size() - 32 - 8) / 4))
3239                 numDesc = (data.size() - 32 - 8) / 4;
3240 
3241             cd_wr_speed_performance* wr =
3242                 (cd_wr_speed_performance*)mm->wr_speed_des;
3243 
3244             qDebug() << "(K3b::Device::Device) " << blockDeviceName()
3245                      << ":  Number of supported write speeds via 2A: "
3246                      << numDesc << endl;
3247 
3248             for (unsigned int i = 0; i < numDesc; ++i) {
3249                 int s = (int)from2Byte(wr[i].wr_speed_supp);
3250                 //
3251                 // some DVD writers report CD writing speeds here
3252                 // If that is the case we cannot rely on the reported speeds
3253                 // and need to use the values gained from GET PERFORMANCE.
3254                 //
3255                 if( isDvdMedia( mediaType ) && s < 1352 ) {
3256                     qDebug() << "(K3b::Device::Device) " << blockDeviceName()
3257                              << " Invalid DVD speed: " << s << " KB/s" << endl;
3258                     list.clear();
3259                     break;
3260                 }
3261                 else {
3262                     qDebug() << "(K3b::Device::Device) " << blockDeviceName()
3263                              << " : " << s << " KB/s" << endl;
3264 
3265                     if( isDvdMedia( mediaType ) )
3266                         s = fixupDvdWritingSpeed( s );
3267 
3268                     // sort the list
3269                     QList<int>::iterator it = list.begin();
3270                     while( it != list.end() && *it < s )
3271                         ++it;
3272                     list.insert( it, s );
3273                 }
3274             }
3275         }
3276     }
3277 
3278     return !list.isEmpty();
3279 }
3280 
3281 
getSupportedWriteSpeedsViaGP(QList<int> & list,MediaType mediaType) const3282 bool K3b::Device::Device::getSupportedWriteSpeedsViaGP( QList<int>& list, MediaType mediaType ) const
3283 {
3284     UByteArray data;
3285     if( getPerformance( data, 0x3, 0x0 ) && data.size() >= 8 ) {
3286         int numDesc = (data.size() - 8)/16;
3287         qDebug() << "(K3b::Device::Device) " << blockDeviceName()
3288                  << ":  Number of supported write speeds via GET PERFORMANCE: "
3289                  << numDesc << endl;
3290 
3291         for( int i = 0; i < numDesc; ++i ) {
3292             int s = from4Byte( &data[20+i*16] );
3293 
3294             // Looks as if the code below does not make sense with most drives
3295 //       if( !( data[4+i*16] & 0x2 ) ) {
3296 //  qDebug() << "(K3b::Device::Device) " << blockDeviceName()
3297 //         << " No write speed: " << s << " KB/s" << endl;
3298 //  continue;
3299 //       }
3300 
3301             if( isDvdMedia( mediaType ) && s < 1352 ) {
3302                 //
3303                 // Does this ever happen?
3304                 //
3305                 qDebug() << "(K3b::Device::Device) " << blockDeviceName()
3306                          << " Invalid DVD speed: " << s << " KB/s" << endl;
3307             }
3308             else {
3309                 qDebug() << "(K3b::Device::Device) " << blockDeviceName()
3310                          << " : " << s << " KB/s" << endl;
3311 
3312                 if( isDvdMedia( mediaType ) )
3313                     s = fixupDvdWritingSpeed( s );
3314 
3315                 QList<int>::iterator it = list.begin();
3316                 while( it != list.end() && *it < s )
3317                     ++it;
3318                 // the speed might already have been found in the 2a modepage
3319                 if( it == list.end() || *it != s )
3320                     list.insert( it, s );
3321             }
3322         }
3323     }
3324 
3325     return !list.isEmpty();
3326 }
3327 
3328 
getIndex(unsigned long lba) const3329 int K3b::Device::Device::getIndex( unsigned long lba ) const
3330 {
3331     // if the device is already opened we do not close it
3332     // to allow fast multiple method calls in a row
3333     bool needToClose = !isOpen();
3334 
3335     if( !open() )
3336         return -1;
3337 
3338     int ret = -1;
3339 
3340     //
3341     // first try readCd
3342     //
3343     unsigned char readData[16];
3344     ::memset( readData, 0, 16 );
3345 
3346     //
3347     // The index is found in the Mode-1 Q which occupies at least 9 out of 10 successive CD frames
3348     // It can be identified by ADR == 1
3349     //
3350     // So if the current sector does not provide Mode-1 Q subchannel we try the previous.
3351     //
3352 
3353     if( readCd( readData,
3354                 16,
3355                 1, // CD-DA
3356                 0, // no DAP
3357                 lba,
3358                 1,
3359                 false,
3360                 false,
3361                 false,
3362                 false,
3363                 false,
3364                 0,
3365                 2 // Q-Subchannel
3366             ) ) {
3367         // byte 0: 4 bits CONTROL (MSB) + 4 bits ADR (LSB)
3368         if( (readData[0]&0x0f) == 0x1 )
3369             ret = readData[2];
3370 
3371         // search previous sector for Mode1 Q Subchannel
3372         else if( readCd( readData,
3373                          16,
3374                          1, // CD-DA
3375                          0, // no DAP
3376                          lba-1,
3377                          1,
3378                          false,
3379                          false,
3380                          false,
3381                          false,
3382                          false,
3383                          0,
3384                          2 // Q-Subchannel
3385                      ) ) {
3386             if( (readData[0]&0x0f) == 0x1 )
3387                 ret = readData[2];
3388             else
3389                 ret = -2;
3390         }
3391     }
3392 
3393     else {
3394         qDebug() << "(K3b::Device::Device::getIndex) readCd failed. Trying seek.";
3395 
3396         UByteArray data;
3397         if( seek( lba ) && readSubChannel( data, 1, 0 ) ) {
3398             // byte 5: 4 bits ADR (MSB) + 4 bits CONTROL (LSB)
3399             if( data.size() > 7 && (data[5]>>4 & 0x0F) == 0x1 ) {
3400                 ret = data[7];
3401             }
3402             else if( seek( lba-1 ) && readSubChannel( data, 1, 0 ) ) {
3403                 if( data.size() > 7 && (data[5]>>4 & 0x0F) == 0x1 )
3404                     ret = data[7];
3405                 else
3406                     ret = -2;
3407             }
3408         }
3409         else
3410             qDebug() << "(K3b::Device::Device::getIndex) seek or readSubChannel failed.";
3411     }
3412 
3413     if( needToClose )
3414         close();
3415 
3416     return ret;
3417 }
3418 
3419 
searchIndex0(unsigned long startSec,unsigned long endSec,long & pregapStart) const3420 bool K3b::Device::Device::searchIndex0( unsigned long startSec,
3421                                       unsigned long endSec,
3422                                       long& pregapStart ) const
3423 {
3424     // if the device is already opened we do not close it
3425     // to allow fast multiple method calls in a row
3426     bool needToClose = !isOpen();
3427 
3428     if( !open() )
3429         return false;
3430 
3431     bool ret = false;
3432 
3433     int lastIndex = getIndex( endSec );
3434     if( lastIndex == 0 ) {
3435         // there is a pregap
3436         // let's find the position where the index turns to 0
3437         // we jump in 1 sec steps backwards until we find an index > 0
3438         unsigned long sector = endSec;
3439         while( lastIndex == 0 && sector > startSec ) {
3440             sector -= 75;
3441             if( sector < startSec )
3442                 sector = startSec;
3443             lastIndex = getIndex(sector);
3444         }
3445 
3446         if( lastIndex == 0 ) {
3447             qDebug() << "(K3b::Device::Device) warning: no index != 0 found.";
3448         }
3449         else {
3450             // search forward to the first index = 0
3451             while( getIndex( sector ) != 0 && sector < endSec )
3452                 sector++;
3453 
3454             pregapStart = sector;
3455             ret = true;
3456         }
3457     }
3458     else if( lastIndex > 0 ) {
3459         // no pregap
3460         pregapStart = -1;
3461         ret = true;
3462     }
3463 
3464     if( needToClose )
3465         close();
3466 
3467     return ret;
3468 }
3469 
3470 
indexScan(K3b::Device::Toc & toc) const3471 bool K3b::Device::Device::indexScan( K3b::Device::Toc& toc ) const
3472 {
3473     // if the device is already opened we do not close it
3474     // to allow fast multiple method calls in a row
3475     bool needToClose = !isOpen();
3476 
3477     if( !open() )
3478         return false;
3479 
3480     bool ret = true;
3481 
3482     for( Toc::iterator it = toc.begin(); it != toc.end(); ++it ) {
3483         Track& track = *it;
3484         if( track.type() == Track::TYPE_AUDIO ) {
3485             track.setIndices( QList<K3b::Msf>() );
3486             long index0 = -1;
3487             if( searchIndex0( track.firstSector().lba(), track.lastSector().lba(), index0 ) ) {
3488                 qDebug() << "(K3b::Device::Device) found index 0: " << index0;
3489             }
3490             if( index0 > 0 )
3491                 track.setIndex0( K3b::Msf( index0 - track.firstSector().lba() ) );
3492             else
3493                 track.setIndex0( 0 );
3494 
3495             if( index0 > 0 )
3496                 searchIndexTransitions( track.firstSector().lba(), index0-1, track );
3497             else
3498                 searchIndexTransitions( track.firstSector().lba(), track.lastSector().lba(), track );
3499         }
3500     }
3501 
3502     if( needToClose )
3503         close();
3504 
3505     return ret;
3506 }
3507 
3508 
searchIndexTransitions(long start,long end,K3b::Device::Track & track) const3509 void K3b::Device::Device::searchIndexTransitions( long start, long end, K3b::Device::Track& track ) const
3510 {
3511     qDebug() << "(K3b::Device::Device) searching for index transitions between "
3512              << start << " and " << end << endl;
3513     int startIndex = getIndex( start );
3514     int endIndex = getIndex( end );
3515 
3516     if( startIndex < 0 || endIndex < 0 ) {
3517         qDebug() << "(K3b::Device::Device) could not retrieve index values.";
3518     }
3519     else {
3520         qDebug() << "(K3b::Device::Device) indices: " << start << " - " << startIndex
3521                  << " and " << end << " - " << endIndex << endl;
3522 
3523         if( startIndex != endIndex ) {
3524             if( start+1 == end ) {
3525                 QList<K3b::Msf> indices = track.indices();
3526                 qDebug() << "(K3b::Device::Device) found index transition: " << endIndex << " " << end;
3527                 while ( indices.count() < endIndex )
3528                     indices.append( K3b::Msf() );
3529                 // we save the index relative to the first sector
3530                 if (endIndex > 0 && endIndex < indices.size() + 1)
3531                     indices[endIndex - 1] = K3b::Msf(end) - track.firstSector();
3532                 track.setIndices( indices ); // FIXME: better API
3533             }
3534             else {
3535                 searchIndexTransitions( start, start+(end-start)/2, track );
3536                 searchIndexTransitions( start+(end-start)/2, end, track );
3537             }
3538         }
3539     }
3540 }
3541 
3542 
copyrightProtectionSystemType() const3543 int K3b::Device::Device::copyrightProtectionSystemType() const
3544 {
3545     UByteArray dvdheader;
3546     if( readDvdStructure( dvdheader, 0x1 ) ) {
3547         int ret = -1;
3548         if( dvdheader.size() >= 6 )
3549             ret = dvdheader[4];
3550         return ret;
3551     }
3552     else
3553         return -1;
3554 }
3555 
3556 
getNextWritableAdress(unsigned int & lastSessionStart,unsigned int & nextWritableAdress) const3557 bool K3b::Device::Device::getNextWritableAdress( unsigned int& lastSessionStart, unsigned int& nextWritableAdress ) const
3558 {
3559     bool success = false;
3560 
3561     // FIXME: add CD media handling
3562     int m = mediaType();
3563     if( m & MEDIA_DVD_ALL ) {
3564         // DVD+RW always returns complete
3565         if( m & (K3b::Device::MEDIA_DVD_PLUS_RW|K3b::Device::MEDIA_DVD_RW_OVWR) )
3566             return false;
3567 
3568         UByteArray data;
3569 
3570         if( readDiscInformation( data ) ) {
3571             disc_info_t* inf = (disc_info_t*)data.data();
3572 
3573             //
3574             // The state of the last session has to be "empty" (0x0) or "incomplete" (0x1)
3575             // The procedure here is taken from the dvd+rw-tools
3576             //
3577             if( !(inf->border & 0x2) ) {
3578                 // the incomplete track number is the first track in the last session (the empty session)
3579                 int nextTrack;
3580                 if (m == MEDIA_BD_R_SRM_POW)
3581                     nextTrack = inf->last_track_l | inf->last_track_m << 8;
3582                 else
3583                     nextTrack  = inf->first_track_l | inf->first_track_m << 8;
3584 
3585                 UByteArray trackData;
3586 
3587                 // Read start address of the incomplete track
3588                 if( readTrackInformation( trackData, 0x1, nextTrack ) ) {
3589                     if (m == MEDIA_BD_R_SRM_POW && (trackData[7] & 1))
3590                         nextWritableAdress = from4Byte(&trackData[12]);
3591                     else
3592                         nextWritableAdress = from4Byte( &trackData[8] );
3593 
3594                     if (m == MEDIA_BD_R_SRM_POW) {
3595                         lastSessionStart = 0;
3596                         success = true;
3597                     } else {
3598                         // Read start address of the first track in the last session
3599                         if (readTocPmaAtip(trackData, 0x1, false, 0x0)) {
3600                             lastSessionStart = from4Byte(&trackData[8]);
3601                             success = true;
3602                         }
3603                     }
3604                 }
3605             }
3606         }
3607     }
3608 
3609     return success;
3610 }
3611 
3612 
nextWritableAddress() const3613 int K3b::Device::Device::nextWritableAddress() const
3614 {
3615     UByteArray data;
3616     int nwa = -1;
3617 
3618     if( readDiscInformation( data ) ) {
3619         disc_info_t* inf = (disc_info_t*)data.data();
3620 
3621         //
3622         // The state of the last session has to be "empty" (0x0) or "incomplete" (0x1)
3623         // The procedure here is taken from the dvd+rw-tools
3624         //
3625         if( !(inf->border & 0x2) ) {
3626             // the incomplete track number is the first track in the last session (the empty session)
3627             int nextTrack = inf->first_track_l|inf->first_track_m<<8;
3628 
3629             UByteArray trackData;
3630 
3631             // Read start address of the incomplete track
3632             if( readTrackInformation( trackData, 0x1, nextTrack ) ) {
3633                 nwa = from4Byte( &trackData[8] );
3634             }
3635 
3636             // Read start address of the invisible track
3637             else if ( readTrackInformation( trackData, 0x1, 0xff ) ) {
3638                 nwa = from4Byte( &trackData[8] );
3639             }
3640         }
3641     }
3642 
3643     return nwa;
3644 }
3645 
3646 
mediaId(int mediaType) const3647 QByteArray K3b::Device::Device::mediaId( int mediaType ) const
3648 {
3649     QString id;
3650 
3651     if( mediaType & MEDIA_CD_ALL ) {
3652         // FIXME:
3653     }
3654 
3655     else if( mediaType & MEDIA_DVD_MINUS_ALL ) {
3656         UByteArray data;
3657         if( readDvdStructure( data, 0x0E ) ) {
3658             if( data[4+16] == 3 && data[4+24] == 4 ) {
3659                 id = QString::asprintf( "%6.6s%-6.6s", data.data()+4+17, data.data()+4+25 );
3660             }
3661         }
3662     }
3663 
3664     else if( mediaType & MEDIA_DVD_PLUS_ALL ) {
3665         UByteArray data;
3666         if( readDvdStructure( data, 0x11 ) ||
3667             readDvdStructure( data, 0x0 ) ) {
3668             id = QString::asprintf( "%8.8s/%3.3s", data.data()+23, data.data()+31 );
3669         }
3670     }
3671 
3672     else if( mediaType & MEDIA_BD_ALL ) {
3673         UByteArray data;
3674         if( readDiscStructure( data, 1, 0 ) ) {
3675             if( data[4+0] == 'D' && data[4+1] == 'I' )
3676                 id = QString::asprintf ("%6.6s/%-3.3s", data.data()+4+100, data.data()+4+106 );
3677         }
3678     }
3679 
3680     return id.toLatin1();
3681 }
3682 
3683 
3684 // int K3b::Device::Device::ioctl( int request, ... ) const
3685 // {
3686 //     int r = -1;
3687 // #if defined(Q_OS_LINUX) || defined(Q_OS_NETBSD)
3688 //     d->mutex.lock();
3689 
3690 //     va_list ap;
3691 //     va_start( ap, request );
3692 //     r = ::ioctl( d->deviceFd, request, ap );
3693 //     va_end( ap );
3694 
3695 //     d->mutex.unlock();
3696 // #endif
3697 //     return r;
3698 // }
3699 
3700 
usageLock() const3701 void K3b::Device::Device::usageLock() const
3702 {
3703     d->mutex.lock();
3704 }
3705 
3706 
usageUnlock() const3707 void K3b::Device::Device::usageUnlock() const
3708 {
3709     d->mutex.unlock();
3710 }
3711