/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 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 "config.h" #include #include #include #include #include #include #include "winaspi.h" #include "ScsiIf.h" #include "util.h" #include "decodeSense.cc" typedef DWORD (*GETSUPPORTINFO) (void); typedef DWORD (*GETDLLVERSION) (void); typedef DWORD (*SENDCOMMAND) (char *); #define BUF_SIZE (32*1024) class ScsiIfImpl { public: char *dev_; int maxSendLen_; SRB_ExecSCSICmd6 cmd6_; SRB_ExecSCSICmd10 cmd10_; SRB_ExecSCSICmd12 cmd12_; unsigned char senseBuffer_[SENSE_LEN]; char haid_; char lun_; char scsi_id_; HINSTANCE hinstlib; SENDCOMMAND Sendcommand; }; ScsiIf::ScsiIf(const char *dev) { char *p, *q; impl_ = new ScsiIfImpl; impl_->dev_ = strdupCC(dev); maxDataLen_ = BUF_SIZE; impl_->haid_ = 0; impl_->lun_ = 0; impl_->scsi_id_ = 0; if (p = strchr (impl_->dev_, ':')) { *p = 0; impl_->haid_ = atoi (impl_->dev_); q = ++p; if (p = strchr (q, ':')) { *p = 0; impl_->lun_ = atoi (q); q = ++p; impl_->scsi_id_ = atoi (q); } } impl_->hinstlib = 0; vendor_[0] = 0; product_[0] = 0; revision_[0] = 0; } ScsiIf::~ScsiIf() { delete[] impl_->dev_; impl_->dev_ = NULL; if (impl_->hinstlib) FreeLibrary (impl_->hinstlib); delete impl_; } // opens and flushes scsi device // return: 0: OK // 1: device could not be opened // 2: inquiry failed int ScsiIf::init() { impl_->hinstlib = LoadLibrary ("WNASPI32.DLL"); if (!impl_->hinstlib) { message (-2, "Can't load WNASPI32.DLL"); return 1; } else { impl_->Sendcommand = (SENDCOMMAND)GetProcAddress (impl_->hinstlib, "SendASPI32Command"); } if (inquiry() != 0) return 2; return 0; } // Sets given timeout value in seconds and returns old timeout. // return: old timeout int ScsiIf::timeout (int t) { return 0; } // sends a scsi command and receives data // return 0: OK // 1: scsi command failed (os level, no sense data available) // 2: scsi command failed (sense data available) int ScsiIf::sendCmd (const unsigned char *cmd, int cmdLen, const unsigned char *dataOut, int dataOutLen, unsigned char *dataIn, int dataInLen, int showMessage) { int status, i = 10; switch (cmdLen) { case 6: memset (&impl_->cmd6_, 0, sizeof (SRB_ExecSCSICmd6)); memcpy (impl_->cmd6_.CDBByte, cmd, 6); impl_->cmd6_.SRB_Cmd = SC_EXEC_SCSI_CMD; impl_->cmd6_.SRB_HaId = impl_->haid_; impl_->cmd6_.SRB_Target = impl_->scsi_id_; impl_->cmd6_.SRB_Lun = impl_->lun_; impl_->cmd6_.SRB_SenseLen = SENSE_LEN; impl_->cmd6_.SRB_CDBLen = 6; if (dataOut && dataOutLen) { impl_->cmd6_.SRB_Flags = SRBF_WRITE; impl_->cmd6_.SRB_BufPointer = dataOut; impl_->cmd6_.SRB_BufLen = dataOutLen; } else { impl_->cmd6_.SRB_Flags = SRBF_READ; impl_->cmd6_.SRB_BufPointer = dataIn; impl_->cmd6_.SRB_BufLen = dataInLen; } (impl_->Sendcommand) ((char *) &impl_->cmd6_); while (i-- && impl_->cmd6_.SRB_Status != SS_COMP) { while (!impl_->cmd6_.SRB_Status) Sleep (10); } // AM: Try to get sense data if (impl_->cmd6_.SRB_Status == SS_ERR && impl_->cmd6_.SRB_TargStat == STATUS_CHKCOND) { memcpy(impl_->senseBuffer_, impl_->cmd6_.SenseArea, SENSE_LEN); if (showMessage) printError(); return 2; } if (impl_->cmd6_.SRB_Status != SS_COMP) return (1); break; case 10: memset (&impl_->cmd10_, 0, sizeof (SRB_ExecSCSICmd10)); memcpy (impl_->cmd10_.CDBByte, cmd, 10); impl_->cmd10_.SRB_Cmd = SC_EXEC_SCSI_CMD; impl_->cmd10_.SRB_HaId = impl_->haid_; impl_->cmd10_.SRB_Target = impl_->scsi_id_; impl_->cmd10_.SRB_Lun = impl_->lun_; impl_->cmd10_.SRB_SenseLen = SENSE_LEN; impl_->cmd10_.SRB_CDBLen = 10; if (dataOut && dataOutLen) { impl_->cmd10_.SRB_Flags = SRBF_WRITE; impl_->cmd10_.SRB_BufPointer = dataOut; impl_->cmd10_.SRB_BufLen = dataOutLen; } else { impl_->cmd10_.SRB_Flags = SRBF_READ; impl_->cmd10_.SRB_BufPointer = dataIn; impl_->cmd10_.SRB_BufLen = dataInLen; } (impl_->Sendcommand) ((char *) &impl_->cmd10_); while (i-- && impl_->cmd10_.SRB_Status != SS_COMP) { while (!impl_->cmd10_.SRB_Status) Sleep (10); } // AM: Try to get sense data if (impl_->cmd10_.SRB_Status == SS_ERR && impl_->cmd10_.SRB_TargStat == STATUS_CHKCOND) { memcpy(impl_->senseBuffer_, impl_->cmd10_.SenseArea10, SENSE_LEN); if (showMessage) printError(); return 2; } if (impl_->cmd10_.SRB_Status != SS_COMP) return (1); break; case 12: memset (&impl_->cmd12_, 0, sizeof (SRB_ExecSCSICmd12)); memcpy (impl_->cmd12_.CDBByte, cmd, 12); impl_->cmd12_.SRB_Cmd = SC_EXEC_SCSI_CMD; impl_->cmd12_.SRB_HaId = impl_->haid_; impl_->cmd12_.SRB_Target = impl_->scsi_id_; impl_->cmd12_.SRB_Lun = impl_->lun_; impl_->cmd12_.SRB_SenseLen = SENSE_LEN; impl_->cmd12_.SRB_CDBLen = 12; if (dataOut && dataOutLen) { impl_->cmd12_.SRB_Flags = SRBF_WRITE; impl_->cmd12_.SRB_BufPointer = dataOut; impl_->cmd12_.SRB_BufLen = dataOutLen; } else { impl_->cmd12_.SRB_Flags = SRBF_READ; impl_->cmd12_.SRB_BufPointer = dataIn; impl_->cmd12_.SRB_BufLen = dataInLen; } (impl_->Sendcommand) ((char *) &impl_->cmd12_); while (i-- && impl_->cmd12_.SRB_Status != SS_COMP) { while (!impl_->cmd12_.SRB_Status) Sleep (10); } // AM: Try to get sense data if (impl_->cmd12_.SRB_Status == SS_ERR && impl_->cmd12_.SRB_TargStat == STATUS_CHKCOND) { memcpy(impl_->senseBuffer_, impl_->cmd12_.SenseArea12, SENSE_LEN); if (showMessage) printError(); return 2; } if (impl_->cmd12_.SRB_Status != SS_COMP) return (1); break; } return 0; } const unsigned char *ScsiIf::getSense(int &len) const { len = SENSE_LEN; return impl_->senseBuffer_; } void ScsiIf::printError() { decodeSense(impl_->senseBuffer_, SENSE_LEN); } int ScsiIf::inquiry() { unsigned char cmd[6]; unsigned char result[0x2c]; int i; cmd[0] = 0x12; // INQUIRY cmd[1] = cmd[2] = cmd[3] = 0; cmd[4] = 0x2c; cmd[5] = 0; if (sendCmd (cmd, 6, NULL, 0, result, 0x2c, 1) != 0) { message (-2, "Inquiry command failed on '%s': ", impl_->dev_); return 1; } strncpy(vendor_, (char *)(result + 0x08), 8); vendor_[8] = 0; strncpy(product_, (char *)(result + 0x10), 16); product_[16] = 0; strncpy(revision_, (char *)(result + 0x20), 4); revision_[4] = 0; for (i = 7; i >= 0 && vendor_[i] == ' '; i--) { vendor_[i] = 0; } for (i = 15; i >= 0 && product_[i] == ' '; i--) { product_[i] = 0; } for (i = 3; i >= 0 && revision_[i] == ' '; i--) { revision_[i] = 0; } return 0; }