/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2002 Andreas Mueller * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include "TocEdit.h" #include "CdDevice.h" #include "ProcessMonitor.h" #include "xcdrdao.h" #include "guiUpdate.h" #include "ProgressDialog.h" #include "Settings.h" #include "config.h" #include "remote.h" #include "ScsiIf.h" #include "CdrDriver.h" #include "util.h" #include "Toc.h" #define DRIVER_IDS 13 #define DRIVER_ID_DEFAULT 2 CdDevice *CdDevice::DEVICE_LIST_ = NULL; char *CdDevice::DRIVER_NAMES_[DRIVER_IDS] = { "Undefined", "cdd2600", "generic-mmc", "generic-mmc-raw", "plextor", "plextor-scan", "ricoh-mp6200", "sony-cdu920", "sony-cdu948", "taiyo-yuden", "teac-cdr55", "toshiba", "yamaha-cdr10x" }; CdDevice::CdDevice(const char* dev, const char *vendor, const char *product) { dev_ = dev; vendor_ = vendor; product_ = product; driverId_ = 0; driverOptions_ = 0; deviceType_ = CD_R; manuallyConfigured_ = false; status_ = DEV_UNKNOWN; exitStatus_ = 0; progressStatusChanged_ = 0; progressStatus_ = 0; progressTotalTracks_ = 0; progressTrack_ = 0; progressTotal_ = 0; progressTrackRelative_ = 0; progressBufferFill_ = 0; progressWriterFill_ = 0; process_ = NULL; scsiIf_ = NULL; scsiIfInitFailed_ = 0; next_ = NULL; slaveDevice_ = NULL; autoSelectDriver(); } CdDevice::~CdDevice() { delete scsiIf_; scsiIf_ = NULL; } char *CdDevice::settingString() const { char buf[100]; std::string s; s = "'" + dev_ + "','"; s += vendor_; s += "','"; s += product_; s += "',"; switch (deviceType_) { case CD_R: s += "CD_R"; break; case CD_RW: s += "CD_RW"; break; case CD_ROM: s+= "CD_ROM"; break; } s += ","; s += driverName(driverId_); s += ","; sprintf(buf, "0x%lx", driverOptions_); s += buf; return strdupCC(s.c_str()); } void CdDevice::driverId(int id) { if (id >= 0 && id < DRIVER_IDS) driverId_ = id; } void CdDevice::status(Status s) { status_ = s; } int CdDevice::exitStatus() const { return exitStatus_; } int CdDevice::autoSelectDriver() { unsigned long options = 0; const char *driverName; driverName = CdrDriver::selectDriver(1, vendor_.c_str(), product_.c_str(), &options); if (driverName) { driverId_ = driverName2Id(driverName); driverOptions_ = options; } else { bool r_cdr, w_cdr, r_cdrw, w_cdrw; ScsiIf* sif = new ScsiIf(dev_.c_str()); if (sif && sif->init() == 0 && sif->checkMmc(&r_cdr, &w_cdr, &r_cdrw, &w_cdrw)) { driverId_ = driverName2Id("generic-mmc"); if (r_cdr) deviceType_ = CD_ROM; if (w_cdr) deviceType_ = CD_R; if (w_cdrw) deviceType_ = CD_RW; } else { driverId_ = DRIVER_ID_DEFAULT; driverOptions_ = 0; } if (sif) delete sif; } return 1; } int CdDevice::updateStatus() { Status newStatus = status_; if (process_ != NULL) { if (process_->exited()) { newStatus = DEV_UNKNOWN; exitStatus_ = process_->exitStatus(); progressStatusChanged_ = 1; PROCESS_MONITOR->remove(process_); process_ = NULL; if (slaveDevice_ != NULL) { slaveDevice_->status(DEV_UNKNOWN); slaveDevice_ = NULL; } } } if (status_ == DEV_READY || status_ == DEV_BUSY || status_ == DEV_NO_DISK || status_ == DEV_UNKNOWN) { if (scsiIf_ == NULL) createScsiIf(); if (scsiIf_ != NULL) { switch (scsiIf_->testUnitReady()) { case 0: newStatus = DEV_READY; break; case 1: newStatus = DEV_BUSY; break; case 2: newStatus = DEV_NO_DISK; break; case 3: // Most likely a timeout error. newStatus = DEV_BUSY; break; } } else { newStatus = DEV_FAULT; } } if (newStatus != status_) { status_ = newStatus; return 1; } return 0; } bool CdDevice::updateProgress(Glib::IOCondition cond, int fd) { static char msgSync[4] = { 0xff, 0x00, 0xff, 0x00 }; fd_set fds; int state = 0; char buf[10]; struct timeval timeout = { 0, 0 }; if (process_ == NULL) return false; if (!(cond & Gdk::INPUT_READ)) return false; FD_ZERO(&fds); FD_SET(fd, &fds); while (select(fd + 1, &fds, NULL, NULL, &timeout) > 0 && FD_ISSET(fd, &fds)) { FD_ZERO(&fds); FD_SET(fd, &fds); state = 0; while (state < 4) { if (read(fd, buf, 1) != 1) { //message(-2, "Reading of msg sync failed."); return false; } if (buf[0] == msgSync[state]) { state++; } else { state = 0; if (buf[0] == msgSync[state]) { state++; } } } ProgressMsg msg; int msgsize = read(fd, (char *)&msg, sizeof(msg)); if (msgsize >= PSGMSG_MINSIZE) { if (msg.status >= PGSMSG_MIN && msg.status <= PGSMSG_MAX && msg.track >= 0 && msg.totalProgress >= 0 && msg.totalProgress <= 1000 && msg.bufferFillRate >= 0 && msg.bufferFillRate <= 100) { progressStatus_ = msg.status; progressTotalTracks_ = msg.totalTracks; progressTrack_ = msg.track; progressTrackRelative_ = msg.trackProgress; progressTotal_ = msg.totalProgress; progressBufferFill_ = msg.bufferFillRate; if (msgsize == sizeof(msg)) progressWriterFill_ = msg.writerFillRate; else progressWriterFill_ = 0; progressStatusChanged_ = 1; } } else { message(-1, _("Reading of progress message failed.")); } } if (progressStatusChanged_) guiUpdate(UPD_PROGRESS_STATUS); return true; } CdDevice::DeviceType CdDevice::deviceType() const { return deviceType_; } void CdDevice::deviceType(DeviceType t) { deviceType_ = t; } unsigned long CdDevice::driverOptions() const { return driverOptions_; } void CdDevice::driverOptions(unsigned long o) { driverOptions_ = o; } bool CdDevice::ejectCd(bool load) { bool success = false; if (!scsiIf_) createScsiIf(); if (scsiIf_) { CdrDriver* driver = CdrDriver::createDriver(driverName(driverId_), driverOptions_, scsiIf_); int ret = driver->loadUnload((load ? 0 : 1)); success = (ret == 0); delete(driver); } return success; } // Starts a 'cdrdao' for recording given toc. Returns false if an // error occured and the process was not successfully launched. bool CdDevice::recordDao(Gtk::Window& parent, TocEdit *tocEdit, int simulate, int multiSession, int speed, int eject, int reload, int buffer, int overburn) { char tocFileName[30]; char *args[30]; int n = 0; char devname[30]; char drivername[50]; char speedbuf[20]; char *execName; const char *s; char bufferbuf[20]; int remoteFdArgNum = 0; if ((status_ != DEV_READY && status_ != DEV_FAULT && status_ != DEV_UNKNOWN) || process_ != NULL) return false; sprintf(tocFileName, "/tmp/gcdm.toc.XXXXXX"); int fd = mkstemp(tocFileName); if (!fd) { message(-2, _("Cannot create temporary toc-file: %s"), strerror(errno)); return false; } // Write out temporary toc file containing all the converted wav // files (don't want to rely on cdrdao doing the mp3->wav // translation, besides it's already been done). if (!tocEdit->toc()->write(fd, true)) { close(fd); message(-2, _("Cannot write temporary toc-file.")); return false; } close(fd); if ((s = gnome_config_get_string(SET_CDRDAO_PATH)) != NULL) execName = strdupCC(s); else execName = strdupCC("cdrdao"); args[n++] = execName; if (simulate) args[n++] = "simulate"; else args[n++] = "write"; args[n++] = "--remote"; remoteFdArgNum = n; args[n++] = NULL; args[n++] = "-v0"; if (multiSession) args[n++] = "--multi"; if (speed > 0) { sprintf(speedbuf, "%d", speed); args[n++] = "--speed"; args[n++] = speedbuf; } if (eject) args[n++] = "--eject"; if (reload) args[n++] = "--reload"; if (overburn) args[n++] = "--overburn"; args[n++] = "--device"; args[n++] = (char*)dev_.c_str(); if (driverId_ > 0) { sprintf(drivername, "%s:0x%lx", driverName(driverId_), driverOptions_); args[n++] = "--driver"; args[n++] = drivername; } if (buffer >= 10) { sprintf(bufferbuf, "%i", buffer); args[n++] = "--buffers"; args[n++] = bufferbuf; } args[n++] = tocFileName; args[n++] = NULL; assert(n <= 20); PROGRESS_POOL->start(parent, this, tocEdit->filename()); // Remove the SCSI interface of this device to avoid problems with double // usage of device nodes. delete scsiIf_; scsiIf_ = NULL; process_ = PROCESS_MONITOR->start(execName, args, remoteFdArgNum); delete execName; if (process_ != NULL) { status_ = DEV_RECORDING; action_ = A_RECORD; if (process_->commFd() >= 0) { Glib::signal_io().connect(bind(mem_fun(*this, &CdDevice::updateProgress), process_->commFd()), process_->commFd(), Glib::IO_IN | Glib::IO_HUP); } return true; } else { unlink(tocFileName); free(tocFileName); return false; } } void CdDevice::abortDaoRecording() { if (process_ != NULL && !process_->exited()) { PROCESS_MONITOR->stop(process_); } } int CdDevice::progressStatusChanged() { if (progressStatusChanged_) { progressStatusChanged_ = 0; return 1; } return 0; } void CdDevice::progress(int *status, int *totalTracks, int *track, int *trackProgress, int *totalProgress, int *bufferFill, int *writerFill) const { *status = progressStatus_; *totalTracks = progressTotalTracks_; *track = progressTrack_; *trackProgress = progressTrackRelative_; *totalProgress = progressTotal_; *bufferFill = progressBufferFill_; *writerFill = progressWriterFill_; } // Starts a 'cdrdao' for reading whole cd. // Return: 0: OK, process succesfully launched // 1: error occured int CdDevice::extractDao(Gtk::Window& parent, const char *tocFileName, int correction, int readSubChanMode) { char *args[30]; int n = 0; char devname[30]; char drivername[50]; char *execName; const char *s; char correctionbuf[20]; int remoteFdArgNum = 0; if ((status_ != DEV_READY && status_ != DEV_FAULT && status_ != DEV_UNKNOWN) || process_ != NULL) return 1; if ((s = gnome_config_get_string(SET_CDRDAO_PATH)) != NULL) execName = strdupCC(s); else execName = strdupCC("cdrdao"); args[n++] = execName; args[n++] = "read-cd"; args[n++] = "--remote"; remoteFdArgNum = n; args[n++] = NULL; args[n++] = "-v0"; args[n++] = "--read-raw"; switch (readSubChanMode) { case 1: args[n++] = "--read-subchan"; args[n++] = "rw"; break; case 2: args[n++] = "--read-subchan"; args[n++] = "rw_raw"; break; } args[n++] = "--device"; args[n++] = (char*)dev_.c_str(); if (driverId_ > 0) { sprintf(drivername, "%s:0x%lx", driverName(driverId_), driverOptions_); args[n++] = "--driver"; args[n++] = drivername; } sprintf(correctionbuf, "%d", correction); args[n++] = "--paranoia-mode"; args[n++] = correctionbuf; args[n++] = "--datafile"; args[n++] = g_strdup_printf("%s.bin", tocFileName); args[n++] = g_strdup_printf("%s.toc", tocFileName); args[n++] = NULL; assert(n <= 20); PROGRESS_POOL->start(parent, this, tocFileName, false, false); // Remove the SCSI interface of this device to avoid problems with double // usage of device nodes. delete scsiIf_; scsiIf_ = NULL; process_ = PROCESS_MONITOR->start(execName, args, remoteFdArgNum); delete[] execName; if (process_ != NULL) { status_ = DEV_READING; action_ = A_READ; if (process_->commFd() >= 0) { Glib::signal_io().connect(bind(mem_fun(*this, &CdDevice::updateProgress), process_->commFd()), process_->commFd(), Glib::IO_IN | Glib::IO_PRI | Glib::IO_ERR | Glib::IO_HUP); } return 0; } else { return 1; } } void CdDevice::abortDaoReading() { if (process_ != NULL && !process_->exited()) { PROCESS_MONITOR->stop(process_); } } // Starts a 'cdrdao' for duplicating a CD. // Return: 0: OK, process succesfully launched // 1: error occured int CdDevice::duplicateDao(Gtk::Window& parent, int simulate, int multiSession, int speed, int eject, int reload, int buffer, int onthefly, int correction, int readSubChanMode, CdDevice *readdev) { char *args[30]; int n = 0; char devname[30]; char drivername[50]; char r_drivername[50]; char speedbuf[20]; char correctionbuf[20]; char *execName; const char *s; char bufferbuf[20]; int remoteFdArgNum = 0; int rdstat = readdev->status(); if ((rdstat != DEV_READY && rdstat != DEV_UNKNOWN && rdstat != DEV_FAULT) || readdev->process() != NULL) return 1; if ((status_ != DEV_READY && status_ != DEV_FAULT && status_ != DEV_UNKNOWN) || process_ != NULL) return 1; if ((s = gnome_config_get_string(SET_CDRDAO_PATH)) != NULL) execName = strdupCC(s); else execName = strdupCC("cdrdao"); args[n++] = execName; args[n++] = "copy"; if (simulate) args[n++] = "--simulate"; args[n++] = "--remote"; remoteFdArgNum = n; args[n++] = NULL; args[n++] = "-v0"; if (multiSession) args[n++] = "--multi"; sprintf(correctionbuf, "%d", correction); args[n++] = "--paranoia-mode"; args[n++] = correctionbuf; if (speed > 0) { sprintf(speedbuf, "%d", speed); args[n++] = "--speed"; args[n++] = speedbuf; } if (eject) args[n++] = "--eject"; if (reload) args[n++] = "--reload"; if (onthefly) args[n++] = "--on-the-fly"; switch (readSubChanMode) { case 1: args[n++] = "--read-subchan"; args[n++] = "rw"; break; case 2: args[n++] = "--read-subchan"; args[n++] = "rw_raw"; break; } args[n++] = "--device"; args[n++] = (char*)dev_.c_str(); if (driverId_ > 0) { sprintf(drivername, "%s:0x%lx", driverName(driverId_), driverOptions_); args[n++] = "--driver"; args[n++] = drivername; } if (readdev != this) { // reader and write the same, skip source device args[n++] = "--source-device"; args[n++] = (char*)readdev->dev(); if (readdev->driverId() > 0) { sprintf(r_drivername, "%s:0x%lx", driverName(readdev->driverId()), readdev->driverOptions()); args[n++] = "--source-driver"; args[n++] = r_drivername; } } if (buffer >= 10) { sprintf(bufferbuf, "%i", buffer); args[n++] = "--buffers"; args[n++] = bufferbuf; } args[n++] = NULL; assert(n <= 25); PROGRESS_POOL->start(parent, this, _("CD to CD copy")); // Remove the SCSI interface of this device to avoid problems with double // usage of device nodes. delete scsiIf_; scsiIf_ = NULL; process_ = PROCESS_MONITOR->start(execName, args, remoteFdArgNum); delete[] execName; if (process_ != NULL) { slaveDevice_ = readdev; slaveDevice_->status(DEV_READING); status_ = DEV_RECORDING; action_ = A_DUPLICATE; if (process_->commFd() >= 0) { Glib::signal_io().connect(bind(mem_fun(*this, &CdDevice::updateProgress), process_->commFd()), process_->commFd(), Glib::IO_IN | Glib::IO_HUP); } return 0; } else { return 1; } } void CdDevice::abortDaoDuplication() { if (process_ != NULL && !process_->exited()) { PROCESS_MONITOR->stop(process_); } } // Starts a 'cdrdao' for blanking a CD. // Return: 0: OK, process succesfully launched // 1: error occured int CdDevice::blank(Gtk::Window* parent, int fast, int speed, int eject, int reload) { char *args[20]; int n = 0; char devname[30]; char drivername[50]; char speedbuf[20]; char *execName; const char *s; int remoteFdArgNum = 0; if ((status_ != DEV_READY && status_ != DEV_FAULT && status_ != DEV_UNKNOWN) || process_ != NULL) return 1; if ((s = gnome_config_get_string(SET_CDRDAO_PATH)) != NULL) execName = strdupCC(s); else execName = strdupCC("cdrdao"); args[n++] = execName; args[n++] = "blank"; args[n++] = "--remote"; remoteFdArgNum = n; args[n++] = NULL; args[n++] = "-v0"; args[n++] = "--blank-mode"; if (fast) args[n++] = "minimal"; else args[n++] = "full"; if (speed > 0) { sprintf(speedbuf, "%d", speed); args[n++] = "--speed"; args[n++] = speedbuf; } if (eject) args[n++] = "--eject"; if (reload) args[n++] = "--reload"; args[n++] = "--device"; args[n++] = (char*)dev_.c_str(); if (driverId_ > 0) { sprintf(drivername, "%s:0x%lx", driverName(driverId_), driverOptions_); args[n++] = "--driver"; args[n++] = drivername; } args[n++] = NULL; assert(n <= 20); if (parent) PROGRESS_POOL->start(*parent, this, _("Blanking CDRW"), false, false); else PROGRESS_POOL->start(this, _("Blanking CDRW"), false, false); // Remove the SCSI interface of this device to avoid problems with double // usage of device nodes. delete scsiIf_; scsiIf_ = NULL; process_ = PROCESS_MONITOR->start(execName, args, remoteFdArgNum); delete[] execName; if (process_ != NULL) { status_ = DEV_BLANKING; action_ = A_BLANK; if (process_->commFd() >= 0) { Glib::signal_io().connect(bind(mem_fun(*this, &CdDevice::updateProgress), process_->commFd()), process_->commFd(), Glib::IO_IN | Glib::IO_HUP); } return 0; } else { return 1; } } void CdDevice::abortBlank() { if (process_ != NULL && !process_->exited()) { PROCESS_MONITOR->stop(process_); } } void CdDevice::createScsiIf() { char buf[100]; if (scsiIfInitFailed_) return; delete scsiIf_; scsiIf_ = new ScsiIf(dev_.c_str()); if (scsiIf_->init() != 0) { delete scsiIf_; scsiIf_ = NULL; scsiIfInitFailed_ = 1; } } int CdDevice::driverName2Id(const char *driverName) { int i; for (i = 1; i < DRIVER_IDS; i++) { if (strcmp(DRIVER_NAMES_[i], driverName) == 0) return i; } return 0; } int CdDevice::maxDriverId() { return DRIVER_IDS - 1; } const char *CdDevice::driverName(int id) { if (id >= 0 && id < DRIVER_IDS) { return DRIVER_NAMES_[id]; } else { return "Undefined"; } } const char *CdDevice::status2string(Status s) { char *ret = NULL; switch (s) { case DEV_READY: ret = "Ready"; break; case DEV_RECORDING: ret = "Recording"; break; case DEV_READING: ret = "Reading"; break; case DEV_WAITING: ret = "Waiting"; break; case DEV_BLANKING: ret = "Blanking"; break; case DEV_BUSY: ret = "Busy"; break; case DEV_NO_DISK: ret = "No disk"; break; case DEV_FAULT: ret = "Not available"; break; case DEV_UNKNOWN: ret = "Unknown"; break; } return ret; } const char *CdDevice::deviceType2string(DeviceType t) { char *ret = NULL; switch (t) { case CD_R: ret = "CD-R"; break; case CD_RW: ret = "CD-RW"; break; case CD_ROM: ret = "CD-ROM"; break; } return ret; } /* reads configured devices from gnome settings */ void CdDevice::importSettings() { int i, n; char *s; char buf[20]; CdDevice *dev; n = gnome_config_get_int(SET_DEVICES_NUM); if (n > 0) { gnome_config_push_prefix(SET_SECTION_DEVICES); for (i = 0; i < n; i++) { sprintf(buf, "%d", i); s = gnome_config_get_string(buf); if (s != NULL) { if ((dev = CdDevice::add(s)) != NULL) dev->manuallyConfigured(true); } } gnome_config_pop_prefix(); } } /* saves manually configured devices as gnome settings */ void CdDevice::exportSettings() { int i, n; char *s; char buf[20]; CdDevice *drun; gnome_config_clean_section(SET_SECTION_DEVICES); for (drun = first(), n = 0; drun != NULL; drun = next(drun)) { if (drun->manuallyConfigured()) { n++; } } if (n > 0) { gnome_config_set_int(SET_DEVICES_NUM, n); gnome_config_push_prefix(SET_SECTION_DEVICES); for (drun = first(), i = 0; drun != NULL; drun = next(drun)) { if (drun->manuallyConfigured()) { sprintf(buf, "%d", i); s = drun->settingString(); gnome_config_set_string(buf, s); delete[] s; i++; } } gnome_config_pop_prefix(); } } CdDevice *CdDevice::add(const char* dev, const char *vendor, const char *product) { CdDevice *run, *pred, *ent; for (pred = NULL, run = DEVICE_LIST_; run != NULL; pred = run, run = run->next_) { if (strcmp(run->dev(), dev) == 0) return run; } ent = new CdDevice(dev, vendor, product); if (pred != NULL) { ent->next_ = pred->next_; pred->next_ = ent; } else { ent->next_ = DEVICE_LIST_; DEVICE_LIST_ = ent; } return ent; } static char *nextToken(char *&p) { char *val = NULL; if (p == NULL || *p == 0) return NULL; while (*p != 0 && isspace(*p)) p++; if (*p == 0) return NULL; if (*p == '\'') { p++; val = p; while (*p != 0 && *p != '\'') p++; if (*p == 0) { // error, no matching ' found return NULL; } else { *p++ = 0; // skip over , while (*p != 0 && *p != ',') p++; if (*p == ',') p++; } } else { val = p; while (*p != 0 && *p != ',') p++; if (*p == ',') *p++ = 0; } return val; } static CdDevice *addImpl(char *s) { char *p; int driverId; std::string dev; std::string vendor; std::string model; std::string device; unsigned long options; char *val; CdDevice::DeviceType type; CdDevice *cddev; if (s[0] != '\'') return NULL; p = s; if ((val = nextToken(p)) == NULL) return NULL; dev = val; if ((val = nextToken(p)) == NULL) return NULL; vendor = val; if ((val = nextToken(p)) == NULL) return NULL; model = val; if ((val = nextToken(p)) == NULL) return NULL; if (strcasecmp(val, "CD_R") == 0) type = CdDevice::CD_R; else if (strcasecmp(val, "CD_RW") == 0) type = CdDevice::CD_RW; else if (strcasecmp(val, "CD_ROM") == 0) type = CdDevice::CD_ROM; else type = CdDevice::CD_R; if ((val = nextToken(p)) == NULL) return NULL; driverId = CdDevice::driverName2Id(val); if ((val = nextToken(p)) == NULL) return NULL; options = strtoul(val, NULL, 0); cddev = CdDevice::add(dev.c_str(), vendor.c_str(), model.c_str()); cddev->driverId(driverId); cddev->deviceType(type); cddev->driverOptions(options); return cddev; } CdDevice *CdDevice::add(const char *setting) { char *s = strdupCC(setting); CdDevice *dev = addImpl(s); delete[] s; return dev; } CdDevice *CdDevice::find(const char* dev) { CdDevice *run; for (run = DEVICE_LIST_; run != NULL; run = run->next_) { if (strcmp(run->dev(), dev) == 0) return run; } return NULL; } void CdDevice::scan() { int i, len; ScsiIf::ScanData *sdata = ScsiIf::scan(&len); if (sdata) { for (i = 0; i < len; i++) CdDevice::add(sdata[i].dev.c_str(), sdata[i].vendor, sdata[i].product); delete[] sdata; } #ifdef SCSI_ATAPI sdata = ScsiIf::scan(&len, "ATA"); if (sdata) { for (i = 0; i < len; i++) CdDevice::add(sdata[i].dev.c_str(), sdata[i].vendor, sdata[i].product); delete[] sdata; } else { // Only scan for ATAPI devices if we got nothing on the ATA // interface, otherwise every device would show up twice on the // list. sdata = ScsiIf::scan(&len, "ATAPI"); if (sdata) { for (i = 0; i < len; i++) CdDevice::add(sdata[i].dev.c_str(), sdata[i].vendor, sdata[i].product); delete[] sdata; } } #endif } void CdDevice::remove(const char* dev) { CdDevice *run, *pred; for (pred = NULL, run = DEVICE_LIST_; run != NULL; pred = run, run = run->next_) { if (strcmp(run->dev(), dev) == 0) { if (run->status() == DEV_RECORDING || run->status() == DEV_BLANKING || run->status() == DEV_READING || run->status() == DEV_WAITING) return; if (pred != NULL) pred->next_ = run->next_; else DEVICE_LIST_ = run->next_; delete run; return; } } } void CdDevice::clear() { CdDevice *next; while (DEVICE_LIST_ != NULL) { next = DEVICE_LIST_->next_; delete DEVICE_LIST_; DEVICE_LIST_ = next; } } CdDevice *CdDevice::first() { return DEVICE_LIST_; } CdDevice *CdDevice::next(const CdDevice *run) { if (run != NULL) return run->next_; else return NULL; } int CdDevice::count() { CdDevice *run; int cnt = 0; for (run = DEVICE_LIST_; run != NULL; run = run->next_) cnt++; return cnt; } int CdDevice::updateDeviceStatus() { int newStatus = 0; CdDevice *run; blockProcessMonitorSignals(); for (run = DEVICE_LIST_; run != NULL; run = run->next_) { if (run->updateStatus()) newStatus = 1; } unblockProcessMonitorSignals(); return newStatus; }