File indexing completed on 2024-04-14 04:44:44

0001 /*
0002     SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 /**
0006    This file contains all the MMC command implementations of the K3b device class
0007    to make the code more readable.
0008 **/
0009 
0010 
0011 #include "k3bdevice.h"
0012 #include "k3bscsicommand.h"
0013 #include "k3bdeviceglobals.h"
0014 #include "QDebug"
0015 
0016 #include <string.h>
0017 
0018 
0019 bool K3b::Device::Device::testUnitReady() const
0020 {
0021     ScsiCommand cmd( this );
0022     cmd.enableErrorMessages( false );
0023     cmd[0] = MMC_TEST_UNIT_READY;
0024     cmd[5] = 0; // Necessary to set the proper command length
0025     return( cmd.transport() == 0 );
0026 }
0027 
0028 
0029 bool K3b::Device::Device::getFeature( UByteArray& data, unsigned int feature ) const
0030 {
0031     unsigned char header[2048];
0032     ::memset( header, 0, 2048 );
0033 
0034     ScsiCommand cmd( this );
0035     cmd[0] = MMC_GET_CONFIGURATION;
0036     cmd[1] = 2;      // read only specified feature
0037     cmd[2] = feature>>8;
0038     cmd[3] = feature;
0039     cmd[8] = 8;      // we only read the data length first
0040     cmd[9] = 0;      // Necessary to set the proper command length
0041 
0042     // we only read the data length first
0043     unsigned int dataLen = 8;
0044     if( !cmd.transport( TR_DIR_READ, header, 8 ) )
0045         dataLen = from4Byte( header ) + 4;
0046     else
0047         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": GET CONFIGURATION length det failed.";
0048 
0049     //
0050     // Some buggy firmwares do not return the size of the available data
0051     // but the returned data or something invalid altogether.
0052     // So we simply use the maximum possible value to be on the safe side
0053     // with these buggy drives.
0054     // We cannot use this as default since many firmwares fail with a too high data length.
0055     //
0056     if( (dataLen-8) % 8 || dataLen <= 8 )
0057         dataLen = 0xFFFF;
0058 
0059     // again with real length
0060     data.resize( dataLen );
0061     ::memset( data.data(), 0, data.size() );
0062 
0063     cmd[7] = data.size() >> 8;
0064     cmd[8] = data.size();
0065     if( cmd.transport( TR_DIR_READ, data.data(), data.size() ) == 0 ) {
0066         data.resize( qMin( data.size(), (int)from4Byte( data.data() ) + 4 ) );
0067         return true;
0068     }
0069     else {
0070         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": GET CONFIGURATION with real length "
0071                  << data.size() << " failed." << Qt::endl;
0072         data.clear();
0073         return false;
0074     }
0075 }
0076 
0077 
0078 int K3b::Device::Device::featureCurrent( unsigned int feature ) const
0079 {
0080     UByteArray data;
0081     if( getFeature( data, feature ) ) {
0082         int ret = -1;
0083         if( data.size() >= 11 )
0084             ret = ( data[8+2]&1 ? 1 : 0 );  // check the current flag
0085 
0086         return ret;
0087     }
0088     else
0089         return -1;
0090 }
0091 
0092 
0093 bool K3b::Device::Device::readIsrc( unsigned int track, QByteArray& isrc ) const
0094 {
0095     UByteArray data;
0096 
0097     if( readSubChannel( data, 0x3, track ) ) {
0098         bool isrcValid = false;
0099 
0100         if( data.size() >= 8+18 ) {
0101             isrcValid = (data[8+4]>>7 & 0x1);
0102 
0103             if( isrcValid ) {
0104                 isrc = QByteArray( reinterpret_cast<char*>(data[8+5]), 13 );
0105 
0106                 // TODO: check the range of the chars
0107 
0108             }
0109         }
0110 
0111         return isrcValid;
0112     }
0113     else
0114         return false;
0115 }
0116 
0117 
0118 bool K3b::Device::Device::readMcn( QByteArray& mcn ) const
0119 {
0120     UByteArray data;
0121 
0122     if( readSubChannel( data, 0x2, 0 ) ) {
0123         bool mcnValid = false;
0124 
0125         if( data.size() >= 8+18 ) {
0126             mcnValid = (data[8+4]>>7 & 0x1);
0127 
0128             if( mcnValid )
0129                 mcn = QByteArray( reinterpret_cast<char*>(data[8+5]), 14 );
0130         }
0131 
0132         return mcnValid;
0133     }
0134     else
0135         return false;
0136 }
0137 
0138 
0139 bool K3b::Device::Device::getPerformance( UByteArray& data,
0140                                           unsigned int type,
0141                                           unsigned int dataType,
0142                                           unsigned int lba ) const
0143 {
0144     unsigned int descLen = 0;
0145     switch( type ) {
0146     case 0x0:
0147         descLen = 16;
0148         break;
0149     case 0x1:
0150         descLen = 8;
0151         break;
0152     case 0x2:
0153         descLen = 2048;
0154         break;
0155     case 0x3:
0156         descLen = 16;
0157         break;
0158     case 0x4:
0159         descLen = 8;
0160         break;
0161     case 0x5:
0162         descLen = 8; // FIXME: ??
0163         break;
0164     }
0165 
0166     unsigned int dataLen = descLen + 8;
0167     UByteArray header( dataLen );
0168     ::memset( header.data(), 0, dataLen );
0169 
0170     ScsiCommand cmd( this );
0171     cmd[0] = MMC_GET_PERFORMANCE;
0172     cmd[1] = dataType;
0173     cmd[2] = lba >> 24;
0174     cmd[3] = lba >> 16;
0175     cmd[4] = lba >> 8;
0176     cmd[5] = lba;
0177     cmd[9] = 1;      // first we read one descriptor
0178     cmd[10] = type;
0179     cmd[11] = 0;     // Necessary to set the proper command length
0180     if( cmd.transport( TR_DIR_READ, header.data(), dataLen ) ) {
0181         qDebug() << "(K3b::Device::Device) " << blockDeviceName()
0182                  << ": GET PERFORMANCE length det failed." << Qt::endl;
0183         return false;
0184     }
0185 
0186     dataLen = from4Byte( header.data() ) + 4;
0187 
0188     // At least one Panasonic drive returns gigantic changing numbers for the data length
0189     // which makes K3b crash below when *data cannot be allocated. That's why we cut the
0190     // length here.
0191     // FIXME: 2048 is a proper upper boundary for the write speed but not for all
0192     //        return types. "Defect Status Data" for example might return way more data.
0193     // FIXME: Since we only use getPerformance for writing speeds and without a proper length
0194     //        those do not make sense it is better to fail here anyway.
0195     if( descLen == 0 || (dataLen-8) % descLen || dataLen <= 8 || dataLen > 2048 ) {
0196         qDebug() << "(K3b::Device::Device) " << blockDeviceName()
0197                  << ": GET PERFORMANCE reports bogus dataLen: " << dataLen << Qt::endl;
0198         return false;
0199     }
0200 
0201     data.resize( dataLen );
0202     ::memset( data.data(), 0, data.size() );
0203 
0204     unsigned int numDesc = (dataLen-8)/descLen;
0205 
0206     cmd[8] = numDesc>>8;
0207     cmd[9] = numDesc;
0208     if( cmd.transport( TR_DIR_READ, data.data(), data.size() ) == 0 ) {
0209         data.resize( qMin( data.size(), (int)from4Byte( data.data() ) + 4 ) );
0210 
0211         if( data.size() > 8 ) {
0212             return true;
0213         }
0214         else {
0215             qDebug() << "(K3b::Device::Device) " << blockDeviceName()
0216                     << ": GET PERFORMANCE reports invalid data size:" << data.size() << Qt::endl;
0217             data.clear();
0218             return false;
0219         }
0220     }
0221     else {
0222         qDebug() << "(K3b::Device::Device) " << blockDeviceName()
0223                  << ": GET PERFORMANCE with real length "
0224                  << data.size() << " failed." << Qt::endl;
0225         data.clear();
0226         return false;
0227     }
0228 }
0229 
0230 
0231 bool K3b::Device::Device::setSpeed( unsigned int readingSpeed,
0232                                   unsigned int writingSpeed,
0233                                   bool cav ) const
0234 {
0235     ScsiCommand cmd( this );
0236     cmd[0] = MMC_SET_SPEED;
0237     cmd[1] = ( cav ? 0x1 : 0x0 );
0238     cmd[2] = readingSpeed >> 8;
0239     cmd[3] = readingSpeed;
0240     cmd[4] = writingSpeed >> 8;
0241     cmd[5] = writingSpeed;
0242     cmd[11] = 0;      // Necessary to set the proper command length
0243     return ( cmd.transport( TR_DIR_WRITE ) == 0 );
0244 }
0245 
0246 
0247 bool K3b::Device::Device::seek( unsigned long lba ) const
0248 {
0249     ScsiCommand cmd( this );
0250     cmd[0] = MMC_SEEK_10;
0251     cmd[2] = lba>>24;
0252     cmd[3] = lba>>16;
0253     cmd[4] = lba>>8;
0254     cmd[5] = lba;
0255     cmd[9] = 0;      // Necessary to set the proper command length
0256     return !cmd.transport();
0257 }
0258 
0259 
0260 bool K3b::Device::Device::readTrackInformation( UByteArray& data, int type, int value ) const
0261 {
0262     unsigned char header[2048];
0263     ::memset( header, 0, 2048 );
0264 
0265     ScsiCommand cmd( this );
0266     cmd[0] = MMC_READ_TRACK_INFORMATION;
0267     cmd[9] = 0;      // Necessary to set the proper command length
0268 
0269     switch( type ) {
0270     case 0:
0271     case 1:
0272     case 2:
0273         cmd[1] = type & 0x3;
0274         cmd[2] = value>>24;
0275         cmd[3] = value>>16;
0276         cmd[4] = value>>8;
0277         cmd[5] = value;
0278         break;
0279     default:
0280         qDebug() << "(K3b::Device::readTrackInformation) wrong type parameter: " << type;
0281         return false;
0282     }
0283 
0284     // first we read the header
0285     unsigned int dataLen = 4;
0286     cmd[8] = 4;
0287     if( cmd.transport( TR_DIR_READ, header, 4 ) == 0 )
0288         dataLen = from2Byte( header ) + 2;
0289     else
0290         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": READ TRACK INFORMATION length det failed.";
0291 
0292     //
0293     // Some buggy firmwares do not return the size of the available data
0294     // but the returned data.
0295     // So we try to determine the correct size based on the medium type
0296     // DVD+R:  40 (MMC4)
0297     // DVD-DL: 48 (MMC5)
0298     // CD:     36 (MMC2)
0299     //
0300     if( dataLen <= 6 ) {
0301         int m = mediaType();
0302         if( m & (MEDIA_DVD_R_DL|MEDIA_DVD_R_DL_SEQ|MEDIA_DVD_R_DL_JUMP) )
0303             dataLen = 48;
0304         else if( m & (MEDIA_DVD_PLUS_R|MEDIA_DVD_PLUS_R_DL) )
0305             dataLen = 40;
0306         else
0307             dataLen = 36;
0308     }
0309 
0310     // again with real length
0311     data.resize( dataLen );
0312     ::memset( data.data(), 0, data.size() );
0313 
0314     cmd[7] = data.size() >> 8;
0315     cmd[8] = data.size();
0316     if( cmd.transport( TR_DIR_READ, data.data(), data.size() ) == 0 ) {
0317         data.resize( qMin( data.size(), from2Byte( data.data() ) + 2 ) );
0318         return true;
0319     }
0320     else {
0321         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": READ TRACK INFORMATION with real length "
0322                  << data.size() << " failed." << Qt::endl;
0323         data.clear();
0324         return false;
0325     }
0326 }
0327 
0328 
0329 
0330 bool K3b::Device::Device::read10( unsigned char* data,
0331                                 unsigned int dataLen,
0332                                 unsigned long startAdress,
0333                                 unsigned int length,
0334                                 bool fua ) const
0335 {
0336     ::memset( data, 0, dataLen );
0337 
0338     ScsiCommand cmd( this );
0339     cmd[0] = MMC_READ_10;
0340     cmd[1] = ( fua ? 0x8 : 0x0 );
0341     cmd[2] = startAdress>>24;
0342     cmd[3] = startAdress>>16;
0343     cmd[4] = startAdress>>8;
0344     cmd[5] = startAdress;
0345     cmd[7] = length>>8;
0346     cmd[8] = length;
0347     cmd[9] = 0;      // Necessary to set the proper command length
0348 
0349     if( cmd.transport( TR_DIR_READ, data, dataLen ) ) {
0350         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": READ 10 failed!";
0351         return false;
0352     }
0353     else
0354         return true;
0355 }
0356 
0357 
0358 bool K3b::Device::Device::read12( unsigned char* data,
0359                                 unsigned int dataLen,
0360                                 unsigned long startAdress,
0361                                 unsigned long length,
0362                                 bool streaming,
0363                                 bool fua ) const
0364 {
0365     ::memset( data, 0, dataLen );
0366 
0367     ScsiCommand cmd( this );
0368     cmd[0] = MMC_READ_12;
0369     cmd[1] = ( fua ? 0x8 : 0x0 );
0370     cmd[2] = startAdress>>24;
0371     cmd[3] = startAdress>>16;
0372     cmd[4] = startAdress>>8;
0373     cmd[5] = startAdress;
0374     cmd[6] = length>>24;
0375     cmd[7] = length>>16;
0376     cmd[8] = length>>8;
0377     cmd[9] = length;
0378     cmd[10] = (streaming ? 0x80 : 0 );
0379     cmd[11] = 0;      // Necessary to set the proper command length
0380 
0381     if( cmd.transport( TR_DIR_READ, data, dataLen ) ) {
0382         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": READ 12 failed!";
0383         return false;
0384     }
0385     else
0386         return true;
0387 }
0388 
0389 
0390 bool K3b::Device::Device::readCd( unsigned char* data,
0391                                 unsigned int dataLen,
0392                                 int sectorType,
0393                                 bool dap,
0394                                 unsigned long startAdress,
0395                                 unsigned long length,
0396                                 bool sync,
0397                                 bool header,
0398                                 bool subHeader,
0399                                 bool userData,
0400                                 bool edcEcc,
0401                                 int c2,
0402                                 int subChannel ) const
0403 {
0404     ::memset( data, 0, dataLen );
0405 
0406     ScsiCommand cmd( this );
0407     cmd[0] = MMC_READ_CD;
0408     cmd[1] = (sectorType<<2 & 0x1c) | ( dap ? 0x2 : 0x0 );
0409     cmd[2] = startAdress>>24;
0410     cmd[3] = startAdress>>16;
0411     cmd[4] = startAdress>>8;
0412     cmd[5] = startAdress;
0413     cmd[6] = length>>16;
0414     cmd[7] = length>>8;
0415     cmd[8] = length;
0416     cmd[9] = ( ( sync      ? 0x80 : 0x0 ) |
0417                ( subHeader ? 0x40 : 0x0 ) |
0418                ( header    ? 0x20 : 0x0 ) |
0419                ( userData  ? 0x10 : 0x0 ) |
0420                ( edcEcc    ? 0x8  : 0x0 ) |
0421                ( c2<<1 & 0x6 ) );
0422     cmd[10] = subChannel & 0x7;
0423     cmd[11] = 0;      // Necessary to set the proper command length
0424 
0425     if( cmd.transport( TR_DIR_READ, data, dataLen ) ) {
0426         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": READ CD failed!";
0427         return false;
0428     }
0429     else {
0430         return true;
0431     }
0432 }
0433 
0434 
0435 bool K3b::Device::Device::readCdMsf( unsigned char* data,
0436                                    unsigned int dataLen,
0437                                    int sectorType,
0438                                    bool dap,
0439                                    const K3b::Msf& startAdress,
0440                                    const K3b::Msf& endAdress,
0441                                    bool sync,
0442                                    bool header,
0443                                    bool subHeader,
0444                                    bool userData,
0445                                    bool edcEcc,
0446                                    int c2,
0447                                    int subChannel ) const
0448 {
0449     ::memset( data, 0, dataLen );
0450 
0451     ScsiCommand cmd( this );
0452     cmd[0] = MMC_READ_CD_MSF;
0453     cmd[1] = (sectorType<<2 & 0x1c) | ( dap ? 0x2 : 0x0 );
0454     cmd[3] = (startAdress+150).minutes();
0455     cmd[4] = (startAdress+150).seconds();
0456     cmd[5] = (startAdress+150).frames();
0457     cmd[6] = (endAdress+150).minutes();
0458     cmd[7] = (endAdress+150).seconds();
0459     cmd[8] = (endAdress+150).frames();
0460     cmd[9] = ( ( sync      ? 0x80 : 0x0 ) |
0461                ( subHeader ? 0x40 : 0x0 ) |
0462                ( header    ? 0x20 : 0x0 ) |
0463                ( userData  ? 0x10 : 0x0 ) |
0464                ( edcEcc    ? 0x8  : 0x0 ) |
0465                ( c2<<1 & 0x6 ) );
0466     cmd[10] = subChannel & 0x7;
0467     cmd[11] = 0;      // Necessary to set the proper command length
0468 
0469     if( cmd.transport( TR_DIR_READ, data, dataLen ) ) {
0470         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": READ CD MSF failed!";
0471         return false;
0472     }
0473     else
0474         return true;
0475 }
0476 
0477 
0478 bool K3b::Device::Device::readSubChannel( UByteArray& data,
0479                                         unsigned int subchannelParam,
0480                                         unsigned int trackNumber ) const
0481 {
0482     unsigned char header[2048];
0483     ::memset( header, 0, 2048 );
0484 
0485     ScsiCommand cmd( this );
0486     cmd[0] = MMC_READ_SUB_CHANNEL;
0487     cmd[2] = 0x40;    // SUBQ
0488     cmd[3] = subchannelParam;
0489     cmd[6] = trackNumber;   // only used when subchannelParam == 03h (ISRC)
0490     cmd[8] = 4;
0491     cmd[9] = 0;      // Necessary to set the proper command length
0492 
0493     // first we read the header
0494     unsigned int dataLen = 4;
0495     if( cmd.transport( TR_DIR_READ, header, 4 ) == 0 )
0496         dataLen = from2Byte( &header[2] ) + 4;
0497     else
0498         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": READ SUB-CHANNEL length det failed.";
0499 
0500     //
0501     // Some buggy firmwares do not return the size of the available data
0502     // but the returned data. So we simply use the maximum possible value to be on the safe side
0503     // with these buggy drives.
0504     // We cannot use this as default since many firmwares fail with a too high data length.
0505     //
0506     if( dataLen <= 4 )
0507         dataLen = 0xFFFF;
0508 
0509     // again with real length
0510     data.resize( dataLen );
0511     ::memset( data.data(), 0, data.size() );
0512 
0513     cmd[7] = data.size() >> 8;
0514     cmd[8] = data.size();
0515     if( cmd.transport( TR_DIR_READ, data.data(), data.size() ) == 0 ) {
0516         data.resize( qMin( data.size(), from2Byte( &data[2] ) + 4 ) );
0517         return true;
0518     }
0519     else {
0520         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": READ SUB-CHANNEL with real length "
0521                  << data.size() << " failed." << Qt::endl;
0522         data.clear();
0523         return false;
0524     }
0525 }
0526 
0527 
0528 bool K3b::Device::Device::readTocPmaAtip( UByteArray& data, int format, bool time, int track ) const
0529 {
0530     unsigned int descLen = 0;
0531 
0532     switch( format ) {
0533     case 0x0:
0534         descLen = 8;
0535         break;
0536     case 0x1:
0537         descLen = 8;
0538         break;
0539     case 0x2:
0540         descLen = 11;
0541         break;
0542     case 0x3:
0543         descLen = 11;
0544         break;
0545     case 0x4:
0546         descLen = 4; // MMC2: 24 and MMC4: 28, so we use the highest common factor
0547         break;
0548     case 0x5:
0549         descLen = 18;
0550         break;
0551     }
0552 
0553     unsigned char header[2048];
0554     ::memset( header, 0, 2048 );
0555 
0556     ScsiCommand cmd( this );
0557     cmd[0] = MMC_READ_TOC_PMA_ATIP;
0558     cmd[1] = ( time ? 0x2 : 0x0 );
0559     cmd[2] = format & 0x0F;
0560     cmd[6] = track;
0561     cmd[8] = 4;
0562     cmd[9] = 0;      // Necessary to set the proper command length
0563 
0564     // we only read the header
0565     unsigned int dataLen = 4;
0566     if( cmd.transport( TR_DIR_READ, header, 4 ) == 0 )
0567         dataLen = from2Byte( header ) + 2;
0568     else
0569         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": READ TOC/PMA/ATIP length det failed.";
0570 
0571     //
0572     // Some buggy firmwares return an invalid size here
0573     // So we simply use the maximum possible value to be on the safe side
0574     // with these buggy drives.
0575     // We cannot use this as default since many firmwares fail with a too high data length.
0576     //
0577     if( descLen != 0 && ((dataLen-4) % descLen || dataLen < 4+descLen) ) {
0578         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": READ TOC/PMA/ATIP invalid length returned: " << dataLen;
0579         dataLen = 0xFFFF;
0580     }
0581 
0582     //
0583     // Not all drives like uneven numbers
0584     //
0585     if( dataLen%2 )
0586         ++dataLen;
0587 
0588     // again with real length
0589     data.resize( dataLen );
0590     ::memset( data.data(), 0, data.size() );
0591 
0592     cmd[7] = data.size() >> 8;
0593     cmd[8] = data.size();
0594     if( cmd.transport( TR_DIR_READ, data.data(), data.size() ) == 0 ) {
0595         dataLen = qMin( dataLen, from2Byte( data.data() ) + 2u );
0596         if( descLen == 0 || (dataLen-4) % descLen || dataLen < 4+descLen ) {
0597             // useless length
0598             data.clear();
0599             return false;
0600         }
0601         else {
0602             data.resize( dataLen );
0603             return true;
0604         }
0605     }
0606     else {
0607         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": READ TOC/PMA/ATIP format "
0608                  << format << " with real length "
0609                  << data.size() << " failed." << Qt::endl;
0610         data.clear();
0611         return false;
0612     }
0613 }
0614 
0615 
0616 bool K3b::Device::Device::mechanismStatus( UByteArray& data ) const
0617 {
0618     unsigned char header[2048];
0619     ::memset( header, 0, 2048 );
0620 
0621     ScsiCommand cmd( this );
0622     cmd[0] = MMC_MECHANISM_STATUS;
0623     cmd[9] = 8;
0624     cmd[11] = 0;    // Necessary to set the proper command length
0625 
0626     // first we read the header
0627     unsigned int dataLen = 8;
0628     if( cmd.transport( TR_DIR_READ, header, 8 ) == 0 )
0629         dataLen = from4Byte( &header[6] ) + 8;
0630     else
0631         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": MECHANISM STATUS length det failed.";
0632 
0633     //
0634     // Some buggy firmwares do not return the size of the available data
0635     // but the returned data or something invalid altogether.
0636     // So we simply use the maximum possible value to be on the safe side
0637     // with these buggy drives.
0638     // We cannot use this as default since many firmwares fail with a too high data length.
0639     //
0640     if( (dataLen-8) % 4 || dataLen <= 8 )
0641         dataLen = 0xFFFF;
0642 
0643     qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": MECHANISM STATUS "
0644              << (int)header[5] << " slots." << Qt::endl;
0645 
0646     // again with real length
0647     data.resize( dataLen );
0648     ::memset( data.data(), 0, data.size() );
0649 
0650     cmd[8] = data.size() >> 8;
0651     cmd[9] = data.size();
0652     if( cmd.transport( TR_DIR_READ, data.data(), data.size() ) == 0 ) {
0653         data.resize( qMin( data.size(), (int)from4Byte( &data[6] ) + 8 ) );
0654         return true;
0655     }
0656     else {
0657         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": MECHANISM STATUS with real length "
0658                  << data.size() << " failed." << Qt::endl;
0659         data.clear();
0660         return false;
0661     }
0662 }
0663 
0664 
0665 
0666 bool K3b::Device::Device::modeSense(UByteArray& pageData, int page) const
0667 {
0668     unsigned char header[2048];
0669     ::memset(header, 0, sizeof(header));
0670 
0671     ScsiCommand cmd(this);
0672     cmd[0] = MMC_MODE_SENSE;
0673     cmd[1] = 0x8;         // Disable Block Descriptors
0674     cmd[2] = page & 0x3F;
0675     cmd[8] = 8;
0676     cmd[9] = 0;           // Necessary to set the proper command length
0677 
0678     // first we determine the data length
0679     int replyLen = 8;
0680     if (cmd.transport(TR_DIR_READ, header, 8) == 0)
0681         replyLen = from2Byte(header) + 2;
0682     else {
0683         qDebug() << "(K3b::Device::Device) " << blockDeviceName() <<
0684             ": MODE SENSE length det failed.";
0685     }
0686     // FIXME: rumor or misnomer?
0687     // Some buggy firmwares do not return the size of the available data
0688     // but the returned data. So we simply use the maximum possible value to be
0689     // on the safe side with these buggy drives.
0690     // We cannot use this as default since many firmwares fail with a too high
0691     // data length.
0692     if (replyLen == 8)
0693         replyLen = 0xFFFF;
0694 
0695     // again with real length
0696     pageData.resize(replyLen);
0697     ::memset(pageData.data(), 0, pageData.size());
0698 
0699     cmd[7] = pageData.size() >> 8;
0700     cmd[8] = pageData.size();
0701     if (cmd.transport(TR_DIR_READ, pageData.data(), pageData.size()) == 0 ) {
0702         pageData.resize(qMin(pageData.size(), from2Byte(pageData.data()) + 2));
0703         return true;
0704     } else {
0705         pageData.clear();
0706         qDebug() << "(K3b::Device::Device) " << blockDeviceName() <<
0707             ": MODE SENSE with real length " << replyLen << " failed." << Qt::endl;
0708         return false;
0709     }
0710 }
0711 
0712 
0713 bool K3b::Device::Device::modeSelect( UByteArray& pageData, bool pf, bool sp ) const
0714 {
0715     pageData[0] = 0;
0716     pageData[1] = 0;
0717     pageData[4] = 0;
0718     pageData[5] = 0;
0719 
0720     // we do not support Block Descriptors here
0721     pageData[6] = 0;
0722     pageData[7] = 0;
0723 
0724     // PS bit reserved
0725     pageData[8] &= 0x3F;
0726 
0727     ScsiCommand cmd( this );
0728     cmd[0] = MMC_MODE_SELECT;
0729     cmd[1] = ( sp ? 1 : 0 ) | ( pf ? 0x10 : 0 );
0730     cmd[7] = pageData.size()>>8;
0731     cmd[8] = pageData.size();
0732     cmd[9] = 0;
0733     return( cmd.transport( TR_DIR_WRITE, pageData.data(), pageData.size() ) == 0 );
0734 }
0735 
0736 
0737 // does only make sense for complete media
0738 bool K3b::Device::Device::readCapacity( K3b::Msf& r ) const
0739 {
0740     ScsiCommand cmd( this );
0741     cmd[0] = MMC_READ_CAPACITY;
0742     cmd[9] = 0;      // Necessary to set the proper command length
0743     unsigned char buf[8];
0744     ::memset( buf, 0, 8 );
0745     if( cmd.transport( TR_DIR_READ, buf, 8 ) == 0 ) {
0746         r = from4Byte( buf );
0747         return true;
0748     }
0749     else
0750         return false;
0751 }
0752 
0753 
0754 bool K3b::Device::Device::readFormatCapacity( int wantedFormat, K3b::Msf& r,
0755                                               K3b::Msf* currentMax, int* currentMaxFormat ) const
0756 {
0757     bool success = false;
0758 
0759     // the maximal length as stated in MMC4
0760     static const unsigned int maxLen = 4 + (8*32);
0761 
0762     unsigned char buffer[maxLen];
0763     ::memset( buffer, 0, maxLen );
0764 
0765     ScsiCommand cmd( this );
0766     cmd[0] = MMC_READ_FORMAT_CAPACITIES;
0767     cmd[7] = maxLen >> 8;
0768     cmd[8] = maxLen & 0xFF;
0769     cmd[9] = 0;      // Necessary to set the proper command length
0770     if( cmd.transport( TR_DIR_READ, buffer, maxLen ) == 0 ) {
0771 
0772         unsigned int realLength = buffer[3] + 4;
0773 
0774         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " READ FORMAT CAPACITY: Current/Max "
0775                  << (int)(buffer[8]&0x3) << " " << from4Byte( &buffer[4] ) << Qt::endl;
0776 
0777         if( currentMax )
0778             *currentMax = from4Byte( &buffer[4] );
0779         if( currentMaxFormat )
0780             *currentMaxFormat = (int)(buffer[8]&0x3);
0781 
0782         //
0783         // Descriptor Type:
0784         // 0 - reserved
0785         // 1 - unformatted :)
0786         // 2 - formatted. Here we get the used capacity (lead-in to last lead-out/border-out)
0787         // 3 - No media present
0788         //
0789         for( unsigned int i = 12; i < realLength-4; i+=8 ) {
0790             int format = (int)((buffer[i+4]>>2)&0x3f);
0791             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << " READ FORMAT CAPACITY: "
0792                      << format << " " << from4Byte( &buffer[i] )
0793                      << " " << (int)( (buffer[i+5] << 16 & 0xFF0000) |
0794                                       (buffer[i+6] << 8  & 0xFF00) |
0795                                       (buffer[i+7]       & 0xFF) ) << Qt::endl;
0796 
0797             if( format == wantedFormat ) {
0798                 // found the descriptor
0799                 r = qMax( (int)from4Byte( &buffer[i] ), r.lba() );
0800                 success = true;
0801             }
0802         }
0803     }
0804 
0805     return success;
0806 }
0807 
0808 
0809 bool K3b::Device::Device::readDiscInformation( UByteArray& data ) const
0810 {
0811     unsigned char header[2];
0812     ::memset( header, 0, 2 );
0813 
0814     ScsiCommand cmd( this );
0815     cmd[0] = MMC_READ_DISC_INFORMATION;
0816     cmd[8] = 2;
0817     cmd[9] = 0;      // Necessary to set the proper command length
0818 
0819     unsigned int dataLen = 0;
0820     if( cmd.transport( TR_DIR_READ, header, 2 ) == 0 )
0821         dataLen = from2Byte( header ) + 2u;
0822     else
0823         qDebug() << "(K3b::Device::Device) " << blockDeviceName()
0824                  << ": READ DISC INFORMATION length det failed" << Qt::endl;
0825 
0826     if( dataLen < 32 ) {
0827         qDebug() << "(K3b::Device::Device) " << blockDeviceName()
0828                  << ": Device reports bogus disc information length of " << dataLen << Qt::endl;
0829         dataLen = 32;
0830     }
0831 
0832     data.resize( dataLen );
0833     ::memset( data.data(), 0, data.size() );
0834 
0835     cmd[7] = data.size() >> 8;
0836     cmd[8] = data.size();
0837     if( cmd.transport( TR_DIR_READ, data.data(), data.size() ) == 0 ) {
0838         data.resize( qMin( data.size(), from2Byte( data.data() ) + 2 ) );
0839         return true;
0840     }
0841     else {
0842         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": READ DISC INFORMATION with real length "
0843                  << dataLen << " failed." << Qt::endl;
0844         data.clear();
0845         return false;
0846     }
0847 }
0848 
0849 
0850 bool K3b::Device::Device::readDvdStructure( UByteArray&  data,
0851                                           unsigned int format,
0852                                           unsigned int layer,
0853                                           unsigned long address,
0854                                           unsigned int agid ) const
0855 {
0856     return readDiscStructure( data, 0x0, format, layer, address, agid );
0857 }
0858 
0859 
0860 bool K3b::Device::Device::readDiscStructure( UByteArray& data,
0861                                            unsigned int mediaType,
0862                                            unsigned int format,
0863                                            unsigned int layer,
0864                                            unsigned long address,
0865                                            unsigned int agid ) const
0866 {
0867     unsigned char header[4];
0868     ::memset( header, 0, 4 );
0869 
0870     ScsiCommand cmd( this );
0871     cmd[0] = MMC_READ_DVD_STRUCTURE;
0872     cmd[1] = mediaType & 0xF;
0873     cmd[2] = address>>24;
0874     cmd[3] = address>>16;
0875     cmd[4] = address>>8;
0876     cmd[5] = address;
0877     cmd[6] = layer;
0878     cmd[7] = format;
0879     cmd[10] = (agid<<6);
0880     cmd[11] = 0;      // Necessary to set the proper command length
0881 
0882     cmd[9] = 4;
0883     if( cmd.transport( TR_DIR_READ, header, 4 ) == 0 ) {
0884         // again with real length
0885         unsigned int dataLen = from2Byte( header ) + 2;
0886 
0887         data.resize( dataLen );
0888         ::memset( data.data(), 0, data.size() );
0889 
0890         cmd[8] = data.size() >> 8;
0891         cmd[9] = data.size();
0892         if( cmd.transport( TR_DIR_READ, data.data(), data.size() ) == 0 ) {
0893             data.resize( qMin( data.size(), from2Byte( data.data() ) + 2 ) );
0894             return true;
0895         }
0896         else {
0897             qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": READ DVD STRUCTURE with real length failed.";
0898             data.clear();
0899             return false;
0900         }
0901     }
0902     else {
0903         qDebug() << "(K3b::Device::Device) " << blockDeviceName() << ": READ DVD STRUCTURE length det failed";
0904         return false;
0905     }
0906 }
0907 
0908 
0909 int K3b::Device::Device::readBufferCapacity( long long& bufferLength, long long& bufferAvail ) const
0910 {
0911     unsigned char data[12];
0912     ::memset( data, 0, 12 );
0913 
0914     ScsiCommand cmd( this );
0915     cmd[0] = MMC_READ_BUFFER_CAPACITY;
0916     cmd[8] = 12;
0917     cmd[9] = 0;      // Necessary to set the proper command length
0918     int r = cmd.transport( TR_DIR_READ, data, 12 );
0919     if( r )
0920         return r;
0921 
0922     unsigned int dataLength = from2Byte( data );
0923 
0924     if( dataLength >= 10 ) {
0925         bufferLength = from4Byte( &data[4] );
0926         bufferAvail = from4Byte( &data[8] );
0927     }
0928     else {
0929         bufferAvail = bufferLength = 0;
0930     }
0931 
0932     return 0;
0933 }