Logo Search packages:      
Sourcecode: qpxtool version File versions  Download package

qpx_mmc.cpp

/*
 * This file is part of the QPxTool project.
 * Copyright (C) 2005-2007 Gennady "ShultZ" Kozlov <qpxtool@mail.ru>
 *
 * original version of CD-R(W) manufacturer identification code got from cdrecord, (C) Joerg Schilling
 *
 * 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.
 * See the file "COPYING" for the exact licensing terms.
 *
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <unistd.h>
//#include <sys/time.h>

//#include "transport.hxx"
#include "qpx_mmc.h"

//#define FEATURE_DEBUG

const unsigned int      bufsz_dev  = 0x0000FF;
const unsigned int      bufsz_rd   = 0x010000;
const unsigned int      bufsz_ATIP = 0x000800;

drive_info::drive_info(){
}

drive_info::drive_info(char* _device){
      device=(char*)malloc(bufsz_dev);
      strcpy(device,_device);
      rd_buf=(unsigned char*)malloc(bufsz_rd);
      ATIP=(unsigned char*)malloc(bufsz_ATIP);
      if (!cmd.associate(device, NULL)) {
//          printf("** Can't open device: %16s\n",_device);
            err=1;
            mmc=-1;
            return;
      }
      mmc=0;
      parms.interval=1;
      parms.tests=0;
      capabilities=0;
      rd_capabilities=0;
      wr_capabilities=0;
      ven_features=0;
      chk_features=0;
      plextor.gigarec=0;
      plextor.varirec_state_cd=0;
      plextor.varirec_pwr_cd=0;
      plextor.varirec_str_cd=0;
      plextor.varirec_state_dvd=0;
      plextor.varirec_pwr_dvd=0;
      plextor.varirec_str_dvd=0;
      plextor.powerec_state=0;
      plextor.plexeraser=0;
      ven_ID=0;
      dev_ID=0;
      iface_id=0;
      iface[0]=0;
      loader_id=0;
      parms.scan_speed_cd=8;
      parms.scan_speed_dvd=5;
      parms.spindown_idx=0;
      silent=0;
}

drive_info::~drive_info(){
//    delete urd_buf;
      busy=1;
//    delete pthread_t;
      delete rd_buf;
      delete ATIP;
      delete device;
}

void drivecpy(drive_info* dst, drive_info* src){
      dst->device=(char*)malloc(bufsz_dev);
//          printf("Can't copy device:(\n");
      memcpy(dst->device, src->device,bufsz_dev);
//          printf("Can't copy device:(\n");
//    if (!dst->cmd.associate(dst->device, NULL)) {
//          dst->mmc=-1;
//          printf("Can't copy device:(\n");
//          return;
//    }
      dst->mmc=src->mmc;
//    dst->memcpy(dst, src, 0xFF);
      dst->rd_buf=(unsigned char*)malloc(bufsz_rd);
      dst->ATIP=(unsigned char*)malloc(bufsz_ATIP);
      dst->ATIP_len = src->ATIP_len;
      dst->ven_ID=src->ven_ID;
      memcpy(dst->ven,src->ven,9);
      dst->dev_ID=src->dev_ID;
      memcpy(dst->dev,src->dev,17);
      memcpy(dst->fw,src->fw,5);
      memcpy(dst->serial,src->serial,17);
      memcpy(dst->TLA,src->TLA,5);
      dst->buffer_size = src->buffer_size;
      dst->capabilities = src->capabilities;
      dst->rd_capabilities = src->rd_capabilities;
      dst->wr_capabilities = src->wr_capabilities;
      dst->ven_features = src->ven_features;
      dst->chk_features = src->chk_features;

      dst->iface_id = src->iface_id;
      memcpy(dst->iface,src->iface,sizeof(str_if));
      dst->loader_id = src->loader_id;

      dst->book_plus_r = src->book_plus_r;
      dst->book_plus_rw = src->book_plus_rw;
      dst->book_plus_rdl = src->book_plus_rdl;

      memcpy(&(dst->plextor),&(src->plextor),sizeof(plex_features));
      memcpy(&(dst->astrategy),&(src->astrategy),sizeof(plex_as));
      memcpy(&(dst->plextor_silent),&(src->plextor_silent),sizeof(plex_silent));
      memcpy(&(dst->media),&(src->media),sizeof(media_info));
      memcpy(&(dst->parms),&(src->parms),sizeof(drive_parms));
      memcpy(&(dst->perf),&(src->perf),sizeof(perf_desc));
//    memcpy(dst->,src->,sizeof());

      dst->parms.tests = src->parms.tests;
      dst->parms.interval = src->parms.interval;
      dst->parms.scan_speed_cd = src->parms.scan_speed_cd;
      dst->parms.scan_speed_dvd = src->parms.scan_speed_dvd;

//    dst->media.type = src->media.type;
//    memcpy(dst->media.MID,src->media.MID,32);
//    dst->media.disc_type = src->media.disc_type;
//    dst->media.book_type = src->media.book_type;
//    dst->media.layers = src->media.layers;
      dst->media.capacity = src->media.capacity;

      dst->silent = src->silent;
}

void drive_info::cmd_clear(){
      for (int i=0; i<12; i++) cmd[i]=0;
}

/*
bool drive_info::lock(){
      if (!busy) {busy=true; return true; }
      else { return false; }
}

bool drive_info::unlock(){
      busy=false;
      return true;
}

bool drive_info::isBusy(){
      return busy;
}

void drive_info::wait_free(){
      while (busy);
}
*/

void spinup(drive_info* drive, unsigned char secs) {
      long st, et;
      char use_readcd = 0;
      const int  addt = 250;
      int i = 0;
      st = getmsecs() + addt;
      if ((drive->media.disc_type & DISC_CD) && (drive->capabilities & CAP_DAE)) use_readcd = 1;
      printf("SpinUp using READ%s command...\n", use_readcd ? " CD" : "" );
      seek(drive, 0);
//    if (use_readcd) read_cd(drive, 0, 1, 0xF8, 1);
      for ( et = getmsecs(); (et-st) < (secs*1000); et = getmsecs() ) {
            printf("Remaining: %.3f sec...\r", secs - ((et-st) / 1000.0));
            if (use_readcd) read_cd(drive, i*15, 15, 0xF8);
            else        read(drive, i*15, 15);
            i++;
      }
      seek(drive, 0);
      if (use_readcd)   read_cd(drive, 0, 1, 0xF8);
      else        read(drive, 0, 1);
      seek(drive, 0);
      usleep( addt );
}

int inquiry(drive_info* drive) {
      char  data[36];   
      if (drive->mmc == -1) return ERR_NO_DEV;
      drive->cmd_clear();
      drive->cmd[0] = MMC_INQUIRY;
      drive->cmd[4] = 36;
      drive->cmd[5] = 0;
      drive->err=drive->cmd.transport(READ,data,36);
      if (drive->err) return ERR_NO_SCSI;
      memcpy(drive->ven,data+8,8);
      drive->ven[8] = 0;
      memcpy(drive->dev,data+16,16);
      drive->dev[16] = 0;
      memcpy(drive->fw,data+32,4);
      drive->fw[4] = 0;
      if ((data[0]&0x1F) != 5) return ERR_NO_MMC;
      drive->mmc=1;
      return 0;
}

int test_unit_ready(drive_info* drive) {
      drive->cmd_clear();
      drive->cmd[0] = MMC_TEST_UNIT_READY;
      if ((drive->err=drive->cmd.transport(NONE, NULL, 0) )) return drive->err;
      return 0;
}

int wait_unit_ready(drive_info* drive, int secs) {
      long st, et;
      st = getmsecs();
      for ( et = getmsecs(); (et-st) < ((long)secs*1000); et = getmsecs() ) {
//          printf("Remaining: %.3f sec...\r", secs - ((et-st) / 1000.0));
            if (!test_unit_ready(drive)) return 0;
            sleep(1);
//          i++;
      }
      printf("wait_unit_ready(): Time Out (%ds)", secs);
      return 1;
}
int request_sense(drive_info* drive, char add){
      drive->cmd_clear();
      drive->cmd[0]= MMC_REQUEST_SENSE;
      drive->cmd[4]= 0x12+add;
      if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,0x12) ))
            {sperror ("REQUEST_SENSE",drive->err); return (drive->err); }
      return 0;
}

/*
int mode_sense6(drive_info* drive, int page, int page_control, short dest_len) {
      drive->cmd_clear();
      drive->cmd[0]=MMC_MODE_SENSE6;
      drive->cmd[1]= 0x10;
      drive->cmd[2]=page_control << 6 | page;
      drive->cmd[4]=dest_len & 0xFF;
      if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,dest_len) ))
            {sperror ("MODE_SENSE(6)",drive->err); return (drive->err); }
      return 0;
}
*/

int mode_sense(drive_info* drive, int page, int page_control, int dest_len) {
      drive->cmd_clear();
      drive->cmd[0]=MMC_MODE_SENSE10;
      drive->cmd[2]=page_control << 6 | page;
      drive->cmd[7]=(dest_len >> 8) & 0xFF;
      drive->cmd[8]=dest_len & 0xFF;
      if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,dest_len) ))
            {sperror ("MODE_SENSE(10)",drive->err); return (drive->err); }
      return 0;
}

/*
int mode_select6(drive_info* drive, short dest_len) {
      drive->cmd_clear();
      drive->cmd[0]=MMC_MODE_SELECT6;
//    drive->cmd[1]= 0x10;
      drive->cmd[4]=dest_len & 0xFF;
      if ((drive->err=drive->cmd.transport(WRITE,drive->rd_buf,dest_len) ))
            {sperror ("MODE_SELECT(6)",drive->err); return (drive->err); }
      return 0;
}
*/

int mode_select(drive_info* drive, int dest_len) {
      drive->cmd_clear();
      drive->cmd[0]=MMC_MODE_SELECT10;
      drive->cmd[1]= 0x10;
      drive->cmd[7]=(dest_len >> 8) & 0xFF;
      drive->cmd[8]=dest_len & 0xFF;
      if ((drive->err=drive->cmd.transport(WRITE,drive->rd_buf,dest_len) ))
            {sperror ("MODE_SELECT(10)",drive->err); return (drive->err); }
      return 0;
}

int get_configuration(drive_info* drive, int feature_number, unsigned int* data_length, int* current, unsigned char ReqType = 0x02) {
      if (data_length) *data_length = 0;
      if (current) *current = 0;
      drive->cmd_clear();
      drive->cmd[0] = MMC_GET_CONFIGURATION;
      drive->cmd[1] = ReqType;
      drive->cmd[2] = (feature_number >> 8) & 0xFF;
      drive->cmd[3] = feature_number & 0xFF;
      drive->cmd[7] = 0;
      drive->cmd[8] = 8;
      if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,8)))
            {sperror ("GET_CONFIGURATION LENGTH",drive->err);
            return (drive->err);}
      if (data_length)
      {
            *data_length = swap4(drive->rd_buf);
            drive->cmd[7] = ((*data_length+4) >> 8) & 0xFF;
            drive->cmd[8] = (*data_length+4) & 0xFF;
            if (*data_length > 4)
                  if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,*data_length+4)))
                        {sperror ("GET_CONFIGURATION",drive->err);
                        return (drive->err);}
      }
      if (current) *current = drive->rd_buf[10] & 0x01;
      return 0;
}

void detect_iface(drive_info* drive){
      unsigned int len=0;
      get_configuration(drive, FEATURE_CORE, &len, NULL);
      drive->iface_id= (drive->rd_buf[12] << 12) | (drive->rd_buf[13] << 8) | (drive->rd_buf[14] << 4) | drive->rd_buf[15];
      if (drive->iface_id<iface_id_max)
            strcpy(drive->iface,iface_list[drive->iface_id]);
      else
            strcpy(drive->iface,iface_list[iface_id_max+1]);
}

int get_mode_pages_list(drive_info* drive) {
      unsigned int len, i, ii;
      unsigned char ml=0, mn=0;
      if (!drive->silent) printf("\n** Reading supported mode pages...\n");
      if (mode_sense(drive, 0x3F, 2, 0x4000)) return 1;
      len = swap2u (drive->rd_buf);
//    printf("data len: %4X (%4d), Header:\n", len, len);
//    for (i=0; i<8; i++) printf(" 0x%02X",drive->rd_buf[i] & 0xFF); printf("\n");
      for (i=8; i<len; i+=ml) {
            mn = drive->rd_buf[i] & 0x3F;
            ml = drive->rd_buf[i+1] & 0xFF;
            ii = 0;
            while ((MODE_PAGES[ii].id != mn) && (MODE_PAGES[ii].id < 0x3F)) ii++;
            if (!drive->silent) {
                  printf("Mode Page: 0x%02X [%s]", mn, MODE_PAGES[ii].name);
//                for (ii=0; ii<(ml+2); ii++) { if (!(ii%32)) printf("\n"); printf(" %02X",drive->rd_buf[i+ii] & 0xFF); }
                  printf("\n");
            }
            ml += 2;
      }
      return 0;
}

int get_features_list(drive_info* drive) {
      unsigned int len, i, ii;
      unsigned short fn;
      unsigned char  fv;
      unsigned char  fl;
      if (!drive->silent) printf("\n** Reading supported features...\n");
      if (get_configuration(drive, 0 , &len, NULL, 0)) return 1;
#if 0 
//#ifdef FEATURE_DEBUG
      printf("data len: %4X (%4d), Header:\n", len, len);
      for (i=0; i<8; i++) printf(" 0x%02X",drive->rd_buf[i] & 0xFF); printf("\n");
#endif
      for (i=8; i<len; i+=fl) {
            fn = swap2u (drive->rd_buf+i);
            fv = drive->rd_buf[i+2];
            fl = drive->rd_buf[i+3];
            ii = 0;
            while ((FEATURES[ii].id != fn) && (FEATURES[ii].id < 0xFFFF)) ii++;
            if (!drive->silent) {
                  printf("Feature: 0x%04X, ver %2X [%s]", fn, fv, FEATURES[ii].name);
#ifdef FEATURE_DEBUG
                  for (ii=0; ii<(fl+4); ii++) { if (!(ii%32)) printf("\n"); printf(" %02X",drive->rd_buf[i+ii] & 0xFF); }
#endif
                  printf("\n");
            }
            fl += 4;
      }
      return 0;
}

int get_profiles_list(drive_info* drive) {
      unsigned int len, i, ii;
      unsigned short profile;
      if (!drive->silent) printf("\n** Reading supported profiles...\n");
      if (get_configuration(drive, FEATURE_PROFILE_LIST , &len, NULL)) return 1;

      for( i = 0; i < len-8; i+=4 ) {
            profile = swap2u (drive->rd_buf+i+12);
            ii=0;
            while ((PROFILES[ii].id != profile) && (PROFILES[ii].id < 0xFFFF)) ii++;
            if (!drive->silent) printf("Profile: 0x%04X [%s]\n", profile, PROFILES[ii].name);

            switch (profile) {
                  case 0x10:                                // DVD-ROM
                        drive->rd_capabilities |= DEVICE_DVD_ROM;
                        break;
                  case 0x11:                                // DVD-R Sequential
                        drive->rd_capabilities |= DEVICE_DVD_R;
                        drive->wr_capabilities |= DEVICE_DVD_R;
                        break;
                  case 0x12:                                // DVD-RAM
                        drive->rd_capabilities |= DEVICE_DVD_RAM;
                        drive->wr_capabilities |= DEVICE_DVD_RAM;
                        break;
                  case 0x13:                                // DVD-RW Restricted Overwrite
                        drive->rd_capabilities |= DEVICE_DVD_RW;
                        drive->wr_capabilities |= DEVICE_DVD_RW;
                        break;
                  case 0x14:                                // DVD-RW Sequential
                        drive->rd_capabilities |= DEVICE_DVD_RW;
                        drive->wr_capabilities |= DEVICE_DVD_RW;
                        break;
                  case 0x15:                                // DVD-R DL Sequential
                        drive->rd_capabilities |= (DEVICE_DVD_R_DL);
                        drive->wr_capabilities |= (DEVICE_DVD_R_DL);
                        break;
                  case 0x16:                                // DVD-R DL Layer Jump
                        drive->rd_capabilities |= (DEVICE_DVD_R_DL);
                        drive->wr_capabilities |= (DEVICE_DVD_R_DL);
                        break;
                  case 0x1A:                                // DVD+RW
                        drive->rd_capabilities |= DEVICE_DVD_PLUS_RW;
                        drive->wr_capabilities |= DEVICE_DVD_PLUS_RW;
                        break;
                  case 0x1B:                                // DVD+R
                        drive->rd_capabilities |= DEVICE_DVD_PLUS_R;
                        drive->wr_capabilities |= DEVICE_DVD_PLUS_R;
                        break;
                  case 0x2B:                                // DVD+R DL
                        drive->rd_capabilities |= (DEVICE_DVD_PLUS_R_DL);
                        drive->wr_capabilities |= (DEVICE_DVD_PLUS_R_DL);
                        break;
                  case 0x08:                                // CD-ROM
                        drive->rd_capabilities |= DEVICE_CD_ROM;
                        drive->wr_capabilities |= DEVICE_CD_ROM;
                        break;
                  case 0x09:                                // CD-R
                        drive->rd_capabilities |= DEVICE_CD_R;
                        drive->wr_capabilities |= DEVICE_CD_R;
                        break;
                  case 0x0A:                                // CD-RW
                        drive->rd_capabilities |= DEVICE_CD_RW;
                        drive->wr_capabilities |= DEVICE_CD_RW;
                        break;
            }
      }
      profile = swap2(drive->rd_buf+6);
      ii=0;
      while ((PROFILES[ii].id != profile) && (PROFILES[ii].id < 0xFFFF)) ii++;
      if (!drive->silent) printf("Current: 0x%04X [%s]\n", profile, PROFILES[ii].name);

      return 0;
}

void detect_capabilities(drive_info* drive){
      unsigned int      len=4;
      drive->capabilities=CAP_SET_CD_SPEED;
      drive->rd_capabilities=0;
      drive->wr_capabilities=0;
      detect_mm_capabilities(drive);
      get_mode_pages_list(drive);
      if (drive->mmc>1) {
            // LU is MMC2 or later. Detecting capabilities by GET_CONFIGURATION
            get_profiles_list(drive);
            get_features_list(drive);
            get_configuration(drive, FEATURE_REMOVABLE_MEDIA , &len, NULL);
            if (len >= 0x0C) drive->capabilities|=CAP_REMOVABLE_MEDIA;
            get_configuration(drive, FEATURE_SMART , &len, NULL);
            if (len >= 0x08) drive->capabilities|=CAP_SMART;
            get_configuration(drive, FEATURE_MICROCODE_UPGRADE , &len, NULL);
            if (len >= 0x08) drive->capabilities|=CAP_MICROCODE_UPGRADE;
            get_configuration(drive, FEATURE_MORPHING , &len, NULL);
            if (len >= 0x08) drive->capabilities|=CAP_MORPHING;
            get_configuration(drive, FEATURE_POWER_MANAGEMENT , &len, NULL);
            if (len >= 0x08) drive->capabilities|=CAP_POWER_MANAGEMENT;
            get_configuration(drive, FEATURE_EMBEDDED_CHANGER , &len, NULL);
            if (len >= 0x08) drive->capabilities|=CAP_EMBEDDED_CHANGER;
            get_configuration(drive, FEATURE_DEFECT_MANAGEMENT , &len, NULL);
            if (len >= 0x08) drive->capabilities|=CAP_DEFECT_MANAGEMENT;
            get_configuration(drive, FEATURE_REAL_TIME_STREAMING , &len, NULL);
            if (len >= 0x08) drive->capabilities|=CAP_REAL_TIME_STREAMING;
            get_configuration(drive, FEATURE_MRW , &len, NULL);
            if (len >= 0x0C) {
                  drive->rd_capabilities|=DEVICE_MRW;
                  if (drive->rd_buf[12]&0x01) drive->wr_capabilities|=DEVICE_MRW;
            }
            get_configuration(drive, FEATURE_CD_READ , &len, NULL); // LU can operate with CD's
            if (len >= 0x0C) {
//                drive->rd_capabilities|=DEVICE_CD_ROM;
                  if (drive->rd_buf[12]&0x1) drive->capabilities|=CAP_CD_TEXT;
                  if (drive->rd_buf[12]&0x2) drive->capabilities|=CAP_C2;
            }
            get_configuration(drive, FEATURE_DVD_READ , &len, NULL); // LU can operate with DVD's
            if (len >= 0x08) {
                  if ((drive->rd_buf[10] >> 2) > 0) drive->mmc=5;
                  if (len >= 0x0C) {
                      if (drive->rd_buf[12]&0x01) {
                              drive->rd_capabilities|=DEVICE_DVD_RW;
                        //    drive->rd_capabilities|=DEVICE_DVD_R_DL;
                        }
                        if (drive->rd_buf[14]&0x01) drive->rd_capabilities|=DEVICE_DVD_R_DL;
                  }
                  get_configuration(drive, FEATURE_DVD_CPRM , &len, NULL);
                  if (len >= 0x08) drive->capabilities|=CAP_DVD_CPRM;
                  get_configuration(drive, FEATURE_DVD_CSS , &len, NULL);
                  if (len >= 0x08) drive->capabilities|=CAP_DVD_CSS;
                  get_configuration(drive, FEATURE_DVD_R_RW_WRITE , &len, NULL);
                  if (len >= 0x08) {
                        drive->wr_capabilities|=DEVICE_DVD_R;
                        if (drive->rd_buf[12]&0x02) drive->wr_capabilities|=DEVICE_DVD_RW;
//                      if (drive->rd_buf[12]&0x04) drive->wr_capabilities|=DEVICE_DVD_R_DL;
                  }
                  get_configuration(drive, FEATURE_LAYER_JUMP_RECORDING , &len, NULL);
                  if (len >= 0x08) drive->wr_capabilities|=DEVICE_DVD_R_DL;

                  get_configuration(drive, FEATURE_DVD_PLUS_R , &len, NULL);
                  if (len >= 0x08) {
//                      drive->mmc=4;
                        drive->rd_capabilities|=DEVICE_DVD_PLUS_R;
                        if (drive->rd_buf[12]&0x01) drive->wr_capabilities|=DEVICE_DVD_PLUS_R;
                  }
                  get_configuration(drive, FEATURE_DVD_PLUS_RW , &len, NULL);
                  if (len >= 0x0C) {
                        drive->rd_capabilities|=DEVICE_DVD_PLUS_RW;
                        if (drive->rd_buf[12]&0x01) drive->wr_capabilities|=DEVICE_DVD_PLUS_RW;
                  }
                  get_configuration(drive, FEATURE_DVD_PLUS_R_DOUBLE_LAYER , &len, NULL);
                  if (len >= 0x0C) {
//                      drive->mmc=5;
                        drive->rd_capabilities|=DEVICE_DVD_PLUS_R_DL;
                        if (drive->rd_buf[12]&0x01) drive->wr_capabilities|=DEVICE_DVD_PLUS_R_DL;
                  }
            }
            get_configuration(drive, FEATURE_DDCD_READ , &len, NULL);  // LU can Reed/Write DDCD's
            if (len >= 0x0C) {
                  drive->rd_capabilities|=DEVICE_DDCD_R;
                  drive->rd_capabilities|=DEVICE_DDCD_RW;
                  get_configuration(drive, FEATURE_DDCD_R_WRITE , &len, NULL);
                  if (len >= 0x0C) drive->wr_capabilities|=DEVICE_DDCD_R;
                  get_configuration(drive, FEATURE_DDCD_RW_WRITE , &len, NULL);
                  if (len >= 0x0C) drive->wr_capabilities|=DEVICE_DDCD_RW;
            }
      if (!drive->silent) printf("** Device is MMC-%d\n",drive->mmc);
      }
}

int read_atip(drive_info* drive) {
      unsigned char     data[4];
      int   size = 0;
      int   i;
      drive->ATIP_len = 0;
      drive->cmd_clear();
      drive->cmd[0]=MMC_READ_TOC_PMA_ATIP;
      drive->cmd[1]=0;
      drive->cmd[2]=  4; // ATIP
      drive->cmd[3]=0;
      drive->cmd[8]=4;
      if ((drive->err=drive->cmd.transport(READ,data,4) ))
            {if (!drive->silent) sperror ("READ_ATIP",drive->err); drive->ATIP_len = 0; return 1;}
      size = swap2u((char*)data);
      size += 2;
      drive->cmd_clear();
      drive->cmd[0]=MMC_READ_TOC_PMA_ATIP;
      drive->cmd[1]=0;
      drive->cmd[2]=  4; // ATIP
      drive->cmd[3]=0;
      drive->cmd[7]=(size >> 8) & 0xFF;
      drive->cmd[8]=size & 0xFF;
      if ((drive->err=drive->cmd.transport(READ,drive->ATIP,size) ))
            {sperror ("READ_ATIP",drive->err); drive->ATIP_len = 0; return 1;}
      drive->ATIP_len = size;
      if (!drive->silent) {
            printf("ATIP (%d bytes):\n",size);
            for (i=0; i<(min(size, 4)); i++) printf(" %3d (%02X)",drive->ATIP[i],drive->ATIP[i]);
            if (size > 4) for (i=0; i<(size-4); i++) {
                  if (!(i % 8)) printf("\n");
                  else if (!(i % 4)) printf("      ");
                  printf(" %3d (%02X)",drive->ATIP[i+4] & 0xFF,drive->ATIP[i+4] & 0xFF);
            }
            printf("\n");
      }
      return 0;
}

int read_toc(drive_info* drive) {
      unsigned char     data[4];
      int   size = 0;
      int   i;
      drive->cmd_clear();
      drive->cmd[0]=MMC_READ_TOC_PMA_ATIP;
      drive->cmd[1]=0;
      drive->cmd[2]=  0; // TOC
      drive->cmd[3]=0;
      drive->cmd[8]=4;
      if ((drive->err=drive->cmd.transport(READ,data,4) ))
            {sperror ("READ_TOC",drive->err); return 1;}
//    if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,2048) ))
//          {sperror ("READ_TOC",drive->err); return 1;}
      size = swap2u((char*)data);
      size += 2;

      drive->cmd_clear();
      drive->cmd[0]=MMC_READ_TOC_PMA_ATIP;
      drive->cmd[1]=0;
      drive->cmd[2]=  0; // TOC
      drive->cmd[3]=0;
      drive->cmd[7]=(size >> 8) & 0xFF;
      drive->cmd[8]=size & 0xFF;
      if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,size) ))
            {if (!drive->silent) sperror ("READ_TOC",drive->err); return 1;}

      if (!drive->silent) {
            printf("TOC (%d bytes):\n",size);
            for (i=0; i<(min(size, 4)); i++) printf(" %3d (%02X)",drive->rd_buf[i] & 0xFF,drive->rd_buf[i] & 0xFF);
            if (size > 4) for (i=0; i<(size-4); i++) {
                  if (!(i % 8)) printf("\n");
                  else if (!(i % 4)) printf("      ");
                  printf(" %3d (%02X)",drive->rd_buf[i+4] & 0xFF,drive->rd_buf[i+4] & 0xFF);
            }
            printf("\n");
      }
      return 0;
}

int read_capacity(drive_info* drive) {
      unsigned char data[8]; memset(data, 0, 8);
      unsigned int ccity,bsize;
      drive->cmd_clear();
      drive->cmd[0] = MMC_READ_RECORDED_CAPACITY;
      drive->cmd[9] = 0;
      drive->cmd.transport (READ,data,8);
      ccity = data[0]<<24|data[1]<<16|data[2]<<8|data[3], ccity++;
        bsize = data[4]<<24|data[5]<<16|data[6]<<8|data[7];
      drive->media.capacity = ccity; //capacity in blocks
      lba2msf(&drive->media.capacity,&drive->media.capacity_msf);
      drive->media.sectsize = bsize; //block size
        return 0;
}

int read_track_info(drive_info* drive, trk* track, unsigned int track_n){
      int size = 2048;
      drive->cmd_clear();
      drive->cmd[0] = MMC_READ_TRACK_INFORMATION;
      drive->cmd[1] = 0x01;
      drive->cmd[2] = (track_n >> 24) & 0xFF;
      drive->cmd[3] = (track_n >> 16) & 0xFF;
      drive->cmd[4] = (track_n >> 8) & 0xFF;
      drive->cmd[5] = track_n & 0xFF ;
      drive->cmd[7] = (size >> 8) & 0xFF ;
      drive->cmd[8] = size & 0xFF ;
      if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,size) ))
            {if (!drive->silent) sperror ("READ_TRACK_INFO",drive->err); return 1;}
      
//    int i,
      int len;
      len = ( drive->rd_buf[0] << 8 ) | drive->rd_buf[1];
/*    printf("\nTrack #%d info:\n  ",track->n);
      for (i=0; i<len+2; i++) { printf(" 0x%02X",drive->rd_buf[i] & 0xFF); if (!((i+1)%8)) printf("\n  ");}
      if (((i)%8)) printf("\n");*/

      track->n = ((drive->rd_buf[32]&0xFF) << 8) | (drive->rd_buf[2]&0xFF);
      track->session = ((drive->rd_buf[33]&0xFF) << 8) | (drive->rd_buf[3]&0xFF);
      track->track_mode = drive->rd_buf[5] & 0x0F;
      track->data_mode = drive->rd_buf[6] & 0x0F;
      track->start = ((drive->rd_buf[8]&0xFF) << 24) | ((drive->rd_buf[9]&0xFF) << 16) |
            ((drive->rd_buf[10]&0xFF) << 8) | (drive->rd_buf[11]&0xFF);
      track->next_writable = ((drive->rd_buf[12]&0xFF) << 24) | ((drive->rd_buf[13]&0xFF) << 16) |
            ((drive->rd_buf[14]&0xFF) << 8) | (drive->rd_buf[15]&0xFF);
      track->free = ((drive->rd_buf[16]&0xFF) << 24) | ((drive->rd_buf[17]&0xFF) << 16) |
            ((drive->rd_buf[18]&0xFF) << 8) | (drive->rd_buf[19]&0xFF);
      track->size = ((drive->rd_buf[24]&0xFF) << 24) | ((drive->rd_buf[25]&0xFF) << 16) |
            ((drive->rd_buf[26]&0xFF) << 8) | (drive->rd_buf[27]&0xFF);
      track->last_recorded = ((drive->rd_buf[28]&0xFF) << 24) | ((drive->rd_buf[29]&0xFF) << 16) |
            ((drive->rd_buf[30]&0xFF) << 8) | (drive->rd_buf[31]&0xFF);
      track->end = track->start+track->size-1;

      lba2msf(&track->start,&track->msf_start);
      lba2msf(&track->next_writable,&track->msf_next);
      lba2msf(&track->last_recorded,&track->msf_last);
      lba2msf(&track->end,&track->msf_end);
      lba2msf(&track->size,&track->time);

      return 0;
}

int get_track_list(drive_info* drive){
      int i;
      if (drive->media.disc_type & DISC_CD) {
            if (!drive->silent) printf("Get CD track list\n");
            if (read_toc(drive)) {
                  printf("Error reading TOC :(\n");
                  drive->media.tracks = 0;
            } else {
//                drive->media.tracks = 0;
                  drive->media.tracks = drive->rd_buf[3] & 0xFF;
                  for (i=0; i<drive->media.tracks; i++) {
                        drive->media.track[i].n = i+1;
                        drive->media.track[i].session = 1;
                        drive->media.track[i].start = swap4(drive->rd_buf+i*8+8);
                        drive->media.track[i].end   = swap4(drive->rd_buf+i*8+16);
                        drive->media.track[i].size = drive->media.track[i].end - drive->media.track[i].start;
                        drive->media.track[i].free = 0;
                        drive->media.track[i].last_recorded = 0;
                        drive->media.track[i].track_mode = drive->rd_buf[i*8+5] & 0x0F;
//                      drive->media.track[i].data_mode = 0;
                        drive->media.track[i].data_mode = (drive->rd_buf[i*8+5] >> 4) & 0x0F;

                        lba2msf(&drive->media.track[i].start, &drive->media.track[i].msf_start);
                        lba2msf(&drive->media.track[i].next_writable, &drive->media.track[i].msf_next);
                        lba2msf(&drive->media.track[i].last_recorded, &drive->media.track[i].msf_last);
                        lba2msf(&drive->media.track[i].end,  &drive->media.track[i].msf_end);
                        lba2msf(&drive->media.track[i].size, &drive->media.track[i].time);
                  }
                  printf("tracks: %d\n",drive->media.tracks);
            }
      } else if (drive->media.disc_type & DISC_DVD) {
            printf("Get DVD track list\n");
            for (i=0; i<drive->media.tracks; i++) {
//                track.n = ++i;
                  read_track_info(drive, &drive->media.track[i], i+1);

            }
            if (!drive->silent) printf("tracks: %d\n",drive->media.tracks);
      }
      if ((drive->media.tracks) && (!drive->silent)) for (i=0; i<drive->media.tracks; i++) {
                  printf("\nTrack #  : %d\n",   drive->media.track[i].n);
                  printf("Session #: %d\n",     drive->media.track[i].session);
                  printf("Track mode    : %d\n",drive->media.track[i].track_mode);
                  printf("Data mode     : %d\n",drive->media.track[i].data_mode);
                  printf("Track start   : %d\n",drive->media.track[i].start);
                  printf("Next writable : %d\n",drive->media.track[i].next_writable);
                  printf("Free          : %d\n",drive->media.track[i].free);
                  printf("Size          : %d\n",drive->media.track[i].size);
                  printf("Last recorded : %d\n",drive->media.track[i].last_recorded);
      }
      return 0;
}

int read_free(drive_info* drive) {
      trk track;
      if (drive->media.dstatus == 2) {
            drive->media.capacity_free = 0;
            return 0;
      }
      if (drive->media.disc_type & DISC_CD) {
            if (((drive->media.last_lead_out >> 24) & 0xFF ) == 0xFF) {
                  drive->media.capacity_free = 0;
                  return 0;
            } else {
                  drive->media.capacity_free = drive->media.last_lead_out - drive->media.capacity - 150;
                  lba2msf(&drive->media.capacity_free,&drive->media.capacity_free_msf);
                  return 0;
            }
      } else if (drive->media.disc_type & DISC_DVD) {
//          track.n = drive->media.sessions+1;
            read_track_info(drive, &track, drive->media.sessions+1);
            drive->media.capacity_free = track.free;
            return 0;
      }
      drive->media.capacity_free = 0;
      return 1;
}

int read_disc_information(drive_info* drive) {
      int i=0,len=0;
      drive->cmd_clear();
      drive->cmd[0] = MMC_READ_DISC_INFORMATION;
      drive->cmd[7] = 0x08;
      drive->cmd[8] = 0x00;
      drive->cmd.transport (READ,drive->rd_buf,2048);
      len= (drive->rd_buf[0]<<8)|drive->rd_buf[1];
      if (!drive->silent) printf("Disc info length: 0x%04X\n  ",len);
      if (len!=0x20) {
            drive->media.erasable = 0;
            drive->media.dstatus = 0;
            drive->media.sstatus = 0;
            drive->media.sessions = 0;
            drive->media.tracks = 0;
            return 1;
      }
      if (!drive->silent) for (i=0; i<len+2; i++) {
            printf(" 0x%02X",drive->rd_buf[i] & 0xFF);
            if (!((i+1)%8)) printf("\n  ");
      }
      if (((i)%8)) printf("\n");
      drive->media.erasable = (drive->rd_buf[2]&0x10);
      drive->media.dstatus = drive->rd_buf[2]&0x03;
      drive->media.sstatus = (drive->rd_buf[2]>>2)&0x03;
      drive->media.sessions = (drive->rd_buf[4]|(drive->rd_buf[9]<<8));
//    if (!drive->media.sstatus) drive->media.sessions--;
      drive->media.tracks = drive->rd_buf[6]|(drive->rd_buf[11]<<8);
      if (!drive->silent) {
            printf("   first track# on disc: %d\n", drive->rd_buf[3]);
            printf("   first track# in last session: %d\n", drive->rd_buf[5]|(drive->rd_buf[10]<<8));
            printf("   last  track# in last session: %d\n", drive->media.tracks);
            printf("   disc type: %02X\n", drive->rd_buf[8]&0xFF);
            printf("   disc ID: %02X%02X%02X%02X\n",
                  drive->rd_buf[12],drive->rd_buf[13],drive->rd_buf[14],drive->rd_buf[15]);
            printf("   Last session  lead-in  start: %d:%02d.%02d\n",
                  (drive->rd_buf[16]<<8)|drive->rd_buf[17],drive->rd_buf[18],drive->rd_buf[19]);
            drive->media.last_lead_out = (((drive->rd_buf[20]&0xFF) << 8) | (drive->rd_buf[21]&0xFF))*75*60 + ((drive->rd_buf[22]&0xFF)*75) + (drive->rd_buf[23]&0xFF);
            printf("   Last possible lead-out start: %d:%02d.%02d (sector 0x%08X)\n",
                  (drive->rd_buf[20]<<8)|drive->rd_buf[21],drive->rd_buf[22],drive->rd_buf[23],drive->media.last_lead_out);
      }
      if (!drive->media.sstatus) {
            drive->media.sessions--;
            drive->media.tracks--;
      }
      return 0;
}

void read_disc_regions(drive_info* drive){
//#warning "read_disc_regions()"
      int len=8;
      unsigned char enc;
      unsigned char regmask;
      int i;
      drive->cmd_clear();
      drive->cmd[0] = MMC_READ_DVD_STRUCTURE;
      drive->cmd[7] = 0x01;
      drive->cmd[8] = len>>8;
      drive->cmd[9] = len & 0xFF;
      drive->cmd[11] = 0;
      if (( drive->err = drive->cmd.transport(READ,drive->rd_buf,len) ))
            { if (!drive->silent) sperror ("READ_DISC_REGIONS",drive->err); return; }

      if (!drive->silent) {
            printf("READ_DISC_REGIONS data: ");
            for(i=0; i<len ;i++) printf(" %02X",drive->rd_buf[i] & 0xFF);
            printf("\n");
      }

      enc = drive->rd_buf[5];
      regmask = drive->rd_buf[5];

      printf("Disc is %sprotected\n", enc ? "" : "NOT ");
      printf("Disc regions       : ");
      if (regmask != 0xFF) {
            for (i=0; i<8; i++)
                  if (!((regmask >> i) & 1))
                        {printf("%d",i+1); drive->rpc.region = i+1;}
            printf("\n");
      } else
            printf("does not set\n");
}

void read_rpc_state(drive_info* drive){
      int len=8;
      int i;
      unsigned char regmask;
      unsigned char t;//,vl,ul;
      unsigned char sh;

      if (!(drive->rd_capabilities & DEVICE_DVD)) 
            {drive->rpc.phase = 0; return;}

      drive->cmd_clear();
      drive->cmd[0] = MMC_REPORT_KEY;
      drive->cmd[8] = len>>8;
      drive->cmd[9] = len & 0xFF;
      drive->cmd[10] = 0x08;
      drive->cmd[11] = 0;
      if (( drive->err = drive->cmd.transport(READ,drive->rd_buf,len) ))
            { if (drive->err == 0x52400) 
                  {printf("\n** Unit is RPC-I\n"); drive->rpc.phase = 1; }
            else
                  {if (!drive->silent) sperror ("READ_RPC_STATE",drive->err);  drive->rpc.phase = 0; }
            return; }
/*    printf("MMC_REPORT_KEY data: ");
      for(i=0; i<len ;i++) printf(" %02X",drive->rd_buf[i] & 0xFF);
      printf("\n");*/
      if (swap2(drive->rd_buf) < 6) return;
      
      drive->rpc.ch_u = drive->rd_buf[4] & 0x07;
      drive->rpc.ch_v = (drive->rd_buf[4] >> 3) & 0x07;
      t  = (drive->rd_buf[4] >> 6) & 0x03;
      regmask = drive->rd_buf[5];
      sh = drive->rd_buf[6];

      drive->rpc.phase = 2;
      printf("\n** Unit is RPC-II\n");
      printf("Current region     : ");
      if (regmask != 0xFF) {
            for (i=0; i<8; i++)
                  if (!((regmask >> i) & 1))
                        {printf("%d",i+1); drive->rpc.region = i+1;}
            printf("\n");
      } else
            printf("does not set\n");
      printf("User changes left  : %d\n",drive->rpc.ch_u);
      printf("Vendor resets left : %d\n",drive->rpc.ch_v);
}

int determine_cd_type(drive_info* drive) {
//    unsigned char*    ATIP;
//    int         ATIP_len;
//    int         i;
      int ratip = read_atip(drive);
      if (ratip) {
            if (!drive->silent) printf("no ATIP found, assuming disc type: CD-ROM\n");
            return DISC_CDROM; // CD-ROM
//    } else {
//          drive->ATIP_len += 4;
      }
      if (drive->ATIP_len < 8) {
            if (!drive->silent) printf("ATIP too small, assuming disc type: CD-ROM\n");
            return DISC_CDROM; // CD-ROM
      }
/*
      printf("ATIP_len=%d\nATIP data:",drive->ATIP_len);
      for (i=0; i< drive->ATIP_len; i++) printf("%4d",(drive->ATIP[i])&0xFF);
      printf("\n");
*/
      // CD-RW?
      int cdrw = !!(drive->ATIP[6] & 0x40);
      int cdrw_subtype = (drive->ATIP[6] & 0x38) >> 3;
      if (cdrw) {
            if (!drive->silent) printf("disc type: CD-RW\n");
            switch (cdrw_subtype) {
                  case 0: return DISC_CDRW | DISC_CDRWMS; break;
                  case 1: return DISC_CDRW | DISC_CDRWHS; break;
                  case 2: return DISC_CDRW | DISC_CDRWUS; break;
                  case 3: return DISC_CDRW | DISC_CDRWUSP; break;
                  default: return DISC_CDRW;
            }
      }
      if (!drive->silent) printf("disc type: CD-R\n");
      return DISC_CDR;
}

int read_mediaid_dvd(drive_info* drive){
      int         i;
      unsigned int      len;
      char        header[40];
      union { unsigned char _e[4+40],_11[4+256]; } dvd;
      unsigned char     format; // 0x11 +, 0x0E -
      if (drive->media.disc_type & DISC_DVDminus)
            format=0x0E;
      else
            format=0x11;
      drive->cmd_clear();
      drive->cmd[0] = MMC_READ_DVD_STRUCTURE;
      drive->cmd[7] = format;
      drive->cmd[9] = 4;
      drive->cmd[11] = 0;
      drive->err = drive->cmd.transport(READ,header,4);//))
      len = (header[0]<<8|header[1]) + 2;
      if (len>sizeof(dvd)) len=sizeof(dvd);
      drive->cmd_clear();
      drive->cmd[0] = MMC_READ_DVD_STRUCTURE;
      drive->cmd[7] = format;
      drive->cmd[8] = len>>8;
      drive->cmd[9] = len;
      drive->cmd[11] = 0;
      drive->err = drive->cmd.transport(READ,&dvd,len);
      drive->media.MID[0] = 0;
      if (drive->media.disc_type & DISC_DVDminus) {
            memcpy(drive->media.MID,dvd._e+21,6);
            drive->media.MID[6]='/';
            memcpy(drive->media.MID+7,dvd._e+29,6);
            drive->media.MID[12]=0;
//          drive->media.MID[12]='/';
//          memcpy(drive->media.MID+13,dvd._e+37,6);
//          drive->media.MID[18]=0;
      } else {
            memcpy(drive->media.MID,dvd._11+23,8);
            drive->media.MID[8]='/';
            memcpy(drive->media.MID+9,dvd._11+31,3);
            drive->media.MID[12]=0;
//          for (i=12; i<19; i++) drive->media.MID[i]=0;
      }
      for (i=0; i<12; i++) if(drive->media.MID[i] == 0) drive->media.MID[i]=0x20;
      return 0;
}

int read_mediaid_cd(drive_info* drive)
{
//    printf("read_mediaid_cd()\n");
      msf   lin;
      int type;
//    int atippr = read_atip(drive);
//    if (!atippr) drive->ATIP_len+=4; else return 1;
      if (!drive->ATIP_len) return 1;
      lin.m=drive->ATIP[8];
      lin.s=drive->ATIP[9];
      lin.f=drive->ATIP[10];
      type = lin.f % 10;
      lin.f -= type;
      int idx=0;
      int nf=1;
      while (mi[idx].lin.m && nf)
            if (lin.m == mi[idx].lin.m && lin.s == mi[idx].lin.s && lin.f == mi[idx].lin.f) nf=0;
            else idx++;
      
//    strncpy(drive->media.MID,mi[idx].name,47));
      sprintf(drive->media.MID,"[%02d:%02d.%02d] %s",lin.m,lin.s,lin.f,mi[idx].name);
      return 0;
}

int determine_disc_type(drive_info* drive) {
      int current = 0;
//    int i=0;
      drive->media.disc_type = DISC_NODISC;
//    drive->media.type = Media_NoMedia;
      if (drive->mmc>1) {
            get_configuration(drive, FEATURE_PROFILE_LIST, NULL, &current);
            switch (drive->rd_buf[7]) {
                  case 0: drive->media.disc_type = DISC_NODISC; break;
                  case PROFILE_CD_ROM:          drive->media.disc_type = DISC_CDROM; break;
                  case PROFILE_CD_R:            drive->media.disc_type = DISC_CDR; break;
                  case PROFILE_CD_RW:           drive->media.disc_type = DISC_CDRW; break;
                  case PROFILE_DVD_ROM:         drive->media.disc_type = DISC_DVDROM; break;
                  case PROFILE_DVD_R_SEQ:       drive->media.disc_type = DISC_DVDminusR; break;
                  case PROFILE_DVD_RAM:         drive->media.disc_type = DISC_DVDRAM; break;
                  case PROFILE_DVD_RW_RESTOV:   drive->media.disc_type = DISC_DVDminusRWR; break;
                  case PROFILE_DVD_RW_SEQ:      drive->media.disc_type = DISC_DVDminusRWS; break;
                  case PROFILE_DVD_R_DL_SEQ:    drive->media.disc_type = DISC_DVDminusRDL; break;
                  case PROFILE_DVD_R_DL_JUMP:   drive->media.disc_type = DISC_DVDminusRDLJ; break;
                  case PROFILE_DVD_PLUS_RW:     drive->media.disc_type = DISC_DVDplusRW; break;
                  case PROFILE_DVD_PLUS_R:      drive->media.disc_type = DISC_DVDplusR; break;
                  case PROFILE_DVD_PLUS_R_DL:   drive->media.disc_type = DISC_DVDplusRDL; break;

                  default: drive->media.disc_type = DISC_UN; break;
            }
            if (!drive->media.disc_type) return 0;
            read_disc_information(drive);
            if (drive->media.disc_type & DISC_CD) {
                  drive->media.disc_type = determine_cd_type(drive);
                  read_mediaid_cd(drive);
                  if (!drive->silent) printf("** MID: '%s'\n",drive->media.MID);
                  return 0;
            } else if (drive->media.disc_type & DISC_DVD) {
//                drive->media.type=Media_DVD;
                  drive->rd_buf[4]=0;
                  drive->cmd_clear();
                  drive->cmd[0] = MMC_READ_DVD_STRUCTURE;
                  drive->cmd[7] = 0;//0x11; //dvd_dash;
                  drive->cmd[9] = 36;
                  drive->cmd[11] = 0;
                  if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,36))) 
                        if (!drive->silent) sperror ("READ_DVD_STRUCTURE",drive->err);
                  drive->media.book_type = (drive->rd_buf[4] & 0xFF);
                  drive->media.layers = 1 + ((drive->rd_buf[6] & 0x60) >> 5);
                  read_mediaid_dvd(drive);
                  if (!drive->silent) printf("** MID: '%s'\n",drive->media.MID);
                  if ((!(drive->wr_capabilities & DEVICE_DVD))||(drive->media.disc_type & DISC_DVDROM)) {
                        if (!drive->silent) {
                              printf("Device can't write DVD's or media detected as DVD-ROM,\n");
                              printf("trying to corectly detect DVD type...\n");
                        }
                        switch ((drive->media.book_type>>4)&0x0F){
                              case BOOK_DVD_R:
                                    if (drive->media.layers == 1) 
                                          drive->media.disc_type = DISC_DVDminusR;
                                    else
                                          drive->media.disc_type = DISC_DVDminusRDL;
                                    break;
                              case BOOK_DVD_RW:
                                    drive->media.disc_type = DISC_DVDminusRWS; break;
                              case BOOK_DVD_PR:
                                    drive->media.disc_type = DISC_DVDplusR; break;
                              case BOOK_DVD_PRW:
                                    drive->media.disc_type = DISC_DVDplusRW; break;
                              case BOOK_DVD_PR_DL:
                                    drive->media.disc_type = DISC_DVDplusRDL; break;
                              case BOOK_DVD_ROM:
                                    if (strncmp(drive->media.MID,"        /   ",12)) {
                                          if (!drive->silent) printf("MID found:)\n");
                                          if (drive->media.erasable) {
                                                drive->media.disc_type = DISC_DVDplusRW;
                                          } else {
                                                if (drive->media.layers == 1)
                                                      drive->media.disc_type = DISC_DVDplusR;
                                                else
                                                      drive->media.disc_type = DISC_DVDplusRDL;
                                          }
                                    }
                                    break;
                              default:
                                    break;
                        }
                  }
                  read_writer_info(drive);
                  if (!drive->silent) printf("** Writer used: '%s'\n",drive->media.writer);
/*
                  read_disc_regions(drive);
                  printf("DVD Copyright info: ");
                  for (i=0;i<4;i++) printf("0x%02X ",drive->rd_buf[i]);
                  printf("\n");
*/
                  return 0;
            }
      } else {
            read_capacity(drive);
            if (drive->media.capacity) {
//                drive->media.type=Media_CD;
                  drive->media.disc_type = DISC_CDROM;
                  read_disc_information(drive);
            }
            return 0;
      }
      return 1;
}

int get_spindown(drive_info* drive) {
      mode_sense(drive, 0x0D, 00, 192);
      if (drive->err)
            {drive->parms.spindown_idx=spindowns; return (drive->err);}
      drive->parms.spindown_idx = drive->rd_buf[11] & 0x0F;
      return 0;
}

int set_spindown(drive_info* drive) {
      int   i;
      for (i=0; i<16; i++) drive->rd_buf[i]=0;
      drive->rd_buf[8] = 0x0D;
      drive->rd_buf[9] = 0x06;
      drive->rd_buf[11] = drive->parms.spindown_idx & 0x0F;
      drive->rd_buf[13] = 0x3C;
      drive->rd_buf[15] = 0x4B;
      mode_select(drive, 16);
      return 0;
}

int get_performance(drive_info* drive) {
      const int max_descs=52;
      const int desc_len=16;
      int   len, descn;
//    int   i;
      int   j,offs;
      drive->cmd_clear();
      drive->cmd[0] = MMC_GET_PERFORMANCE;
      drive->cmd[1] = 0x00;
      drive->cmd[8] = (max_descs >> 8) & 0xFF;
      drive->cmd[9] = max_descs & 0xFF;
      if ((drive->err=drive->cmd.transport(READ,drive->rd_buf, 1024)))
            { sperror ("GET_PERFORMANCE",drive->err); return (drive->err); }
//    return 1;
      len = (drive->rd_buf[0]<<24) | (drive->rd_buf[1]<<16) | (drive->rd_buf[2]<<8) | (drive->rd_buf[3]);
      descn = len/desc_len;
//    printf("Performance data length: %d; decriptors: %d\n",len, descn);

//    printf("GET_PERFORMANCE response dump:\n");
//    for (j=0; j*8<len; j++) {
//          for (i=0; i<8; i++) printf(" 0x%02X",drive->rd_buf[i]);
//          printf("\n");
//    }
      for (j=0; j<descn; j++) {
            offs = 8+j*desc_len;
            printf("\tDescriptor #%02d:",j);
//          for (i=0; i<desc_len; i++)  printf(" 0x%02X",(drive->rd_buf[offs+i])&0xFF);
//          printf("\n");
            drive->perf.lba_s = ((drive->rd_buf[offs]<<24)&0xFF000000) | ((drive->rd_buf[offs+1]<<16)&0xFF0000) |
                   ((drive->rd_buf[offs+2]<<8)&0xFF00) | ((drive->rd_buf[offs+3])&0xFF);
            offs = 8+j*desc_len+4;
            drive->perf.spd_s = ((drive->rd_buf[offs]<<24)&0xFF000000) | ((drive->rd_buf[offs+1]<<16)&0xFF0000) |
                   ((drive->rd_buf[offs+2]<<8)&0xFF00) | ((drive->rd_buf[offs+3])&0xFF);
            offs = 8+j*desc_len+8;
            drive->perf.lba_e = ((drive->rd_buf[offs]<<24)&0xFF000000) | ((drive->rd_buf[offs+1]<<16)&0xFF0000) |
                   ((drive->rd_buf[offs+2]<<8)&0xFF00) | ((drive->rd_buf[offs+3])&0xFF);
            offs = 8+j*desc_len+12;
            drive->perf.spd_e = ((drive->rd_buf[offs]<<24)&0xFF000000) | ((drive->rd_buf[offs+1]<<16)&0xFF0000) |
                   ((drive->rd_buf[offs+2]<<8)&0xFF00) | ((drive->rd_buf[offs+3])&0xFF);
            printf("\t%dkB/s@%d -> %dkB/s@%d\n",
                  drive->perf.spd_s,drive->perf.lba_s,drive->perf.spd_e,drive->perf.lba_e);
      }
      return 0;
}

int get_write_speed(drive_info* drive) {
      int   offs;
      mode_sense(drive, 0x2A, 00, 256);
      offs=0; while (((drive->rd_buf[offs]) & 0x3F) != 0x2A) offs++;
      drive->parms.write_speed_kb = swap2(drive->rd_buf+offs+28);
      return 0;
}

int get_write_speed_tbl(drive_info* drive) {
      int   offs;
      int   i, spdcnt;
      mode_sense(drive, 0x2A, 00, 256);
      offs=0; while (((drive->rd_buf[offs]) & 0x3F) != 0x2A) offs++;
//    drive->parms.write_speed_kb = swap2(drive->rd_buf+offs+28);
      spdcnt = swap2(drive->rd_buf+offs+30);
      for (i=0; i<speed_tbl_size;i++)
            drive->parms.wr_speed_tbl_kb[i] = 0;
//    printf("== Write speeds: %d\n",spdcnt);
      for (i=0; (i<spdcnt) && (i<speed_tbl_size); i++) {
            drive->parms.wr_speed_tbl_kb[i] = swap2(drive->rd_buf+offs+32+i*4+2);
//          printf("  Speed #%02d: %d kB/s\n",i,drive->parms.wr_speed_tbl_kb[i]);
      }
      return 0;
}

int get_read_speed(drive_info* drive) {
      int   offs;
      mode_sense(drive, 0x2A, 00, 256);
      offs=0; while (((drive->rd_buf[offs]) & 0x3F) != 0x2A) offs++;
      drive->parms.read_speed_kb = swap2(drive->rd_buf+offs+14);
      return 0;
}

int set_streaming(drive_info* drive) {
      char data[28]; memset(data, 0, 28);

      int* start_lba  = (int*)&data[4];
      int* end_lba    = (int*)&data[8];
      int* read_size  = (int*)&data[12];
      int* read_time  = (int*)&data[16];
      int* write_size = (int*)&data[20];
      int* write_time = (int*)&data[24];

      read_capacity(drive);

      *start_lba = swap4(0);
      *end_lba = swap4(drive->media.capacity);
//    *end_lba = swap4(0);
      *read_time = swap4(1000);
      *read_size = swap4(drive->parms.read_speed_kb);
      *write_time = swap4(1000);
      *write_size = swap4(drive->parms.write_speed_kb);
      drive->cmd_clear();
      drive->cmd[0] = MMC_SET_STREAMING;
      drive->cmd[10] = 28;
      if ((drive->err=drive->cmd.transport(WRITE,data,28)))
            {sperror ("SET_STREAMING",drive->err); return (drive->err); }
      return 0;
}

int set_cd_speed(drive_info* drive) {
      int   speed = 0xFFFF;
      int   speed_wr = 0xFFFF;
      if (drive->parms.read_speed_kb) speed = drive->parms.read_speed_kb;
      if (drive->parms.write_speed_kb) speed_wr = drive->parms.write_speed_kb;

      drive->cmd_clear();
      drive->cmd[0] = MMC_SET_SPEED;
      drive->cmd[1] = 0x01;
      drive->cmd[2] = (speed >> 8) & 0xFF;
      drive->cmd[3] = speed & 0xFF;
//    drive->cmd[4] = 0xFF;
//    drive->cmd[5] = 0xFF;
      drive->cmd[4] = (speed_wr >> 8) & 0xFF;
      drive->cmd[5] = speed_wr & 0xFF;
      if ((drive->err=drive->cmd.transport(NONE,NULL,0) )) {
//          if (drive->err != 0x23A02) drive->capabilities&=(NCAP_SET_CD_SPEED);
//          sperror ("SET_CD_SPEED",drive->err);
            return (drive->err);
      }
      return 0;
}

//#define __STREAMING_PRIOR
int set_read_speed(drive_info* drive) {
      int   rez=0;
      if ((rez = set_cd_speed(drive)))
            rez = set_streaming(drive);
/*
#ifdef __STREAMING_PRIOR
      if (drive->media.disc_type & DISC_CD) {
            rez = set_cd_speed(drive);
      } else if (drive->media.disc_type & DISC_DVD) {
            { if ((rez = set_cd_speed(drive))) rez = set_streaming(drive); }
      }
#else
      if ((drive->capabilities & CAP_SET_CD_SPEED) )//&& (drive->media.disc_type & DISC_CD))
            { if ((rez = set_cd_speed(drive))) rez = set_streaming(drive); }
      else if (drive->capabilities & CAP_REAL_TIME_STREAMING)
            { rez = set_streaming(drive); }
#endif*/
      return rez;
}

int get_media_status(drive_info* drive){
      drive->cmd_clear();
      drive->cmd[0]=MMC_GET_EVENT_STATUS_NOTIFICATION;
      drive->cmd[1]=0x01;
      drive->cmd[4]=0x10;
      drive->cmd[7]=0;
      drive->cmd[8]=8;
      if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,8)))
            { sperror ("GET_EVENT_STATUS",drive->err); return (drive->err); }
      if (drive->rd_buf[5] & 0x01) drive->parms.status |= STATUS_OPEN;
      else drive->parms.status &= (~STATUS_OPEN);
      if (drive->rd_buf[5] & 0x02) drive->parms.status |= STATUS_MEDIA_PRESENT;
      else drive->parms.status &= (~STATUS_MEDIA_PRESENT);
      drive->parms.event = drive->rd_buf[4] & 0x0F;
      return 0;
}

int load_eject(drive_info* drive, bool load){
      drive->cmd_clear();
      drive->cmd[0]=MMC_START_STOP_UNIT;
      drive->cmd[4]=0x02 | load;
      if ((drive->err=drive->cmd.transport(NONE,NULL,0)))
            { sperror ("LOAD_EJECT",drive->err); return (drive->err); }
      return 0;
}

int get_lock(drive_info* drive){
//    printf("get_lock()\n");
      int offs;
      if (mode_sense(drive, 0x2A, 0, 256)) 
            { sperror ("GET_LOCK",drive->err); return (drive->err); }
      offs=0; while (((drive->rd_buf[offs]) & 0x3F) != 0x2A) offs++;
      if (drive->rd_buf[offs+6] & 0x02) drive->parms.status |= STATUS_LOCK;
      else drive->parms.status &= (~STATUS_LOCK);
#ifndef __PXCONTROL
      printf("--- Disc %slocked\n",(drive->parms.status & STATUS_LOCK) ? "" : "UN");
#endif
      return 0;
}

int set_lock(drive_info* drive){
      int lock;
//    printf("--- %slocking disc...\n",(drive->parms.status & STATUS_LOCK) ? "" : "UN");
      if (drive->parms.status & STATUS_LOCK) lock=1; else lock=0; 
      drive->cmd_clear();
      drive->cmd[0]=MMC_PREVENT_ALLOW_MEDIUM_REMIVAL;
      drive->cmd[4]=lock;
      if ((drive->err=drive->cmd.transport(NONE, NULL, 0)))
            { sperror ("SET_LOCK",drive->err); get_lock(drive); return (drive->err); }
      get_lock(drive);
      return 0;
}

int play_audio_msf(drive_info* drive, int beg, int end){
      drive->cmd_clear();
      drive->cmd[0]=MMC_PLAY_AUDIO_MSF;
      drive->cmd[3]=(beg>>16) & 0xFF;
      drive->cmd[4]=(beg>>8) & 0xFF;
      drive->cmd[5]=beg & 0xFF;
      drive->cmd[6]=(end>>16) & 0xFF;
      drive->cmd[7]=(end>>8) & 0xFF;
      drive->cmd[8]=end & 0xFF;
      if ((drive->err=drive->cmd.transport(NONE, NULL, 0)))
            { sperror ("PLAY_AUDIO_MSF",drive->err); return (drive->err); }
      return 0;
}

int play_audio(drive_info* drive, int beg, short int len){
      drive->cmd_clear();
      drive->cmd[0]=MMC_PLAY_AUDIO;
      drive->cmd[2]=(beg>>24) & 0xFF;
      drive->cmd[3]=(beg>>16) & 0xFF;
      drive->cmd[4]=(beg>>8) & 0xFF;
      drive->cmd[5]=beg & 0xFF;
      drive->cmd[7]=(len>>8) & 0xFF;
      drive->cmd[8]=len & 0xFF;
      if ((drive->err=drive->cmd.transport(NONE, NULL, 0)))
            { sperror ("PLAY_AUDIO",drive->err); return (drive->err); }
      return 0;
}

int seek(drive_info* drive, int lba, unsigned char flags){
      drive->cmd_clear();
      drive->cmd[0]=MMC_SEEK;
      drive->cmd[2]=(lba>>24) & 0xFF;
      drive->cmd[3]=(lba>>16) & 0xFF;
      drive->cmd[4]=(lba>>8) & 0xFF;
      drive->cmd[5]=lba & 0xFF;

      drive->cmd[9]=flags;
      if ((drive->err=drive->cmd.transport(NONE, NULL, 0)))
            { sperror ("SEEK",drive->err); return (drive->err); }
      return 0;
}


int read_cd(drive_info* drive, int lba, int sector_count, unsigned char flags, unsigned char FUA) {
//    int transfer_length = sector_count * 3072;

//    int sect_data = 2352;
      int sect_data = 3072;

      int transfer_length = sector_count * sect_data;

      drive->cmd_clear();
      drive->cmd[0]=MMC_READ_CD;
      drive->cmd[1]= FUA ? 0x08 : 0x00;
      drive->cmd[2]=(lba>>24) & 0xFF;
      drive->cmd[3]=(lba>>16) & 0xFF;
      drive->cmd[4]=(lba>>8) & 0xFF;
      drive->cmd[5]=lba & 0xFF;
      drive->cmd[8]=sector_count;
      drive->cmd[9]=flags;
      if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,transfer_length)))
            { sperror ("READ_CD",drive->err); return (drive->err); }
      return 0;
}

int read(drive_info* drive, int lba, int sector_count, unsigned char FUA) {
//    int transfer_length = sector_count * 3072;
      int transfer_length = sector_count * 2048;
      drive->cmd_clear();
      drive->cmd[0]=MMC_READ;
      drive->cmd[1]= FUA ? 0x08 : 0x00;
      drive->cmd[2]=(lba>>24) & 0xFF;
      drive->cmd[3]=(lba>>16) & 0xFF;
      drive->cmd[4]=(lba>>8) & 0xFF;
      drive->cmd[5]=lba & 0xFF;
      drive->cmd[8]=sector_count;
      if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,transfer_length)))
            {sperror ("READ",drive->err); return (drive->err);}
      return 0;
}

int read_one_ecc_block(drive_info* drive, int lba) {
      drive->cmd_clear();
      drive->cmd[0] = MMC_READ;
      drive->cmd[2] = (lba>>24) & 0xFF;
      drive->cmd[3] = (lba>>16) & 0xFF;
      drive->cmd[4] = (lba>>8) & 0xFF;
      drive->cmd[5] = lba & 0xFF;
      drive->cmd[8] = 0x10;
      if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,0x8000)))
            {sperror ("READ_ONE_ECC_BLOCK",drive->err); return (drive->err);}
//    if ((drive->err=drive->cmd.transport(READ,(void*)((unsigned char*)drive->rd_buf+(0x0001<<14)),0x34)))
//          {sperror ("READ_ONE_ECC_BLOCK",drive->err); return (drive->err);}
      return 0;
}

int get_drive_serial_number(drive_info* drive) {
//    char data[2048]; memset(data, 0, sizeof(data));
      unsigned int data_length;
      unsigned int length;
      get_configuration(drive, FEATURE_LOGICAL_UNIT_SERIAL_NUMBER, &data_length, NULL);
      length = drive->rd_buf[11]; drive->rd_buf[12+length]=0;
      if (data_length>8) strncpy(drive->serial, (char*)drive->rd_buf+12, 16);
      else drive->serial[0]=0;
      return 1;
}

int read_buffer_capacity(drive_info* drive){
      if (mode_sense(drive, 0x2A, 0, 192)) return 1;
      drive->buffer_size=((drive->rd_buf[20] & 0xFF) << 8 ) | (drive->rd_buf[21] & 0xFF);
      printf("Buffer capacity: 0x%04X (%d)KB\n", drive->buffer_size, drive->buffer_size);
      return 0;
}

int read_writer_info(drive_info* drive)
{
      if (!(drive->media.disc_type & (DISC_DVDminusR | DISC_DVDminusRWS | DISC_DVDminusRWR))) {
            strcpy(drive->media.writer, "n/a (only for DVD-R(W))");
            return 1;
      }
      char format=0x0D;
      drive->media.writer[0]=0;
      drive->rd_buf[8]=0;
      drive->cmd_clear();
      drive->cmd[0]=MMC_READ_DVD_STRUCTURE;
      drive->cmd[5]=0x62;
      drive->cmd[7]=format;
      drive->cmd[8]=8;
      drive->cmd[9]=8;
      if ((drive->err = drive->cmd.transport(READ,drive->rd_buf,2056)) || (!drive->rd_buf[8])) {
            printf("Read Writer Info Method 1 failed\n");
            drive->cmd_clear();
            drive->cmd[0]=MMC_READ_DVD_STRUCTURE;
            drive->cmd[5]=0x02;
            drive->cmd[7]=format;
            drive->cmd[8]=8;
            drive->cmd[9]=8;
            if ((drive->err=drive->cmd.transport(READ,drive->rd_buf,2056))) {
                  printf("Read Writer Info Method 2 failed\n");
                  return 1;
            }
      }
      for (int k=0;k<0x3F;k++) {
            if (!drive->rd_buf[8+k]) drive->rd_buf[8+k]=0x20;
      }
      strncpy(drive->media.writer, (char*)drive->rd_buf+8, 0x3F);
      remove_double_spaces(drive->media.writer);
//    remove_end_spaces(drive->media.writer);
      return 0;
}

int detect_mm_capabilities(drive_info* drive){
      char len;
      int offs;
      int i,j;
      if (mode_sense(drive, 0x2A, 0, 256)) return 1;
      offs=0; while (((drive->rd_buf[offs]) & 0x3F) != 0x2A) offs++;
      len=drive->rd_buf[offs+1];
      if (!drive->silent) printf("CD parameters page length: 0x%02X\n",len);
      if (len >= 28) {drive->mmc=3;}
      else if (len >= 24) {drive->mmc=2;}
      else {drive->mmc=1;}
      if (!drive->silent) for (i=offs; i<(offs+len+2);i+=8){
            for (j=0;j<8;j++) printf(" %02X",drive->rd_buf[i+j] & 0xFF);
            printf("\n");
      }
//    if (drive->mmc) drive->rd_capabilities|=DEVICE_CD_ROM;
      if (drive->rd_buf[offs+2] & 0x01)drive->rd_capabilities|=DEVICE_CD_R;
      if (drive->rd_buf[offs+2] & 0x02)drive->rd_capabilities|=DEVICE_CD_RW;

      if (drive->rd_buf[offs+3] & 0x01)drive->wr_capabilities|=DEVICE_CD_R;
      if (drive->rd_buf[offs+3] & 0x02)drive->wr_capabilities|=DEVICE_CD_RW;
      if (drive->rd_buf[offs+3] & 0x04)drive->capabilities|=CAP_TEST_WRITE;

      if (drive->rd_buf[offs+4] & 0x01)drive->capabilities|=CAP_CD_AUDIO;
      if (drive->rd_buf[offs+4] & 0x02)drive->capabilities|=CAP_COMPOSITE;
      if (drive->rd_buf[offs+4] & 0x04)drive->capabilities|=CAP_DIGITAL_PORT_1;
      if (drive->rd_buf[offs+4] & 0x08)drive->capabilities|=CAP_DIGITAL_PORT_2;
      if (drive->rd_buf[offs+4] & 0x10)drive->capabilities|=CAP_MODE2_FORM1;
      if (drive->rd_buf[offs+4] & 0x20)drive->capabilities|=CAP_MODE2_FORM2;
      if (drive->rd_buf[offs+4] & 0x40)drive->capabilities|=CAP_MULTISESSION;

      if (drive->rd_buf[offs+5] & 0x01)drive->capabilities|=CAP_DAE;
      if (drive->rd_buf[offs+5] & 0x02)drive->capabilities|=CAP_ACCURATE_STREAM;
      if (drive->rd_buf[offs+5] & 0x10)drive->capabilities|=CAP_C2;
      if (drive->rd_buf[offs+5] & 0x20)drive->capabilities|=CAP_ISRC;
      if (drive->rd_buf[offs+5] & 0x40)drive->capabilities|=CAP_UPC;
      if (drive->rd_buf[offs+5] & 0x80)drive->capabilities|=CAP_READ_BAR_CODE;      

      if (drive->rd_buf[offs+6] & 0x01)drive->capabilities|=CAP_LOCK;
      if (drive->rd_buf[offs+6] & 0x08)drive->capabilities|=CAP_EJECT;

      drive->loader_id = (drive->rd_buf[offs+6] >> 5) & 0x07;

      if (drive->rd_buf[offs+7] & 0x10)drive->capabilities|=CAP_SIDE_CHANGE;

      switch (drive->mmc) {
            case 3:
                  drive->parms.write_speed_kb=drive->rd_buf[37] << 8 | drive->rd_buf[36];
            case 2:
                  if (drive->rd_buf[offs+2] & 0x08)drive->rd_capabilities|=DEVICE_DVD_ROM;
                  if (drive->rd_buf[offs+2] & 0x10)drive->rd_capabilities|=DEVICE_DVD_R;
                  if (drive->rd_buf[offs+2] & 0x20)drive->rd_capabilities|=DEVICE_DVD_RAM;
                  if (drive->rd_buf[offs+3] & 0x10)drive->wr_capabilities|=DEVICE_DVD_R;
                  if (drive->rd_buf[offs+3] & 0x20)drive->wr_capabilities|=DEVICE_DVD_RAM;
//                break;
            case 1:
                  drive->parms.max_read_speed_kb=drive->rd_buf[offs+9] <<8 | drive->rd_buf[offs+8];
                  drive->parms.read_speed_kb=drive->rd_buf[offs+15] <<8 | drive->rd_buf[offs+14];
                  drive->parms.max_write_speed_kb=drive->rd_buf[offs+19] <<8 | drive->rd_buf[offs+19];
                  drive->parms.write_speed_kb=drive->rd_buf[offs+21] << 8 | drive->rd_buf[offs+20];
                  break;
      }
      if (!drive->silent) printf("Max speeds:\tR@%dKBps / W@%dKBps\nCurrent speeds:\tR@%dKBps / W@%dKBps\n",
            drive->parms.max_read_speed_kb, drive->parms.max_write_speed_kb,
            drive->parms.read_speed_kb, drive->parms.write_speed_kb);
      return 0;
}

int convert_to_ID (drive_info* drive) {
      if (!strncmp(drive->ven,"PLEXTOR ",8)) {
            drive->ven_ID=WR_PLEXTOR;
            if(!strncmp(drive->dev,"CD-R   PREMIUM",14))
                  drive->dev_ID=PLEXTOR_PREMIUM;
            else
            if(!strncmp(drive->dev,"DVD-ROM PX-130",14))
                  { drive->ven_ID=RD_BENQ;
                  drive->dev_ID=BENQ_DV1650V;}
            else
            if(!strncmp(drive->dev,"DVDR   PX-708A2",15))
                  drive->dev_ID=PLEXTOR_708A2;
            else
            if(!strncmp(drive->dev,"DVDR   PX-712",13))
                  drive->dev_ID=PLEXTOR_712;
            else
            if(!strncmp(drive->dev,"DVDR   PX-714",13))
                  drive->dev_ID=PLEXTOR_716;
            else
            if(!strncmp(drive->dev,"DVDR   PX-716",13))
                  drive->dev_ID=PLEXTOR_716;
            else
            if(!strncmp(drive->dev,"DVDR   PX-740",13))
                  { drive->ven_ID=WR_BENQ;
                  drive->dev_ID=BENQ_DW1640;}
            else
/*          if(!strncmp(drive->dev,"DVDR   PX-750",13))
            else*/
            if(!strncmp(drive->dev,"DVDR   PX-755",13))
                  drive->dev_ID=PLEXTOR_760;
            else
            if(!strncmp(drive->dev,"DVDR   PX-760",13))
                  drive->dev_ID=PLEXTOR_760;
            else
                  drive->dev_ID=PLEXTOR_OLD;
//                { drive->ven_ID = WR_GENERIC; drive->dev_ID = 0; }
      }


      else if (!strncmp(drive->ven,"PIONEER ",8)) {
            drive->ven_ID=WR_PIONEER;
            if(!strncmp(drive->dev,"DVD-RW  DVR-106",15))
                  drive->dev_ID=PIO_DVR_106;
            else
            if(!strncmp(drive->dev,"DVD-RW  DVR-107",15))
                  drive->dev_ID=PIO_DVR_107;
            else
            if(!strncmp(drive->dev,"DVD-RW  DVR-108",15))
                  drive->dev_ID=PIO_DVR_108;
            else
            if(!strncmp(drive->dev,"DVD-RW  DVR-109",15))
                  drive->dev_ID=PIO_DVR_109;
            else
            if(!strncmp(drive->dev,"DVD-RW  DVR-110",15))
                  drive->dev_ID=PIO_DVR_110;
            else
            if(!strncmp(drive->dev,"DVD-RW  DVR-111",15))
                  drive->dev_ID=PIO_DVR_111;
            else
                  drive->dev_ID=PIO_OLD;
//                { drive->ven_ID = WR_GENERIC; drive->dev_ID = 0; }
      }


      else if (!strncmp(drive->ven,"ASUS    ",8)) {
            drive->ven_ID=WR_PIONEER;
            if(!strncmp(drive->dev,"DRW-0402P",9))
                  drive->dev_ID=PIO_DVR_106;
            else
            if(!strncmp(drive->dev,"DRW-0804P",9))
                  drive->dev_ID=PIO_DVR_107;
            else
            if(!strncmp(drive->dev,"DRW-1604P",9))
                  drive->dev_ID=PIO_DVR_108;
            else
            if(!strncmp(drive->dev,"DRW-1608P ",10))
                  drive->dev_ID=PIO_DVR_109;
            else
            if(!strncmp(drive->dev,"DRW-1608P2",10))
                  drive->dev_ID=PIO_DVR_110;
            else
            if(!strncmp(drive->dev,"DRW-1608P3",10))
                  drive->dev_ID=PIO_DVR_111;
            else
                  drive->dev_ID=PIO_OLD;
      }


      else if (!strncmp(drive->ven,"_NEC    ",8)) {
            drive->ven_ID=WR_NEC;
            if(!strncmp(drive->dev,"DVD_RW ND-352",13))
                  drive->dev_ID=NEC_3520;
            else
            if(!strncmp(drive->dev,"DVD_RW ND-353",13))
                  drive->dev_ID=NEC_3530;
            else
            if(!strncmp(drive->dev,"DVD_RW ND-354",13))
                  drive->dev_ID=NEC_3540;
            else
            if(!strncmp(drive->dev,"DVD_RW ND-355",13))
                  drive->dev_ID=NEC_4550;
            else
            if(!strncmp(drive->dev,"DVD_RW ND-357",13))
                  drive->dev_ID=NEC_4570;
            else
            if(!strncmp(drive->dev,"DVD_RW ND-365",13))
                  drive->dev_ID=NEC_4650;
            else
            if(!strncmp(drive->dev,"DVD_RW ND-455",13))
                  drive->dev_ID=NEC_4550;
            else
            if(!strncmp(drive->dev,"DVD_RW ND-457",13))
                  drive->dev_ID=NEC_4570;
            else
            if(!strncmp(drive->dev,"DVD_RW ND-465",13))
                  drive->dev_ID=NEC_4650;
            else
                  drive->dev_ID=NEC_OLD;
//                { drive->ven_ID = WR_GENERIC; drive->dev_ID = 0; }
      }


      else if (!strncmp(drive->ven,"LITE-ON ",8)) {
            drive->ven_ID=WR_LITEON;
            if(!strncmp(drive->dev,"LTR-52327S",10))
                  drive->dev_ID=LTN_LTR_52327;
            else
            if(!strncmp(drive->dev,"DVDRW SOHW-811S",14))
                  drive->dev_ID=LTN_SOHW_811S;
            else
            if(!strncmp(drive->dev,"DVDRW SOHW-812S",14))
                  drive->dev_ID=LTN_SOHW_812S;
            else
            if(!strncmp(drive->dev,"DVDRW SOHW-832S",14))
                  drive->dev_ID=LTN_SOHW_832S;
            else
            if(!strncmp(drive->dev,"DVDRW SOHW-1653S",15))
                  drive->dev_ID=LTN_SOHW_1653S;
            else
            if(!strncmp(drive->dev,"DVDRW SOHW-1673S",15))
                  drive->dev_ID=LTN_SOHW_1673S;
            else
            if(!strncmp(drive->dev,"DVDRW SOHW-1693S",15))
                  drive->dev_ID=LTN_SOHW_1693S;
            else
            if(!strncmp(drive->dev,"DVDRW SHW-1635S",14))
                  drive->dev_ID=LTN_SHW_1635S;
            else
                  drive->dev_ID=LTN_OLD;
      }


      else if (!strncmp(drive->ven,"BENQ    ",8)) {
            drive->ven_ID=WR_BENQ;
            if(!strncmp(drive->dev,"DVD DD DW1620",13))
                  drive->dev_ID=BENQ_DW1620;
            else
            if(!strncmp(drive->dev,"DVD DD DW1640",13))
                  drive->dev_ID=BENQ_DW1640;
            else
                  drive->dev_ID=BENQ_OLD;
      }


      else if (!strncmp(drive->ven,"TEAC    ",8)) {
//          if(!strncmp(drive->dev,"DW-552GA",8))
            if(!strncmp(drive->dev,"DV-W50D",7)) {
                  drive->ven_ID=WR_PIONEER;
                  drive->dev_ID=PIO_DVR_106;
            } else
            if(!strncmp(drive->dev,"DV-W58D",7)) {
                  drive->ven_ID=WR_PIONEER;
                  drive->dev_ID=PIO_DVR_107;
            } else
            if(!strncmp(drive->dev,"DV-W516D",8)) {
                  drive->ven_ID=WR_PIONEER;
                  drive->dev_ID=PIO_DVR_108;
            } else
            if(!strncmp(drive->dev,"DV-W58G",7)) {
                  drive->ven_ID=WR_LITEON;
                  drive->dev_ID=LTN_SOHW_811S;
            } else
            if(!strncmp(drive->dev,"DV-W58G-A",9)) {
                  drive->ven_ID=WR_LITEON;
                  drive->dev_ID=LTN_SOHW_812S;
            } else {
                  drive->ven_ID = WR_GENERIC;
                  drive->dev_ID = 0;
            }
      }


      else if (!strncmp(drive->ven,"SONY    ",8)) {
            drive->ven_ID=WR_LITEON;
            if(!strncmp(drive->dev,"DVD RW DRU-700A",15))
                  drive->dev_ID=LTN_SOHW_832S;
            else
                  drive->dev_ID=LTN_OLD;
      }

      else { drive->ven_ID = WR_GENERIC; drive->dev_ID = 0; }
      return 0;
}

int detect_check_capabilities(drive_info* drive){
      drive->chk_features=0;
      switch (drive->ven_ID) {
            case WR_PLEXTOR:
                  switch (drive->dev_ID) {
                        case PLEXTOR_760:
                        case PLEXTOR_716:
                              drive->chk_features|=CHK_TA;
                        case PLEXTOR_712:
                        case PLEXTOR_708A2:
                              drive->chk_features|=CHK_JB_DVD;
                              drive->chk_features|=CHK_PI;
                              drive->chk_features|=CHK_PO;
                        case PLEXTOR_PREMIUM:
                              drive->chk_features|=CHK_JB_CD;
                              drive->chk_features|=CHK_CX;
                              drive->chk_features|=CHK_FETE;
                  }
                  break;
            case WR_PIONEER:
                  drive->chk_features|=CHK_CX;
                  if (drive->rd_capabilities & DEVICE_DVD) {
                        drive->chk_features|=CHK_PIE;
//                      drive->chk_features|=CHK_PIF;
                  }
                  break;
            case WR_NEC:
                  drive->chk_features|=CHK_CX;
                  if (drive->rd_capabilities & DEVICE_DVD) {
                        drive->chk_features|=CHK_PIE;
                        drive->chk_features|=CHK_PIF;
                  }
                  break;
            case WR_LITEON:
                  drive->chk_features|=CHK_CX;
//                drive->chk_features|=CHK_JB_CD;
                  if (drive->rd_capabilities & DEVICE_DVD) {
                        drive->chk_features|=CHK_PIE;
//                      drive->chk_features|=CHK_PIF;
//                      drive->chk_features|=CHK_JB_DVD;
                  }
                  break;
            case RD_BENQ:
                  drive->chk_features|=CHK_CX;
                  drive->chk_features|=CHK_JB_CD;
                  if (drive->rd_capabilities & DEVICE_DVD) {
                        drive->chk_features|=CHK_PIE;
//                      drive->chk_features|=CHK_PIF;
                        drive->chk_features|=CHK_JB_DVD;
                  }
                  break;
            case WR_BENQ:
                  drive->chk_features|=CHK_CX;
//                drive->chk_features|=CHK_JB_CD;
                  if (drive->rd_capabilities & DEVICE_DVD) {
                        drive->chk_features|=CHK_PIE;
//                      drive->chk_features|=CHK_PIF;
//                      drive->chk_features|=CHK_JB_DVD;
                  }
                  break;
            case WR_GENERIC:
                  if (drive->capabilities | CAP_C2)
                        drive->chk_features|=CHK_CX;
                  break;
            default:
                  break;
      }
      return 0;
}

Generated by  Doxygen 1.6.0   Back to index