File indexing completed on 2024-03-24 04:57:18
0001 /* 0002 * This file is part of WorkMan, the civilized CD player library 0003 * Copyright (C) 1991-1997 by Steven Grimm <koreth@midwinter.com> 0004 * Copyright (C) by Dirk Försterling <milliByte@DeathsDoor.com> 0005 * Copyright (C) 2004-2006 Alexander Kern <alex.kern@gmx.de> 0006 * 0007 * This library is free software; you can redistribute it and/or 0008 * modify it under the terms of the GNU Library General Public 0009 * License as published by the Free Software Foundation; either 0010 * version 2 of the License, or (at your option) any later version. 0011 * 0012 * This library is distributed in the hope that it will be useful, 0013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 * Library General Public License for more details. 0016 * 0017 * You should have received a copy of the GNU Library General Public 0018 * License along with this library; if not, write to the Free 0019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 0020 * 0021 * 0022 * Frontend functions for sending raw SCSI commands to the CD-ROM drive. 0023 * These depend on wm_scsi(), which should be defined in each platform 0024 * module. 0025 */ 0026 0027 #include <stdio.h> 0028 #include <stdlib.h> 0029 #include <string.h> 0030 #include "include/wm_config.h" 0031 #include "include/wm_struct.h" 0032 #include "include/wm_scsi.h" 0033 #include "include/wm_platform.h" 0034 #include "include/wm_helpers.h" 0035 #include "include/wm_cdrom.h" 0036 #include "include/wm_cdtext.h" 0037 0038 #define SCMD_INQUIRY 0x12 0039 #define SCMD_MODE_SELECT 0x15 0040 #define SCMD_MODE_SENSE 0x1a 0041 #define SCMD_START_STOP 0x1b 0042 #define SCMD_PREVENT 0x1e 0043 #define SCMD_READ_SUBCHANNEL 0x42 0044 #define SCMD_READ_TOC 0x43 0045 #define SCMD_PLAY_AUDIO_MSF 0x47 0046 #define SCMD_PAUSE_RESUME 0x4b 0047 #define SCMD_SET_CD_SPEED 0xbb 0048 0049 #define SUBQ_STATUS_INVALID 0x00 0050 #define SUBQ_STATUS_PLAY 0x11 0051 #define SUBQ_STATUS_PAUSE 0x12 0052 #define SUBQ_STATUS_DONE 0x13 0053 #define SUBQ_STATUS_ERROR 0x14 0054 #define SUBQ_STATUS_NONE 0x15 0055 #define SUBQ_STATUS_NO_DISC 0x17 /* Illegal, but Toshiba returns it. */ 0056 #define SUBQ_ILLEGAL 0xff 0057 0058 #define PAGE_AUDIO 0x0e 0059 #define LEADOUT 0xaa 0060 0061 #define WM_MSG_CLASS WM_MSG_CLASS_SCSI 0062 0063 /* local prototypes */ 0064 int wm_scsi_mode_select( struct wm_drive *d, unsigned char *buf, unsigned char len ); 0065 int wm_scsi2_pause_resume(struct wm_drive *d, int resume); 0066 int wm_scsi2_prevent(struct wm_drive *d, int prevent); 0067 int wm_scsi2_play(struct wm_drive *d, int sframe, int eframe); 0068 int wm_scsi2_get_trackinfo(struct wm_drive *d, int track, int *data, int *startframe); 0069 int wm_scsi2_get_cdlen(struct wm_drive *d, int frames); 0070 int wm_scsi2_get_drive_status(struct wm_drive *d, int oldmode, 0071 int *mode, int *pos, int *track, int *ind); 0072 int wm_scsi2_get_trackcount(struct wm_drive *d, int *tracks); 0073 int wm_scsi2_pause(struct wm_drive *d); 0074 int wm_scsi2_resume(struct wm_drive *d); 0075 int wm_scsi2_stop(struct wm_drive *d); 0076 int wm_scsi2_eject(struct wm_drive *d); 0077 int wm_scsi2_closetray(struct wm_drive *d); 0078 int wm_scsi2_get_volume(struct wm_drive *d, int *left, int *right); 0079 int wm_scsi2_set_volume(struct wm_drive *d, int left, int right); 0080 /* local prototypes END */ 0081 0082 /* 0083 * Send a SCSI command over the bus, with all the CDB bytes specified 0084 * as unsigned char parameters. This doesn't use varargs because some 0085 * systems have stdargs instead and the number of bytes in a CDB is 0086 * limited to 12 anyway. 0087 * 0088 * d Drive structure 0089 * buf Buffer for data, both sending and receiving 0090 * len Size of buffer 0091 * dir TRUE if the command expects data to be returned in the buffer. 0092 * a0- CDB bytes. Either 6, 10, or 12 of them, depending on the command. 0093 */ 0094 /*VARARGS4*/ 0095 int 0096 sendscsi( struct wm_drive *d, void *buf, 0097 unsigned int len, int dir, 0098 unsigned char a0, unsigned char a1, 0099 unsigned char a2, unsigned char a3, 0100 unsigned char a4, unsigned char a5, 0101 unsigned char a6, unsigned char a7, 0102 unsigned char a8, unsigned char a9, 0103 unsigned char a10, unsigned char a11 ) 0104 { 0105 int cdblen = 0; 0106 unsigned char cdb[12]; 0107 0108 cdb[0] = a0; 0109 cdb[1] = a1; 0110 cdb[2] = a2; 0111 cdb[3] = a3; 0112 cdb[4] = a4; 0113 cdb[5] = a5; 0114 0115 switch ((a0 >> 5) & 7) { 0116 case 0: 0117 cdblen = 6; 0118 break; 0119 0120 case 5: 0121 cdb[10] = a10; 0122 cdb[11] = a11; 0123 cdblen = 12; 0124 0125 case 1: 0126 case 2: 0127 case 6: /* assume 10-byte vendor-specific codes for now */ 0128 cdb[6] = a6; 0129 cdb[7] = a7; 0130 cdb[8] = a8; 0131 cdb[9] = a9; 0132 if (! cdblen) 0133 cdblen = 10; 0134 break; 0135 } 0136 0137 if(d->proto.scsi) 0138 return d->proto.scsi(d, cdb, cdblen, buf, len, dir); 0139 return -1; 0140 } 0141 0142 /* 0143 * Send a MODE SENSE command and return the results (minus header cruft) 0144 * in a user buffer. 0145 * 0146 * d Drive structure 0147 * page Number of page to query (plus page control bits, if any) 0148 * buf Result buffer 0149 */ 0150 int 0151 wm_scsi_mode_sense( struct wm_drive *d, unsigned char page, unsigned char *buf ) 0152 { 0153 unsigned char pagebuf[255]; 0154 int status, i, len, offset; 0155 0156 status = sendscsi(d, pagebuf, sizeof(pagebuf), 1, SCMD_MODE_SENSE, 0, 0157 page, 0, sizeof(pagebuf), 0,0,0,0,0,0,0); 0158 if (status < 0) 0159 return (status); 0160 0161 /* 0162 * The first byte of the returned data is the transfer length. Then 0163 * two more bytes and the length of whatever header blocks are in 0164 * front of the page we want. 0165 */ 0166 len = pagebuf[0] - pagebuf[3] - 3; 0167 offset = pagebuf[3] + 4; 0168 for (i = 0; i < len; i++) 0169 buf[i] = pagebuf[offset + i]; 0170 0171 return (0); 0172 } 0173 0174 /* 0175 * Send a MODE SELECT command. 0176 * 0177 * d Drive structure 0178 * buf Page buffer (no need to put on block descriptors) 0179 * len Size of page 0180 */ 0181 int 0182 wm_scsi_mode_select( struct wm_drive *d, unsigned char *buf, unsigned char len ) 0183 { 0184 unsigned char pagebuf[255]; 0185 int i; 0186 0187 pagebuf[0] = pagebuf[1] = pagebuf[2] = pagebuf[3] = 0; 0188 for (i = 0; i < (int) len; i++) 0189 pagebuf[i + 4] = buf[i]; 0190 0191 return sendscsi(d, pagebuf, len + 4, 0, SCMD_MODE_SELECT, 0x10, 0, 0192 0, len + 4, 0,0,0,0,0,0,0); 0193 } 0194 0195 /* 0196 * Send an INQUIRY command to get the drive type. 0197 * 0198 * d Drive structure 0199 * vendor Buffer for vendor name (8 bytes + null) 0200 * model Buffer for model name (16 bytes + null) 0201 * rev Buffer for revision level (4 bytes + null) 0202 * 0203 * The above string lengths apply to the SCSI INQUIRY command. The 0204 * actual WorkMan drive structure reserves 31 bytes + NULL per entry. 0205 * 0206 * If the model name begins with "CD-ROM" and zero or more spaces, that will 0207 * all be stripped off since it's just extra junk to WorkMan. 0208 */ 0209 int 0210 wm_scsi_get_drive_type(struct wm_drive *d) 0211 { 0212 /* removed unsigned*/ 0213 char *s, *t, buf[36]; 0214 0215 memset(buf, 0, 36); 0216 0217 wm_lib_message(WM_MSG_CLASS_SCSI | WM_MSG_LEVEL_INFO, "Sending SCSI inquiry command...\n"); 0218 if(sendscsi(d, buf, 36, 1, SCMD_INQUIRY, 0, 0, 0, 36, 0,0,0,0,0,0,0)) { 0219 sprintf(d->vendor, WM_STR_GENVENDOR); 0220 sprintf(d->model, WM_STR_GENMODEL); 0221 sprintf(d->revision, WM_STR_GENREV); 0222 wm_lib_message(WM_MSG_CLASS_SCSI | WM_MSG_LEVEL_ERROR, 0223 "SCSI Inquiry command not supported in this context\n"); 0224 return -1; 0225 } 0226 0227 wm_lib_message(WM_MSG_CLASS_SCSI | WM_MSG_LEVEL_DEBUG, "sent.\n"); 0228 0229 memcpy(d->vendor, buf + 8, 8); 0230 d->vendor[8] = '\0'; 0231 memcpy(d->model, buf + 16, 16); 0232 d->model[16] = '\0'; 0233 memcpy(d->revision, buf + 32, 4); 0234 d->revision[4] = '\0'; 0235 wm_lib_message(WM_MSG_CLASS_SCSI | WM_MSG_LEVEL_VERB, "SCSI Inquiry result: [%s|%s|%s]\n", 0236 d->vendor, d->model, d->revision); 0237 0238 /* Remove "CD-ROM " from the model. */ 0239 if (! strncmp(d->model, "CD-ROM", 6)) { 0240 s = d->model + 6; 0241 t = d->model; 0242 while (*s == ' ' || *s == '\t') 0243 s++; 0244 while( (*t++ = *s++) ) 0245 ; 0246 } 0247 0248 wm_lib_message(WM_MSG_CLASS_SCSI | WM_MSG_LEVEL_INFO, "scsi: Cooked data: %s %s rev. %s\n", 0249 d->vendor, d->model,d->revision); 0250 0251 return 0; 0252 } /* wm_scsi_get_drive_type() */ 0253 0254 /* 0255 * Send a SCSI-2 PAUSE/RESUME command. "resume" is 1 to resume, 0 to pause. 0256 */ 0257 int 0258 wm_scsi2_pause_resume(struct wm_drive *d, int resume) 0259 { 0260 return sendscsi(d, NULL, 0, 0, SCMD_PAUSE_RESUME, 0, 0, 0, 0, 0, 0, 0261 0, resume ? 1 : 0, 0,0,0); 0262 } 0263 0264 /* 0265 * Send a SCSI-2 "prevent media removal" command. "prevent" is 1 to lock 0266 * caddy in. 0267 */ 0268 int 0269 wm_scsi2_prevent(struct wm_drive *d, int prevent) 0270 { 0271 return sendscsi(d, NULL, 0, 0, SCMD_PREVENT, 0, 0, 0, 0, 0, 0, 0272 0, prevent ? 1 : 0, 0,0,0); 0273 } 0274 0275 /* 0276 * Send a SCSI-2 PLAY AUDIO MSF command. Pass the starting and ending 0277 * frame numbers. 0278 */ 0279 int 0280 wm_scsi2_play(struct wm_drive *d, int sframe, int eframe) 0281 { 0282 return sendscsi(d, NULL, 0, 0, SCMD_PLAY_AUDIO_MSF, 0, 0, 0283 sframe / (60 * 75), (sframe / 75) % 60, sframe % 75, 0284 eframe / (60 * 75), (eframe / 75) % 60, eframe % 75, 0285 0,0,0); 0286 } 0287 0288 /* 0289 * Send a SCSI-2 READ TOC command to get the data for a particular track. 0290 * Fill in track information from the returned data. 0291 */ 0292 int 0293 wm_scsi2_get_trackinfo(struct wm_drive *d, int track, 0294 int *data, int *startframe) 0295 { 0296 unsigned char buf[12]; /* one track's worth of info */ 0297 0298 if (sendscsi(d, buf, sizeof(buf), 1, SCMD_READ_TOC, 2, 0299 0, 0, 0, 0, track, sizeof(buf) / 256, 0300 sizeof(buf) % 256, 0,0,0)) 0301 return (-1); 0302 0303 *data = buf[5] & 4 ? 1 : 0; 0304 *startframe = buf[9] * 60 * 75 + buf[10] * 75 + buf[11]; 0305 0306 return 0; 0307 } 0308 0309 /* 0310 * Get the starting frame for the leadout area (which should be the same as 0311 * the length of the disc as far as WorkMan is concerned). 0312 */ 0313 int 0314 wm_scsi2_get_cdlen(struct wm_drive *d, int frames) 0315 { 0316 int tmp; 0317 return wm_scsi2_get_trackinfo(d, LEADOUT, &tmp, &frames); 0318 } 0319 0320 /* 0321 * Get the current status of the drive by sending the appropriate SCSI-2 0322 * READ SUB-CHANNEL command. 0323 */ 0324 int 0325 wm_scsi2_get_drive_status(struct wm_drive *d, int oldmode, 0326 int *mode, int *pos, int *track, int *ind) 0327 { 0328 unsigned char buf[48]; 0329 0330 /* If we can't get status, the CD is ejected, so default to that. */ 0331 *mode = WM_CDM_EJECTED; 0332 0333 /* If we can't read status, the CD has been ejected. */ 0334 buf[1] = SUBQ_ILLEGAL; 0335 if (sendscsi(d, buf, sizeof(buf), 1, SCMD_READ_SUBCHANNEL, 2, 64, 1, 0336 0, 0, 0, sizeof(buf) / 256, sizeof(buf) % 256, 0,0,0)) 0337 return 0; 0338 0339 switch (buf[1]) { 0340 case SUBQ_STATUS_PLAY: 0341 *mode = WM_CDM_PLAYING; 0342 *track = buf[6]; 0343 *ind = buf[7]; 0344 *pos = buf[9] * 60 * 75 + buf[10] * 75 + buf[11]; 0345 break; 0346 0347 case SUBQ_STATUS_PAUSE: 0348 if (oldmode == WM_CDM_PLAYING || oldmode == WM_CDM_PAUSED) { 0349 *mode = WM_CDM_PAUSED; 0350 *track = buf[6]; 0351 *ind = buf[7]; 0352 *pos = buf[9] * 60 * 75 + 0353 buf[10] * 75 + 0354 buf[11]; 0355 } else 0356 *mode = WM_CDM_STOPPED; 0357 break; 0358 0359 /* 0360 * SUBQ_STATUS_DONE is sometimes returned when the CD is idle, 0361 * even though the spec says it should only be returned when an 0362 * audio play operation finishes. 0363 */ 0364 case SUBQ_STATUS_DONE: 0365 case SUBQ_STATUS_NONE: 0366 case SUBQ_STATUS_INVALID: 0367 if (oldmode == WM_CDM_PLAYING) 0368 *mode = WM_CDM_TRACK_DONE; 0369 else 0370 *mode = WM_CDM_STOPPED; 0371 break; 0372 0373 /* 0374 * This usually means there's no disc in the drive. 0375 */ 0376 case SUBQ_STATUS_NO_DISC: 0377 break; 0378 0379 /* 0380 * This usually means the user ejected the CD manually. 0381 */ 0382 case SUBQ_STATUS_ERROR: 0383 break; 0384 0385 case SUBQ_ILLEGAL: /* call didn't really succeed */ 0386 break; 0387 0388 default: 0389 *mode = WM_CDM_UNKNOWN; 0390 break; 0391 } 0392 0393 return 0; 0394 } 0395 0396 /* 0397 * Get the number of tracks on the CD using the SCSI-2 READ TOC command. 0398 */ 0399 int 0400 wm_scsi2_get_trackcount(struct wm_drive *d, int *tracks) 0401 { 0402 unsigned char buf[4]; 0403 0404 if (sendscsi(d, buf, sizeof(buf), 1, SCMD_READ_TOC, 0, 0405 0, 0, 0, 0, 0, sizeof(buf) / 256, 0406 sizeof(buf) % 256, 0,0,0)) 0407 return -1; 0408 0409 *tracks = buf[3] - buf[2] + 1; 0410 return 0; 0411 } 0412 0413 /* 0414 * Pause the CD. 0415 */ 0416 int 0417 wm_scsi2_pause(struct wm_drive *d) 0418 { 0419 return wm_scsi2_pause_resume(d, 0); 0420 } 0421 0422 /* 0423 * Resume playing after a pause. 0424 */ 0425 int 0426 wm_scsi2_resume(struct wm_drive *d) 0427 { 0428 return wm_scsi2_pause_resume(d, 1); 0429 } 0430 0431 /* 0432 * Stop playing the CD by sending a START STOP UNIT command. 0433 */ 0434 int 0435 wm_scsi2_stop(struct wm_drive *d) 0436 { 0437 return sendscsi(d, NULL, 0, 0, SCMD_START_STOP, 0, 0,0,0,0,0,0,0,0,0,0); 0438 } 0439 0440 /* 0441 * Eject the CD by sending a START STOP UNIT command. 0442 */ 0443 int 0444 wm_scsi2_eject(struct wm_drive *d) 0445 { 0446 /* Unlock the disc (possibly unnecessary). */ 0447 if (wm_scsi2_prevent(d, 0)) 0448 return -1; 0449 wm_lib_message(WM_MSG_CLASS_SCSI | WM_MSG_LEVEL_VERB, "Issuing START_STOP for ejecting...\n"); 0450 return sendscsi(d, NULL, 0, 0, SCMD_START_STOP, 2, 0,0,0,0,0,0,0,0,0,0); 0451 } 0452 0453 /* 0454 * Something like a dummy. The SCSI-2 specs are too hard for me to 0455 * understand here... 0456 * 0457 * If you have the correct command handy, please send the code to 0458 * milliByte@DeathsDoor.com 0459 */ 0460 int 0461 wm_scsi2_closetray(struct wm_drive *d) 0462 { 0463 wm_lib_message(WM_MSG_CLASS_SCSI | WM_MSG_LEVEL_VERB, "Issuing START_STOP for closing...\n"); 0464 return sendscsi(d, NULL, 0,0, SCMD_START_STOP, 2, 0,0,0,0,0,0,0,0,0,0); 0465 } 0466 0467 /* 0468 * Get the volume by doing a MODE SENSE command. 0469 */ 0470 int 0471 wm_scsi2_get_volume(struct wm_drive *d, int *left, int *right) 0472 { 0473 unsigned char mode[16]; 0474 0475 *left = *right = -1; 0476 0477 /* Get the current audio parameters first. */ 0478 if (wm_scsi_mode_sense(d, PAGE_AUDIO, mode)) 0479 return (-1); 0480 0481 *left = ((int) mode[9] * 100) / 255; 0482 *right = ((int) mode[11] * 100) / 255; 0483 0484 return 0; 0485 } 0486 0487 /* 0488 * Set the volume by doing a MODE SELECT command. 0489 */ 0490 int 0491 wm_scsi2_set_volume(struct wm_drive *d, int left, int right) 0492 { 0493 unsigned char mode[16]; 0494 0495 /* Get the current audio parameters first. */ 0496 if (wm_scsi_mode_sense(d, PAGE_AUDIO, mode)) 0497 return -1; 0498 0499 /* Tweak the volume part of the parameters. */ 0500 mode[9] = (left * 255) / 100; 0501 mode[11] = (right * 255) / 100; 0502 0503 /* And send them back to the drive. */ 0504 return wm_scsi_mode_select(d, mode, sizeof(mode)); 0505 } 0506 0507 /*------------------------------------------------------------------------* 0508 * wm_scsi_get_cdtext(drive, buffer, length) 0509 * 0510 * Return a buffer with cdtext-stream. buffer mus be allocated and filled 0511 * 0512 * 0513 *------------------------------------------------------------------------*/ 0514 0515 int 0516 wm_scsi_get_cdtext(struct wm_drive *d, unsigned char **pp_buffer, int *p_buffer_length) 0517 { 0518 int ret; 0519 unsigned char temp[8]; 0520 unsigned char *dynamic_temp; 0521 int cdtext_possible; 0522 unsigned short cdtext_data_length; 0523 unsigned long feature_list_length; 0524 #define IGNORE_FEATURE_LIST 0525 #ifndef IGNORE_FEATURE_LIST 0526 struct feature_list_header *pHeader; 0527 struct feature_descriptor_cdread *pDescriptor; 0528 #endif /* IGNORE_FEATURE_LIST */ 0529 0530 dynamic_temp = NULL; 0531 cdtext_possible = 0; 0532 wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "wm_scsi_get_cdtext entered\n"); 0533 0534 wm_lib_message(WM_MSG_LEVEL_INFO|WM_MSG_CLASS, "CDTEXT INFO: use GET_FEATURY_LIST(0x46)...\n"); 0535 ret = sendscsi(d, temp, 8, 1, 0x46, 0x02, 0x00, 0x1E, 0, 0, 0, 0, 8, 0, 0, 0); 0536 0537 if(ret) { 0538 wm_lib_message(WM_MSG_LEVEL_INFO|WM_MSG_CLASS, 0539 "CDTEXT ERROR: GET_FEATURY_LIST(0x46) not implemented or broken. ret = %i!\n", ret); 0540 #ifndef IGNORE_FEATURE_LIST 0541 wm_lib_message(WM_MSG_LEVEL_INFO|WM_MSG_CLASS, 0542 "CDTEXT ERROR: Try #define IGNORE_FEATURE_LIST in libwm/scsi.c\n"); 0543 #else 0544 cdtext_possible = 1; 0545 wm_lib_message(WM_MSG_LEVEL_INFO|WM_MSG_CLASS, 0546 "CDTEXT INFO: GET_FEATURY_LIST(0x46) ignored. It is OK, because many CDROMS do not implement this feature\n"); 0547 #endif /* IGNORE_FEATURE_LIST */ 0548 } else { 0549 feature_list_length = temp[0]*0xFFFFFF + temp[1]*0xFFFF + temp[2]*0xFF + temp[3] + 4; 0550 0551 dynamic_temp = malloc(feature_list_length); 0552 0553 if(!dynamic_temp) 0554 return -1; 0555 0556 memset(dynamic_temp, 0, feature_list_length); 0557 ret = sendscsi(d, dynamic_temp, feature_list_length, 1, 0558 0x46, 0x02, 0x00, 0x1E, 0, 0, 0, (feature_list_length>>8) & 0xFF, 0559 feature_list_length & 0xFF, 0, 0, 0); 0560 0561 #ifndef IGNORE_FEATURE_LIST 0562 if(!ret) { 0563 pHeader = (struct feature_list_header*)dynamic_temp; 0564 /* printf("length = %i, profile = 0x%02X%02X\n", pHeader->lenght_lsb, pHeader->profile_msb, pHeader->profile_lsb);*/ 0565 pDescriptor = (struct feature_descriptor_cdread*) 0566 (dynamic_temp + sizeof(struct feature_list_header)); 0567 /* printf("code = 0x%02X%02X, settings = 0x%02X, add_length = %i, add_settings = 0x%02X \n", 0568 pDescriptor->feature_code_msb, pDescriptor->feature_code_lsb, pDescriptor->settings, 0569 pDescriptor->add_lenght, pDescriptor->add_settings);*/ 0570 0571 cdtext_possible = pDescriptor->add_settings & 0x01; 0572 } else { 0573 cdtext_possible = 0; 0574 } 0575 #else 0576 cdtext_possible = 1; 0577 #endif /* IGNORE_FEATURE_LIST */ 0578 0579 free (dynamic_temp); 0580 dynamic_temp = 0; 0581 } 0582 0583 if(!cdtext_possible) { 0584 wm_lib_message(WM_MSG_LEVEL_INFO|WM_MSG_CLASS, 0585 "CDTEXT INFO: GET_FEATURY_LIST(0x46) says, CDTEXT is not present!\n"); 0586 return EXIT_SUCCESS; 0587 } 0588 0589 wm_lib_message(WM_MSG_LEVEL_INFO|WM_MSG_CLASS, "CDTEXT INFO: try to read, how long CDTEXT is?\n"); 0590 ret = sendscsi(d, temp, 4, 1, SCMD_READ_TOC, 0x00, 0x05, 0, 0, 0, 0, 0, 4, 0, 0, 0); 0591 0592 if(ret) { 0593 wm_lib_message(WM_MSG_LEVEL_INFO|WM_MSG_CLASS, 0594 "CDTEXT ERROR: READ_TOC(0x43) with format code 0x05 not implemented or broken. ret = %i!\n", ret); 0595 } else { 0596 cdtext_data_length = temp[0]*0xFF + temp[1] + 4 + 1; /* divide by 18 + 4 ? */ 0597 /* cdtext_data_length%18 == 0;? */ 0598 wm_lib_message(WM_MSG_LEVEL_INFO|WM_MSG_CLASS, 0599 "CDTEXT INFO: CDTEXT is %i byte(s) long\n", cdtext_data_length); 0600 /* cdc_buffer[2]; cdc_buffer[3]; reserwed */ 0601 dynamic_temp = malloc(cdtext_data_length); 0602 if(!dynamic_temp) 0603 return -1; 0604 0605 memset(dynamic_temp, 0, cdtext_data_length); 0606 wm_lib_message(WM_MSG_LEVEL_INFO|WM_MSG_CLASS, "CDTEXT INFO: try to read CDTEXT\n"); 0607 ret = sendscsi(d, dynamic_temp, cdtext_data_length, 1, 0608 SCMD_READ_TOC, 0x00, 0x05, 0, 0, 0, 0, (cdtext_data_length>>8) & 0xFF, 0609 cdtext_data_length & 0xFF, 0, 0, 0); 0610 0611 if(ret) { 0612 wm_lib_message(WM_MSG_LEVEL_INFO|WM_MSG_CLASS, 0613 "CDTEXT ERROR: READ_TOC(0x43) with format code 0x05 not implemented or broken. ret = %i!\n", ret); 0614 } else { 0615 cdtext_data_length = temp[0]*0xFF + temp[1] + 4 + 1; /* divide by 18 + 4 ? */ 0616 wm_lib_message(WM_MSG_LEVEL_INFO|WM_MSG_CLASS, 0617 "CDTEXT INFO: read %i byte(s) of CDTEXT\n", cdtext_data_length); 0618 0619 /* send cdtext only 18 bytes packs * ? */ 0620 *(p_buffer_length) = cdtext_data_length - 4; 0621 *pp_buffer = malloc(*p_buffer_length); 0622 if(!(*pp_buffer)) { 0623 return -1; 0624 } 0625 memcpy(*pp_buffer, dynamic_temp + 4, *p_buffer_length); 0626 } 0627 free(dynamic_temp); 0628 dynamic_temp = 0; 0629 } 0630 0631 return ret; 0632 } /* wm_scsi_get_cdtext() */ 0633 0634 int 0635 wm_scsi_set_speed(struct wm_drive *d, int read_speed) 0636 { 0637 int ret; 0638 0639 ret = sendscsi(d, NULL, 0, 0, 0640 SCMD_SET_CD_SPEED, 0x00, (read_speed>>8) & 0xFF, read_speed & 0xFF, 0xFF, 0xFF, 0641 0, 0, 0, 0, 0, 0); 0642 wm_lib_message(WM_MSG_LEVEL_ERROR|WM_MSG_CLASS, 0643 "wm_scsi_set_speed returns %i\n", ret); 0644 return ret; 0645 } /* wm_scsi_set_speed() */