--- src/core/device/k3bdevice.cpp.orig Thu Oct 30 11:53:35 2003 +++ src/core/device/k3bdevice.cpp Sat Nov 8 12:15:01 2003 @@ -32,7 +32,9 @@ #include #include +#ifndef __FreeBSD__ #include +#endif #include #include #include @@ -40,6 +42,7 @@ #include #include +#ifndef __FreeBSD__ #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,70) typedef unsigned char u8; @@ -48,6 +51,18 @@ #include #define __STRICT_ANSI__ #include +#else +#include +#include +#include +#define __BYTE_ORDER BYTE_ORDER +#define __BIG_ENDIAN BIG_ENDIAN +//#define CDROMEJECT CDIOCEJECT +//#define CDROMCLOSETRAY CDIOCCLOSE +#define CD_FRAMESIZE_RAW 2352 +#include +int bsd_open_close_device(int bus, int target, int lun, bool eject); +#endif @@ -167,6 +182,7 @@ { kdDebug() << "(K3bCdDevice) " << blockDeviceName() << ": init()" << endl; +#ifndef __FreeBSD__ if(open() < 0) return false; @@ -175,10 +191,18 @@ // we also query the mode page 2A and use the cdrom.h stuff to get as much information as possible // + // On BSD the device capabilities are already set by the devicemanager. So this code may + // find more capabilities -- if it works d->deviceType = 0; +#endif d->supportedProfiles = 0; +#ifndef __FreeBSD__ ScsiCommand cmd( open() ); +#else + ScsiCommand cmd(m_passDevice); + d->deviceType |= CDROM; +#endif unsigned char header[8]; ::memset( header, 0, 8 ); cmd[0] = 0x46; // GET CONFIGURATION @@ -580,8 +604,16 @@ int mm_cap_len = 0; if( modeSense( &mm_cap_buffer, mm_cap_len, 0x2A ) ) { mm_cap_page_2A* mm_p = (mm_cap_page_2A*)(mm_cap_buffer+8); - if( mm_p->BUF ) d->burnfree = true; - if( mm_p->cd_rw_write ) d->deviceType |= CDRW; + if( mm_p->BUF ) + { + kdDebug() << "(K3bCdDevice) ModeSense: burnfree." << endl; + d->burnfree = true; + } + if( mm_p->cd_rw_write ) + { + kdDebug() << "(K3bCdDevice) ModeSense: CDRW." << endl; + d->deviceType |= CDRW; + } m_maxWriteSpeed = (int)( from2Byte(mm_p->max_write_speed) * 1024.0 / ( 2352.0 * 75.0 ) ); m_maxReadSpeed = (int)( from2Byte(mm_p->max_read_speed) * 1024.0 / ( 2352.0 * 75.0 ) ); @@ -592,6 +624,7 @@ } +#ifndef __FreeBSD__ // // This is the backup if the drive does not support the GET CONFIGURATION command @@ -619,6 +652,7 @@ if (drivetype & CDC_DVD) d->deviceType |= DVD; +#endif if( writesCd() ) checkWriteModes(); @@ -642,10 +676,11 @@ m_version = QString::fromLocal8Bit( (char*)(inq+32), 4 ).stripWhiteSpace(); } +#ifndef __FreeBSD__ close(); +#endif d->interfaceType = interfaceType(); - return furtherInit(); } @@ -649,6 +684,23 @@ return furtherInit(); } +void K3bCdDevice::CdDevice::guessProfiles() +{ + if (!d->supportedProfiles) + { + kdDebug() << "(K3bCdDevice): no profiles found; setting them from device type = " << d->deviceType << endl; + if (d->deviceType & CDROM) d->supportedProfiles |= MEDIA_CD_ROM; + if (d->deviceType & CDR) d->supportedProfiles |= MEDIA_CD_R; + if (d->deviceType & CDRW) d->supportedProfiles |= MEDIA_CD_RW; + if (d->deviceType & DVDR) d->supportedProfiles |= MEDIA_DVD_R_SEQ; + if (d->deviceType & DVDRAM) d->supportedProfiles |= MEDIA_DVD_RAM; + if (d->deviceType & DVD) d->supportedProfiles |= MEDIA_DVD_ROM; + if (d->deviceType & DVDRW) d->supportedProfiles |= MEDIA_DVD_RW_OVWR | MEDIA_DVD_RW_SEQ;// ??? + if (d->deviceType & DVDPR) d->supportedProfiles |= MEDIA_DVD_PLUS_R; + if (d->deviceType & DVDPRW) d->supportedProfiles |= MEDIA_DVD_PLUS_RW; + } +// case 0x11: d->supportedProfiles |= MEDIA_DVD_R_SEQ; +} bool K3bCdDevice::CdDevice::furtherInit() { @@ -658,6 +710,7 @@ K3bCdDevice::CdDevice::interface K3bCdDevice::CdDevice::interfaceType() { +#ifndef __FreeBSD__ if (d->interfaceType == OTHER) { // if the device is already opened we do not close it @@ -680,6 +733,9 @@ if( needToClose ) close(); } +#else + d->interfaceType = SCSI; +#endif return d->interfaceType; } @@ -826,7 +882,11 @@ unsigned char dvdheader[20]; ::memset( dvdheader, 0, 20 ); +#ifndef __FreeBSD__ ScsiCommand cmd( open() ); +#else + ScsiCommand cmd(m_passDevice); +#endif cmd[0] = 0xad; // GPCMD_READ_DVD_STRUCTURE; cmd[9] = 20; if( cmd.transport( TR_DIR_READ, dvdheader, 20 ) ) { @@ -846,6 +906,7 @@ int K3bCdDevice::CdDevice::isReady() const { +#ifndef __FreeBSD__ // if the device is already opened we do not close it // to allow fast multible method calls in a row bool needToClose = !isOpen(); @@ -905,6 +966,10 @@ } else return 2; +#else + ((CdDevice *)this)->refreshDeviceData(); + return m_driveReady; +#endif } @@ -941,6 +1006,7 @@ delete [] data; } else { +#ifndef __FreeBSD__ kdDebug() << "(K3bCdDevice::CdDevice) " << blockDeviceName() << ": READ DISC INFORMATION failed. falling back to cdrom.h" << endl; int drive_status = ::ioctl(d->deviceFd,CDROM_DRIVE_STATUS); @@ -953,6 +1019,10 @@ kdDebug() << "(K3bCdDevice::CdDevice) " << blockDeviceName() << ": No disk in drive" << endl; ret = NO_DISK; } +#else + ((CdDevice *)this)->refreshDeviceData(); + ret = m_deviceStatus; +#endif } if( needToClose ) @@ -1013,7 +1083,11 @@ unsigned char header[2]; ::memset( header, 0, 2 ); +#ifndef __FreeBSD__ ScsiCommand cmd( open() ); +#else + ScsiCommand cmd(m_passDevice); +#endif cmd[0] = 0x51; // READ DISC INFORMATION cmd[8] = 2; @@ -1199,6 +1273,7 @@ bool readSuccess = true; if( !readSectorsRaw( data, lba, 1 ) ) { +#ifndef __FreeBSD__ kdDebug() << "(K3bCdDevice::CdDevice) " << blockDeviceName() << ": MMC RAW READ failed. falling back to cdrom.h." << endl; @@ -1209,8 +1284,11 @@ if( ::ioctl(d->deviceFd,CDROMREADRAW,data) == -1 ) { kdDebug() << "(K3bCdDevice::CdDevice) " << blockDeviceName() << ": could not get track header, (lba " << lba << ") ! " << strerror(errno) << endl; +#endif readSuccess = false; +#ifndef __FreeBSD__ } +#endif } if( readSuccess ) { @@ -1556,7 +1634,7 @@ bool success = true; toc.clear(); - +#ifndef __FreeBSD__ struct cdrom_tochdr tochdr; struct cdrom_tocentry tocentry; @@ -1642,6 +1720,10 @@ else success = false; +#else + ((CdDevice *)this)->refreshDeviceData(); + toc = m_toc; +#endif return success; } @@ -1653,7 +1735,7 @@ bool needToClose = !isOpen(); bool success = false; - +#ifndef __FreeBSD__ if( open() != -1 ) { // // we probaly need to fixup the toc for multisession mixed-mode cds @@ -1681,7 +1763,7 @@ kdDebug() << "(K3bCdDevice::CdDevice) CDROMMULTISESSION failed." << endl; } } - +#endif if( needToClose ) close(); @@ -1692,17 +1774,25 @@ bool K3bCdDevice::CdDevice::block( bool b ) const { if( open() != -1 ) { +#ifndef __FreeBSD__ ScsiCommand cmd( open() ); +#else + ScsiCommand cmd(m_passDevice); +#endif cmd[0] = 0x1E; // ALLOW MEDIA REMOVAL cmd[4] = b ? 0x1 : 0x0; int r = cmd.transport(); if( r ) { kdDebug() << "(K3bCdDevice::CdDevice) MMC ALLOW MEDIA REMOVAL failed. Falling back to cdrom.h." << endl; +#ifndef __FreeBSD__ r = ::ioctl(d->deviceFd,CDROM_LOCKDOOR, b ? 1 : 0 ); +#else + r = ::ioctl(d->deviceFd,b ? CDIOCPREVENT : CDIOCALLOW); +#endif } if( r ) - kdDebug() << "(K3bCdDevice) Cannot block/unblock device " << devicename() << endl; + kdDebug() << "(K3bCdDevice) Cannot block/unblock device " << devicename() << ", errno: " << errno << endl; close(); return ( r == 0 ); @@ -1724,22 +1814,36 @@ return e; } +#ifndef __FreeBSD__ else return false; +#else + ((CdDevice *)this)->refreshDeviceData(); + return m_rewritableCd; +#endif } bool K3bCdDevice::CdDevice::eject() const { block(false); +#ifndef __FreeBSD__ if( open() != -1 ) { ScsiCommand cmd( open() ); +#else + if( true ) { + ScsiCommand cmd(m_passDevice); +#endif cmd[0] = 0x1B; // START/STOP UNIT cmd[4] = 0x2; // LoEj = 1, Start = 0 int r = cmd.transport(); if( r ) { kdDebug() << "(K3bCdDevice::CdDevice) MMC START/STOP UNIT failed. Falling back to cdrom.h." << endl; +#ifndef __FreeBSD__ r = ::ioctl( d->deviceFd, CDROMEJECT ); +#else + r = bsd_open_close_device(m_bus, m_target, m_lun, true); +#endif } close(); @@ -1752,14 +1856,23 @@ bool K3bCdDevice::CdDevice::load() const { +#ifndef __FreeBSD__ if( open() != -1 ) { ScsiCommand cmd( open() ); +#else + if( true ) { + ScsiCommand cmd(m_passDevice); +#endif cmd[0] = 0x1B; // START/STOP UNIT cmd[4] = 0x3; // LoEj = 1, Start = 1 int r = cmd.transport(); if( r ) { kdDebug() << "(K3bCdDevice::CdDevice) MMC START/STOP UNIT failed. Falling back to cdrom.h." << endl; +#ifndef __FreeBSD__ r = ::ioctl( d->deviceFd, CDROMCLOSETRAY ); +#else + r = bsd_open_close_device(m_bus, m_target, m_lun, false); +#endif } close(); return (r == 0); @@ -1793,7 +1906,7 @@ d->deviceFd = openDevice( QFile::encodeName(devicename()) ); if (d->deviceFd < 0) { - kdDebug() << "(K3bCdDevice) Error: could not open device." << endl; + kdDebug() << "(K3bCdDevice) Error: could not open device: " << QFile::encodeName(devicename()) << endl; d->deviceFd = -1; } @@ -1915,7 +2028,11 @@ unsigned char profileBuf[8]; ::memset( profileBuf, 0, 8 ); +#ifndef __FreeBSD__ ScsiCommand cmd( open() ); +#else + ScsiCommand cmd(m_passDevice); +#endif cmd[0] = 0x46; // GET CONFIGURATION cmd[1] = 1; cmd[8] = 8; @@ -1974,7 +2091,11 @@ } inf.m_currentProfile = profile; +#ifndef __FreeBSD__ ScsiCommand cmd( open() ); +#else + ScsiCommand cmd(m_passDevice); +#endif if( inf.diskState() != STATE_NO_MEDIA ) { @@ -2037,6 +2158,33 @@ delete [] data; } +#ifdef __FreeBSD__ + else + { + ((CdDevice *)this)->refreshDeviceData(); + inf.m_rewritable = m_rewritableCd; + inf.m_numSessions = m_toc.size(); + inf.m_capacity = m_discSize; + inf.m_remaining = m_remainingSize; + inf.m_diskState = STATE_UNKNOWN; + inf.m_lastSessionState = STATE_UNKNOWN; + if (m_deviceStatus == EMPTY) + { + inf.m_diskState = STATE_EMPTY; + inf.m_lastSessionState = STATE_EMPTY; + } + else if (m_deviceStatus == APPENDABLE) + { + inf.m_diskState = STATE_INCOMPLETE; + inf.m_lastSessionState = STATE_INCOMPLETE; + } + else if (m_deviceStatus == COMPLETE) + { + inf.m_diskState = STATE_COMPLETE; + inf.m_lastSessionState = STATE_COMPLETE; + } + } +#endif // // Now we determine the size: @@ -2085,7 +2233,7 @@ if( cmd.transport( TR_DIR_READ, trackHeader, 32 ) ) { kdDebug() << "(K3bCdDevice) READ_TRACK_INFORMATION failed." << endl; kdDebug() << "(K3bCdDevice) getting disk size via toc." << endl; - +#ifndef __FreeBSD__ // TODO: use readToc! struct cdrom_tocentry tocentry; @@ -2097,6 +2245,11 @@ inf.m_capacity = tocentry.cdte_addr.lba; inf.m_capacity -= 1; // we need the last sector of the last track, not the first from the lead-out } +#else + ((CdDevice *)this)->refreshDeviceData(); + inf.m_capacity = m_discSize; + inf.m_capacity -= 1; +#endif } else { // not sure about this.... @@ -2160,7 +2313,11 @@ unsigned char dvdheader[20]; ::memset( dvdheader, 0, 20 ); +#ifndef __FreeBSD__ ScsiCommand cmd( open() ); +#else + ScsiCommand cmd(m_passDevice); +#endif cmd[0] = 0xad; // GPCMD_READ_DVD_STRUCTURE; cmd[9] = 20; if( cmd.transport( TR_DIR_READ, dvdheader, 20 ) ) { @@ -2199,7 +2356,11 @@ bool success = true; +#ifndef __FreeBSD__ ScsiCommand cmd( open() ); +#else + ScsiCommand cmd(m_passDevice); +#endif cmd[0] = 0x25; // READ CAPACITY unsigned char buf[8]; ::memset( buf, 0, 8 ); @@ -2236,7 +2397,11 @@ unsigned char header[4]; // for reading the size of the returned data ::memset( header, 0, 4 ); +#ifndef __FreeBSD__ ScsiCommand cmd( open() ); +#else + ScsiCommand cmd(m_passDevice); +#endif cmd[0] = 0x23; // GPCMD_READ_FORMAT_CAPACITIES; cmd[8] = 4; if( cmd.transport( TR_DIR_READ, header, 4 ) == 0 ) { @@ -2324,7 +2489,11 @@ unsigned char header[8]; ::memset( header, 0, 8 ); +#ifndef __FreeBSD__ ScsiCommand cmd( open() ); +#else + ScsiCommand cmd(m_passDevice); +#endif cmd[0] = 0x5A; // MODE SENSE cmd[1] = 0x08; // Disable Block Descriptors cmd[2] = page; @@ -2362,7 +2531,11 @@ bool ret = false; +#ifndef __FreeBSD__ ScsiCommand cmd( open() ); +#else + ScsiCommand cmd(m_passDevice); +#endif cmd[0] = 0x55; // MODE SELECT cmd[1] = ( sp ? 1 : 0 ) | ( pf ? 0x10 : 0 ); cmd[7] = pageLen>>8; @@ -2486,7 +2659,11 @@ unsigned char header[2]; ::memset( header, 0, 2 ); +#ifndef __FreeBSD__ ScsiCommand cmd( open() ); +#else + ScsiCommand cmd(m_passDevice); +#endif cmd[0] = 0x43; // READ TOC/PMA/ATIP cmd[1] = ( time ? 0x2 : 0x0 ); cmd[2] = format & 0x0F; @@ -2536,7 +2713,11 @@ unsigned char header[8]; ::memset( header, 0, 8 ); +#ifndef __FreeBSD__ ScsiCommand cmd( open() ); +#else + ScsiCommand cmd(m_passDevice); +#endif cmd[0] = 0xbd; // MECHANISM STATUS cmd[8] = 8; // first we read the header if( cmd.transport( TR_DIR_READ, header, 8 ) == 0 ) { @@ -2640,7 +2821,11 @@ ::memset( data, 0, dataLen ); +#ifndef __FreeBSD__ ScsiCommand cmd( open() ); +#else + ScsiCommand cmd(m_passDevice); +#endif cmd[0] = 0xbe; // READ CD cmd[1] = (sectorType<<2 & 0x1c) | ( dap ? 0x2 : 0x0 ); cmd[2] = startAdress>>24; @@ -2668,3 +2853,363 @@ return ret; } +#ifdef __FreeBSD__ +void K3bDevice::CdDevice::refreshDeviceData() +{ + // was it called within the last 3 seconds? + QDateTime now = QDateTime::currentDateTime(); + if (m_lastRefresh.isValid() && m_lastRefresh.secsTo(now) < 3) + return; // yes: use previous values + + m_driveReady = 0; + m_rewritableCd = 0; + m_discSize = 0; + m_remainingSize = 0; + m_deviceStatus = NO_INFO; + m_toc.clear(); + + KTempFile tmpfile; + tmpfile.setAutoDelete(true); + + // call cdrecord -toc to get the toc and to detect empty disks + QString call = "/bin/sh -c \"cdrecord -toc " + QString("dev=%1").arg( busTargetLun() ) + " > " + tmpfile.name() + " 2>&1 \""; + kdDebug() << "(K3bCdDevice) Reading Toc : " << call << endl; + system(call.latin1()); + + // read tmp file line by line + K3bTrack lastTrack; + bool firstEntry = true; + QFile tmp (tmpfile.name()); + if ( tmp.open( IO_ReadOnly ) ) + { + QTextStream stream( &tmp ); + bool done = false; + while ( !stream.eof() ) + { + QString str = stream.readLine(); + kdDebug() << "(K3bCdDevice): " << str << endl; + if (done) + continue; + // no disk inserted? + if ( str.startsWith( "cdrecord: No disk" ) ) + { + m_driveReady = NO_DISK; + kdDebug() << "(K3bCdDevice) No Toc Data!" << endl; + // close and delete tmp file + tmp.close(); + done = true; + continue; + } + // emoty disk inserted? + else if (str.startsWith("cdrecord: Cannot read TOC header")) + { + kdDebug() << "(K3bCdDevice) cd is empty" << endl; + m_driveReady = EMPTY; + } + // track data available? + if( str.startsWith("track:") ) + { + // cdrecord produces the following outout: + // lba: (<...>) adr: 1 control: mode: + // the last tracknumber will always be "lout", the leadout of the cd which we only use to determine the + // length of the last track + + // we just want the startSector, the trackType, and the trackMode + int start = 6; // skip the "track:" + start = str.find(":", start )+1; + int end = str.find( "(", start ); + + bool ok; + int startSec = str.mid( start, end-start ).toInt(&ok); + if( ok ) + { + start = str.find( "control:", start )+8; // skip the "control:" + end = str.find("mode:", start ); + int control = str.mid( start, end-start ).toInt(&ok); + if( ok ) + { + start = end + 6; + int mode = str.mid( start ).toInt(&ok); + if( ok ) + { + // all values have been determined + // since we need the start of the next track to determine the length we save the values + // in lastTrack and append the current lastTrack to the toc + + if( !firstEntry ) + { + m_toc.append( K3bTrack( lastTrack.firstSector(), startSec-1, lastTrack.type(), lastTrack.mode() ) ); + kdDebug() << "(K3bCDDevice) Found track: first sector: " << lastTrack.firstSector().toString() + << ", last sector: " << startSec-1 << ", type: " << lastTrack.type() + << ", mode: " << lastTrack.mode() << endl; + if (m_deviceStatus == EMPTY) + m_deviceStatus = APPENDABLE; + if( lastTrack.mode() == K3bTrack::MODE1 ) + m_deviceStatus = COMPLETE; + } + // now this is the meaning of control and mode: + // control (combination of the following) + // 0x01 - Audio with preemp + // 0x02 - Audio copy permitted + // 0x04 - Data track + // 0x08 - 4 channel audio + + // mode (only for data tracks) + // 1 - Mode 1 + // 2 - Mode 2 + + int trackType = 0; + int trackMode = K3bTrack::UNKNOWN; + if( control & 0x04 ) + { + trackType = K3bTrack::DATA; + if( mode == 1 ) + trackMode = K3bTrack::MODE1; + else if( mode == 2 ) + trackMode = K3bTrack::MODE2; + } + else + trackType = K3bTrack::AUDIO; + + lastTrack = K3bTrack( startSec, startSec, trackType, trackMode ); + firstEntry = false; + } + else + { + kdDebug() << "(K3bCdDevice) Could not parse mode of track: " << str.mid( start ) << endl; + } + } + else + { + kdDebug() << "(K3bCdDevice) Could not parse control of track: " << str.mid( start, end-start ) << endl; + } + } + else + { + kdDebug() << "(K3bCdDevice) Could not parse start sector of track: " << str.mid( start, end-start) << endl; + } + } + + } + // close and delete tmp file + tmp.close(); + + } + // skip further tests if there is no disk + if (m_driveReady != NO_DISK && m_driveReady != NO_INFO) + { + + KTempFile tmpfile2; + tmpfile2.setAutoDelete(true); + + // call cdrdao disk-info to get disk capacities, device status, and dsik type + call = "/bin/sh -c \"cdrdao disk-info --device " + QString("%1").arg( busTargetLun() ) + " --driver " + cdrdaoDriver() + " > " + tmpfile2.name() + " 2>&1 \""; + kdDebug() << "(K3bCdDevice) Reading remaining disk size : " << call << endl; + system(call.latin1()); + + // read tmp file line by line + QFile tmp2(tmpfile2.name()); + if ( tmp2.open( IO_ReadOnly ) ) + { + QTextStream stream( &tmp2 ); + while ( !stream.eof() ) + { + QString str = stream.readLine(); + kdDebug() << "(K3bCdDevice): " << str << endl; + + // remaining capacity available? + if ( str.contains( "Remaining Capacity :" ) ) + { + // cdrdao produces the following outout: + // ( blocks, MB) + + int start = str.find("(" )+1; + int end = str.find( " ", start ); + + bool ok; + int remaining = str.mid( start, end-start ).toInt(&ok); + if( ok ) + { + m_remainingSize = remaining-1; + } + else + kdDebug() << "(K3bCdDevice) Could not parse remaining time: " << str.mid( start, end-start) << endl; + } + + // total capacity available? + else if ( str.contains( "Total Capacity :" ) ) + { + // cdrdao produces the following outout: + //