/* * This file is part of the QPxTool project. * Copyright (C) 2005-2006 Gennady "ShultZ" Kozlov * * 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 #include #include #include //#include //#include "transport.hxx" #include "qpx_mmc.h" 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 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); // *data_length = (drive->rd_buf[0]<<24) | (drive->rd_buf[1]<<16) | (drive->rd_buf[2]<<8) | drive->rd_buf[3]; 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_idiface,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; ird_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 fl; if (!drive->silent) printf("\n** Reading supported features...\n"); if (get_configuration(drive, 0 , &len, NULL, 0)) return 1; // 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; ird_buf+i); 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 [%s]", fn, FEATURES[ii].name); // for (ii=0; ii<(fl+4); ii++) { if (!(ii%32)) printf("\n"); printf(" %02X",drive->rd_buf[i+ii] & 0xFF); } 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 Reed/Write 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 Reed/Write DVD's if (len >= 0x08) { 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; ird_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; imedia.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; imedia.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; imedia.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; ird_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; ird_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; ird_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, ¤t); 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*8rd_buf[i]); // printf("\n"); // } for (j=0; jrd_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; iparms.wr_speed_tbl_kb[i] = 0; // printf("== Write speeds: %d\n",spdcnt); for (i=0; (iparms.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); 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; }