File indexing completed on 2024-04-28 08:46:54
0001 /* 0002 * This file is part of WorkMan, the civilized CD player library 0003 * Copyright (C) 1991-1997 by Steven Grimm (original author) 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 * Interface between most of WorkMan and the low-level CD-ROM library 0023 * routines defined in plat_*.c and drv_*.c. The goal is to have no 0024 * platform- or drive-dependent code here. 0025 */ 0026 0027 #define _BSD_SOURCE /* strdup */ 0028 #define _DEFAULT_SOURCE /* stop glibc whining about the previous line */ 0029 0030 #include "include/wm_config.h" 0031 #include "include/wm_struct.h" 0032 #include "include/wm_cddb.h" 0033 #include "include/wm_cdrom.h" 0034 #include "include/wm_platform.h" 0035 #include "include/wm_helpers.h" 0036 #include "include/wm_cdtext.h" 0037 #include "include/wm_scsi.h" 0038 0039 #include <errno.h> 0040 #include <stdio.h> 0041 #include <unistd.h> 0042 #include <stdlib.h> 0043 #include <string.h> 0044 #include <strings.h> 0045 #include <sys/types.h> 0046 0047 #ifdef CAN_CLOSE 0048 #include <fcntl.h> 0049 #endif 0050 0051 /* local prototypes */ 0052 static int fixup_drive_struct(struct wm_drive *); 0053 static int read_toc(struct wm_drive *); 0054 static const char* gen_status(int); 0055 0056 #define WM_MSG_CLASS WM_MSG_CLASS_CDROM 0057 0058 /* extern struct wm_drive generic_proto, toshiba_proto, sony_proto; */ 0059 /* toshiba33_proto; <=== Somehow, this got lost */ 0060 0061 /* 0062 * The supported drive types are listed here. NULL means match anything. 0063 * The first match in the list is used, and substring matches are done (so 0064 * put long names before their shorter prefixes.) 0065 */ 0066 static struct drivelist { 0067 const char *vendor; 0068 const char *model; 0069 const char *revision; 0070 int (*fixup)(struct wm_drive *d); 0071 } drives[] = { 0072 { "TOSHIBA", "XM-3501", NULL, toshiba_fixup }, 0073 { "TOSHIBA", "XM-3401", NULL, toshiba_fixup }, 0074 { "TOSHIBA", "XM-3301", NULL, toshiba_fixup }, 0075 { "SONY", "CDU-8012", NULL, sony_fixup }, 0076 { "SONY", "CDU 561", NULL, sony_fixup }, 0077 { "SONY", "CDU-76S", NULL, sony_fixup }, 0078 { NULL, NULL, NULL, NULL } 0079 }; 0080 0081 /* 0082 * Solaris 2.2 will remove the device out from under us. Getting an ENOENT 0083 * is therefore sometimes not a problem. 0084 */ 0085 int intermittent_dev = 0; 0086 0087 0088 /* 0089 * Macro magic 0090 * 0091 */ 0092 0093 #define CARRAY(id) ((id)-1) 0094 0095 #define DATATRACK 1 0096 0097 /* 0098 * get the current position 0099 */ 0100 int wm_get_cur_pos_rel(void *p) 0101 { 0102 struct wm_drive *pdrive = (struct wm_drive *)p; 0103 return pdrive->thiscd.cur_pos_rel; 0104 } 0105 0106 /* 0107 * get the current position 0108 */ 0109 int wm_get_cur_pos_abs(void *p) 0110 { 0111 struct wm_drive *pdrive = (struct wm_drive *)p; 0112 return pdrive->thiscd.cur_pos_abs; 0113 } 0114 0115 /* 0116 * init the workmanlib 0117 */ 0118 int wm_cd_init(const char *cd_device, const char *soundsystem, 0119 const char *sounddevice, const char *ctldevice, void **ppdrive) 0120 { 0121 int err; 0122 struct wm_drive *pdrive; 0123 0124 if(!ppdrive) 0125 return -1; 0126 0127 pdrive = *ppdrive = (struct wm_drive *)malloc(sizeof(struct wm_drive)); 0128 if(!pdrive) 0129 return -1; 0130 memset(pdrive, 0, sizeof(*pdrive)); 0131 0132 pdrive->cdda = (soundsystem && strcasecmp(soundsystem, "cdin")); 0133 0134 pdrive->cd_device = cd_device ? strdup(cd_device) : strdup(DEFAULT_CD_DEVICE); 0135 pdrive->soundsystem = soundsystem ? strdup(soundsystem): NULL; 0136 pdrive->sounddevice = sounddevice ? strdup(sounddevice) : NULL; 0137 pdrive->ctldevice = ctldevice ? strdup(ctldevice) : NULL; 0138 if(!pdrive->cd_device) { 0139 err = -ENOMEM; 0140 goto init_failed; 0141 } 0142 pdrive->fd = -1; 0143 0144 pdrive->proto.open = gen_open; 0145 pdrive->proto.close = gen_close; 0146 pdrive->proto.get_trackcount = gen_get_trackcount; 0147 pdrive->proto.get_cdlen = gen_get_cdlen; 0148 pdrive->proto.get_trackinfo = gen_get_trackinfo; 0149 pdrive->proto.get_drive_status = gen_get_drive_status; 0150 pdrive->proto.pause = gen_pause; 0151 pdrive->proto.resume = gen_resume; 0152 pdrive->proto.stop = gen_stop; 0153 pdrive->proto.play = gen_play; 0154 pdrive->proto.eject = gen_eject; 0155 pdrive->proto.closetray = gen_closetray; 0156 pdrive->proto.scsi = gen_scsi; 0157 pdrive->proto.set_volume = gen_set_volume; 0158 pdrive->proto.get_volume = gen_get_volume; 0159 pdrive->proto.scale_volume = gen_scale_volume; 0160 pdrive->proto.unscale_volume = gen_unscale_volume; 0161 pdrive->oldmode = WM_CDM_UNKNOWN; 0162 0163 if((err = gen_init(pdrive)) < 0) 0164 goto init_failed; 0165 0166 if ((err = pdrive->proto.open(pdrive)) < 0) 0167 goto open_failed; 0168 0169 /* Can we figure out the drive type? */ 0170 if (wm_scsi_get_drive_type(pdrive)) { 0171 wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "plat_open(): inquiry failed\n"); 0172 } 0173 0174 /* let it override some functions */ 0175 fixup_drive_struct(pdrive); 0176 #ifdef WMLIB_CDDA_BUILD 0177 if(pdrive->cdda && (err = wm_cdda_init(pdrive))) 0178 goto open_failed; 0179 #endif 0180 return wm_cd_status(pdrive); 0181 0182 open_failed: 0183 wm_cd_destroy(pdrive); 0184 0185 init_failed: 0186 free(pdrive->cd_device); 0187 free(pdrive->soundsystem); 0188 free(pdrive->sounddevice); 0189 free(pdrive->ctldevice); 0190 free(pdrive); 0191 0192 return err; 0193 } 0194 0195 int wm_cd_destroy(void *p) 0196 { 0197 struct wm_drive *pdrive = (struct wm_drive *)p; 0198 free_cdtext(); 0199 0200 if(pdrive->cdda) 0201 wm_cdda_destroy(pdrive); 0202 0203 pdrive->proto.close(pdrive); 0204 0205 return 0; 0206 } 0207 /* 0208 * Give information about the drive we found during wmcd_open() 0209 */ 0210 const char *wm_drive_vendor(void *p) 0211 { 0212 struct wm_drive *pdrive = (struct wm_drive *)p; 0213 return pdrive->vendor?pdrive->vendor:""; 0214 } 0215 0216 const char *wm_drive_model(void *p) 0217 { 0218 struct wm_drive *pdrive = (struct wm_drive *)p; 0219 return pdrive->model?pdrive->model:""; 0220 } 0221 0222 const char *wm_drive_revision(void *p) 0223 { 0224 struct wm_drive *pdrive = (struct wm_drive *)p; 0225 return pdrive->revision?pdrive->revision:""; 0226 } 0227 0228 const char *wm_drive_default_device() 0229 { 0230 return DEFAULT_CD_DEVICE; 0231 } 0232 0233 unsigned long wm_cddb_discid(void *p) 0234 { 0235 struct wm_drive *pdrive = (struct wm_drive *)p; 0236 return cddb_discid(pdrive); 0237 } 0238 0239 /* 0240 * Figure out which prototype drive structure we should be using based 0241 * on the vendor, model, and revision of the current pdrive-> 0242 */ 0243 static int fixup_drive_struct(struct wm_drive *d) 0244 { 0245 struct drivelist *driver; 0246 0247 for (driver = drives; driver->vendor; driver++) { 0248 if((strncmp(driver->vendor, d->vendor, strlen(d->vendor))) || 0249 ((driver->model != NULL) && strncmp(driver->model, d->model, strlen(d->model))) || 0250 ((d->revision != NULL) && strncmp(driver->revision, d->revision, strlen(d->revision)))) 0251 continue; 0252 0253 if(!(driver->fixup)) 0254 goto fail; 0255 0256 driver->fixup(d); 0257 return 0; 0258 } 0259 0260 fail: 0261 return -1; 0262 } /* find_drive_struct() */ 0263 0264 /* 0265 * read_toc() 0266 * 0267 * Read the table of contents from the CD. Return a pointer to a wm_cdinfo 0268 * struct containing the relevant information (minus artist/cdname/etc.) 0269 * This is a static struct. Returns NULL if there was an error. 0270 * 0271 * XXX allocates one trackinfo too many. 0272 */ 0273 static int read_toc(struct wm_drive *pdrive) 0274 { 0275 int i; 0276 int pos; 0277 0278 if(!pdrive->proto.get_trackcount || 0279 pdrive->proto.get_trackcount(pdrive, &pdrive->thiscd.ntracks) < 0) { 0280 return -1 ; 0281 } 0282 0283 pdrive->thiscd.length = 0; 0284 pdrive->thiscd.cur_cdmode = WM_CDM_UNKNOWN; 0285 pdrive->thiscd.cd_cur_balance = WM_BALANCE_SYMMETRED; 0286 0287 if (pdrive->thiscd.trk != NULL) 0288 free(pdrive->thiscd.trk); 0289 0290 pdrive->thiscd.trk = malloc((pdrive->thiscd.ntracks + 1) * sizeof(struct wm_trackinfo)); 0291 if (pdrive->thiscd.trk == NULL) { 0292 perror("malloc"); 0293 return -1; 0294 } 0295 0296 for (i = 0; i < pdrive->thiscd.ntracks; i++) { 0297 if(!pdrive->proto.get_trackinfo || 0298 pdrive->proto.get_trackinfo(pdrive, i + 1, &pdrive->thiscd.trk[i].data, 0299 &pdrive->thiscd.trk[i].start) < 0) { 0300 return -1; 0301 } 0302 0303 pdrive->thiscd.trk[i].length = pdrive->thiscd.trk[i].start / 75; 0304 0305 pdrive->thiscd.trk[i].track = i + 1; 0306 wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "track %i, start frame %i\n", 0307 pdrive->thiscd.trk[i].track, pdrive->thiscd.trk[i].start); 0308 } 0309 0310 if(!pdrive->proto.get_cdlen || 0311 pdrive->proto.get_cdlen(pdrive, &pdrive->thiscd.trk[i].start) < 0) { 0312 return -1; 0313 } 0314 pdrive->thiscd.trk[i].length = pdrive->thiscd.trk[i].start / 75; 0315 0316 /* Now compute actual track lengths. */ 0317 pos = pdrive->thiscd.trk[0].length; 0318 for (i = 0; i < pdrive->thiscd.ntracks; i++) { 0319 pdrive->thiscd.trk[i].length = pdrive->thiscd.trk[i+1].length - pos; 0320 pos = pdrive->thiscd.trk[i+1].length; 0321 if (pdrive->thiscd.trk[i].data) 0322 pdrive->thiscd.trk[i].length = (pdrive->thiscd.trk[i + 1].start - pdrive->thiscd.trk[i].start) * 2; 0323 } 0324 0325 pdrive->thiscd.length = pdrive->thiscd.trk[pdrive->thiscd.ntracks].length; 0326 0327 wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "read_toc() successful\n"); 0328 return 0; 0329 } /* read_toc() */ 0330 0331 /* 0332 * wm_cd_status(pdrive) 0333 * 0334 * Return values: 0335 * see wm_cdrom.h 0336 * 0337 * Updates variables. 0338 */ 0339 int wm_cd_status(void *p) 0340 { 0341 struct wm_drive *pdrive = (struct wm_drive *)p; 0342 int mode = -1, tmp; 0343 0344 if(!pdrive->proto.get_drive_status || 0345 (tmp = pdrive->proto.get_drive_status(pdrive, pdrive->oldmode, &mode, 0346 &pdrive->thiscd.cur_frame, 0347 &pdrive->thiscd.curtrack, 0348 &pdrive->thiscd.cur_index)) < 0) { 0349 perror("WM get_drive_status"); 0350 return -1; 0351 } 0352 0353 wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, 0354 "get_drive_status returns status %s, track %i, frame %i\n", 0355 gen_status(mode), pdrive->thiscd.curtrack, pdrive->thiscd.cur_frame); 0356 0357 if(WM_CDS_NO_DISC(pdrive->oldmode) && WM_CDS_DISC_READY(mode)) { 0358 /* device changed */ 0359 pdrive->thiscd.ntracks = 0; 0360 0361 if(read_toc(pdrive) || 0 == pdrive->thiscd.ntracks) { 0362 0363 mode = WM_CDM_NO_DISC; 0364 } else /* refresh cdtext info */ 0365 get_glob_cdtext(pdrive, 1); 0366 0367 wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, 0368 "device status changed() from %s to %s\n", 0369 gen_status(pdrive->oldmode), gen_status(mode)); 0370 } 0371 pdrive->oldmode = mode; 0372 0373 /* 0374 * it seems all driver have'nt state for stop 0375 */ 0376 if(WM_CDM_PAUSED == mode && 0 == pdrive->thiscd.cur_frame) { 0377 mode = WM_CDM_STOPPED; 0378 pdrive->thiscd.curtrack = 0; 0379 } 0380 0381 switch (mode) { 0382 case WM_CDM_PLAYING: 0383 case WM_CDM_PAUSED: 0384 pdrive->thiscd.cur_pos_abs = pdrive->thiscd.cur_frame / 75; 0385 /* search for right track */ 0386 for(tmp = pdrive->thiscd.ntracks; 0387 tmp > 1 && pdrive->thiscd.cur_frame < pdrive->thiscd.trk[CARRAY(tmp)].start; 0388 tmp--) 0389 ; 0390 pdrive->thiscd.curtrack = tmp; 0391 /* Fall through */ 0392 0393 0394 case WM_CDM_UNKNOWN: 0395 if (mode == WM_CDM_UNKNOWN) 0396 { 0397 mode = WM_CDM_NO_DISC; 0398 } 0399 /* Fall through */ 0400 0401 case WM_CDM_STOPPED: 0402 /*assert(thiscd.trk != NULL);*/ 0403 if(pdrive->thiscd.curtrack >= 1 && pdrive->thiscd.curtrack <= pdrive->thiscd.ntracks) { 0404 pdrive->thiscd.cur_pos_rel = (pdrive->thiscd.cur_frame - 0405 pdrive->thiscd.trk[CARRAY(pdrive->thiscd.curtrack)].start) / 75; 0406 if (pdrive->thiscd.cur_pos_rel < 0) 0407 pdrive->thiscd.cur_pos_rel = -pdrive->thiscd.cur_pos_rel; 0408 } 0409 0410 if (pdrive->thiscd.cur_pos_abs < 0) 0411 pdrive->thiscd.cur_pos_abs = pdrive->thiscd.cur_frame = 0; 0412 0413 if (pdrive->thiscd.curtrack < 1) 0414 pdrive->thiscd.curtracklen = pdrive->thiscd.length; 0415 else 0416 pdrive->thiscd.curtracklen = pdrive->thiscd.trk[CARRAY(pdrive->thiscd.curtrack)].length; 0417 /* Fall through */ 0418 0419 case WM_CDM_TRACK_DONE: 0420 pdrive->thiscd.cur_cdmode = mode; 0421 break; 0422 case WM_CDM_FORWARD: 0423 case WM_CDM_EJECTED: 0424 pdrive->thiscd.cur_cdmode = mode; 0425 break; 0426 } 0427 0428 wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, 0429 "wm_cd_status returns %s\n", gen_status(pdrive->thiscd.cur_cdmode)); 0430 0431 return pdrive->thiscd.cur_cdmode; 0432 } 0433 0434 int wm_cd_getcurtrack(void *p) 0435 { 0436 struct wm_drive *pdrive = (struct wm_drive *)p; 0437 if(WM_CDS_NO_DISC(pdrive->thiscd.cur_cdmode)) 0438 return 0; 0439 return pdrive->thiscd.curtrack; 0440 } 0441 0442 int wm_cd_getcurtracklen(void *p) 0443 { 0444 struct wm_drive *pdrive = (struct wm_drive *)p; 0445 if(WM_CDS_NO_DISC(pdrive->thiscd.cur_cdmode)) 0446 return 0; 0447 0448 return pdrive->thiscd.curtracklen; 0449 } 0450 0451 int wm_cd_getcountoftracks(void *p) 0452 { 0453 struct wm_drive *pdrive = (struct wm_drive *)p; 0454 if(WM_CDS_NO_DISC(pdrive->thiscd.cur_cdmode)) 0455 return 0; 0456 0457 return pdrive->thiscd.ntracks; 0458 } 0459 0460 int wm_cd_gettracklen(void *p, int track) 0461 { 0462 struct wm_drive *pdrive = (struct wm_drive *)p; 0463 if (track < 1 || 0464 track > pdrive->thiscd.ntracks || 0465 pdrive->thiscd.trk == NULL) 0466 return 0; 0467 0468 return pdrive->thiscd.trk[CARRAY(track)].length; 0469 } 0470 0471 int wm_cd_gettrackstart(void *p, int track) 0472 { 0473 struct wm_drive *pdrive = (struct wm_drive *)p; 0474 if (track < 1 || 0475 track > (pdrive->thiscd.ntracks+1) || 0476 pdrive->thiscd.trk == NULL) 0477 return 0; 0478 0479 return pdrive->thiscd.trk[CARRAY(track)].start; 0480 } 0481 0482 int wm_cd_gettrackdata(void *p, int track) 0483 { 0484 struct wm_drive *pdrive = (struct wm_drive *)p; 0485 if (track < 1 || 0486 track > pdrive->thiscd.ntracks || 0487 pdrive->thiscd.trk == NULL) 0488 return 0; 0489 0490 return pdrive->thiscd.trk[CARRAY(track)].data; 0491 } 0492 0493 /* 0494 * wm_cd_play(starttrack, pos, endtrack) 0495 * 0496 * Start playing the CD or jump to a new position. "pos" is in seconds, 0497 * relative to start of track. 0498 */ 0499 int wm_cd_play(void *p, int start, int pos, int end) 0500 { 0501 struct wm_drive *pdrive = (struct wm_drive *)p; 0502 int real_start, real_end, status; 0503 int play_start, play_end; 0504 0505 status = wm_cd_status(pdrive); 0506 if(WM_CDS_NO_DISC(status) || pdrive->thiscd.ntracks < 1) 0507 return -1; 0508 0509 /* 0510 * check ranges 0511 */ 0512 for(real_end = pdrive->thiscd.ntracks; 0513 (pdrive->thiscd.trk[CARRAY(real_end)].data == DATATRACK); 0514 real_end--) 0515 ; 0516 for(real_start = 1; 0517 (pdrive->thiscd.trk[CARRAY(real_start)].data == DATATRACK); 0518 real_start++) 0519 ; 0520 0521 if(end == WM_ENDTRACK) 0522 end = real_end; 0523 else if(end > real_end) 0524 end = real_end; 0525 0526 /* 0527 * handle as overrun 0528 */ 0529 if(start < real_start) 0530 start = real_start; 0531 if(start > real_end) 0532 start = real_end; 0533 0534 /* 0535 * Try to avoid mixed mode and CD-EXTRA data tracks 0536 */ 0537 if(start > end || pdrive->thiscd.trk[CARRAY(start)].data == DATATRACK) { 0538 wm_cd_stop(pdrive); 0539 return -1; 0540 } 0541 0542 play_start = pdrive->thiscd.trk[CARRAY(start)].start + pos * 75; 0543 play_end = (end == pdrive->thiscd.ntracks) ? pdrive->thiscd.length * 75 : 0544 pdrive->thiscd.trk[CARRAY(end)].start - 1; 0545 0546 --play_end; 0547 0548 if (play_start >= play_end) 0549 play_start = play_end-1; 0550 0551 if(pdrive->proto.play) 0552 pdrive->proto.play(pdrive, play_start, play_end); 0553 else 0554 return -1; 0555 0556 /* So we don't update the display with the old frame number */ 0557 wm_cd_status(pdrive); 0558 0559 return pdrive->thiscd.curtrack; 0560 } 0561 0562 /* 0563 * wm_cd_pause() 0564 * 0565 * Pause the CD, if it's in play mode. If it's already paused, go back to 0566 * play mode. 0567 */ 0568 int wm_cd_pause(void *p) 0569 { 0570 struct wm_drive *pdrive = (struct wm_drive *)p; 0571 static int paused_pos; 0572 int status; 0573 0574 status = wm_cd_status(pdrive); 0575 if(WM_CDS_NO_DISC(status)) 0576 return -1; 0577 0578 if(WM_CDM_PLAYING == pdrive->thiscd.cur_cdmode) { 0579 paused_pos = pdrive->thiscd.cur_pos_rel; 0580 if(pdrive->proto.pause) 0581 return pdrive->proto.pause(pdrive); 0582 } else if(WM_CDM_PAUSED == status) { 0583 if(pdrive->proto.resume) 0584 return pdrive->proto.resume(pdrive); 0585 else if(pdrive->proto.play) 0586 return pdrive->proto.play(pdrive, pdrive->thiscd.cur_pos_rel, -1); 0587 } 0588 0589 return -1; 0590 } /* wm_cd_pause() */ 0591 0592 /* 0593 * wm_cd_stop() 0594 * 0595 * Stop the CD if it's not already stopped. 0596 */ 0597 int wm_cd_stop(void *p) 0598 { 0599 struct wm_drive *pdrive = (struct wm_drive *)p; 0600 int status; 0601 0602 status = wm_cd_status(pdrive); 0603 if(WM_CDS_NO_DISC(status)) 0604 return -1; 0605 0606 if (status != WM_CDM_STOPPED) { 0607 0608 if(pdrive->proto.stop) 0609 pdrive->proto.stop(pdrive); 0610 0611 status = wm_cd_status(pdrive); 0612 } 0613 0614 return (status != WM_CDM_STOPPED); 0615 } /* wm_cd_stop() */ 0616 0617 /* 0618 * Eject the current CD, if there is one, and set the mode to 5. 0619 * 0620 * Returns 0 on success, 1 if the CD couldn't be ejected, or 2 if the 0621 * CD contains a mounted filesystem. 0622 */ 0623 int wm_cd_eject(void *p) 0624 { 0625 struct wm_drive *pdrive = (struct wm_drive *)p; 0626 int err = -1; 0627 0628 if(pdrive->proto.eject) 0629 err = pdrive->proto.eject(pdrive); 0630 0631 if (err < 0) { 0632 if (err == -3) { 0633 return 2; 0634 } else { 0635 return 1; 0636 } 0637 } 0638 0639 return (WM_CDM_EJECTED == wm_cd_status(pdrive)) ? 0 : -1; 0640 } 0641 0642 int wm_cd_closetray(void *p) 0643 { 0644 struct wm_drive *pdrive = (struct wm_drive *)p; 0645 int status, err = -1; 0646 0647 status = wm_cd_status(pdrive); 0648 if (status == WM_CDM_UNKNOWN || status == WM_CDM_NO_DISC) 0649 return -1; 0650 0651 #ifdef CAN_CLOSE 0652 err = pdrive->proto.closetray(pdrive); 0653 0654 if(err) { 0655 /* do close/open */ 0656 if(!pdrive->proto.close(pdrive)) { 0657 wm_susleep( 1000 ); 0658 err = pdrive->proto.open(pdrive); 0659 wm_susleep( 1000 ); 0660 } 0661 } 0662 0663 #else 0664 err = 0; 0665 #endif 0666 0667 return (err ? 0 : ((wm_cd_status(pdrive) == 2) ? 1 : 0)); 0668 } /* wm_cd_closetray() */ 0669 0670 struct cdtext_info* wm_cd_get_cdtext(void *p) 0671 { 0672 struct wm_drive *pdrive = (struct wm_drive *)p; 0673 int status; 0674 0675 status = wm_cd_status(pdrive); 0676 0677 if(WM_CDS_NO_DISC(status)) 0678 return NULL; 0679 0680 return get_glob_cdtext(pdrive, 0); 0681 } 0682 0683 int wm_cd_set_verbosity(int level) 0684 { 0685 wm_lib_set_verbosity(level); 0686 return wm_lib_get_verbosity(); 0687 } 0688 0689 /* 0690 * volume is valid WM_VOLUME_MUTE <= vol <= WM_VOLUME_MAXIMAL, 0691 * balance is valid WM_BALANCE_ALL_LEFTS <= balance <= WM_BALANCE_ALL_RIGHTS 0692 */ 0693 0694 int wm_cd_volume(void *p, int vol, int bal) 0695 { 0696 struct wm_drive *pdrive = (struct wm_drive *)p; 0697 int left, right; 0698 const int bal1 = (vol - WM_VOLUME_MUTE)/(WM_BALANCE_ALL_RIGHTS - WM_BALANCE_SYMMETRED); 0699 0700 /* 0701 * Set "left" and "right" to volume-slider values accounting for the 0702 * balance setting. 0703 * 0704 */ 0705 if(vol < WM_VOLUME_MUTE) 0706 vol = WM_VOLUME_MUTE; 0707 if(vol > WM_VOLUME_MAXIMAL) 0708 vol = WM_VOLUME_MAXIMAL; 0709 if(bal < WM_BALANCE_ALL_LEFTS) 0710 bal = WM_BALANCE_ALL_LEFTS; 0711 if(bal > WM_BALANCE_ALL_RIGHTS) 0712 bal = WM_BALANCE_ALL_RIGHTS; 0713 0714 left = vol - (bal * bal1); 0715 right = vol + (bal * bal1); 0716 0717 wm_lib_message(WM_MSG_LEVEL_DEBUG|WM_MSG_CLASS, "calculate volume left %i, right %i\n", left, right); 0718 0719 if (left > WM_VOLUME_MAXIMAL) 0720 left = WM_VOLUME_MAXIMAL; 0721 if (right > WM_VOLUME_MAXIMAL) 0722 right = WM_VOLUME_MAXIMAL; 0723 0724 if(pdrive->proto.scale_volume) 0725 pdrive->proto.scale_volume(&left, &right); 0726 0727 if(pdrive->proto.set_volume) 0728 return pdrive->proto.set_volume(pdrive, left, right); 0729 0730 return -1; 0731 } /* cd_volume() */ 0732 0733 int wm_cd_getvolume(void *p) 0734 { 0735 struct wm_drive *pdrive = (struct wm_drive *)p; 0736 int left, right; 0737 0738 if(!pdrive->proto.get_volume || 0739 pdrive->proto.get_volume(pdrive, &left, &right) < 0 || left == -1) 0740 return -1; 0741 0742 if(pdrive->proto.unscale_volume) 0743 pdrive->proto.unscale_volume(&left, &right); 0744 0745 if (left < right) { 0746 pdrive->thiscd.cd_cur_balance = (right - left) / 2; 0747 if (pdrive->thiscd.cd_cur_balance > WM_BALANCE_ALL_RIGHTS) 0748 pdrive->thiscd.cd_cur_balance = WM_BALANCE_ALL_RIGHTS; 0749 return right; 0750 } else if (left == right) { 0751 pdrive->thiscd.cd_cur_balance = WM_BALANCE_SYMMETRED; 0752 return left; 0753 } else { 0754 pdrive->thiscd.cd_cur_balance = (right - left) / 2; 0755 if (pdrive->thiscd.cd_cur_balance < WM_BALANCE_ALL_LEFTS) 0756 pdrive->thiscd.cd_cur_balance = WM_BALANCE_ALL_LEFTS; 0757 return left; 0758 } 0759 } 0760 0761 int wm_cd_getbalance(void *p) 0762 { 0763 struct wm_drive *pdrive = (struct wm_drive *)p; 0764 int left, right; 0765 0766 if(!pdrive->proto.get_volume || 0767 pdrive->proto.get_volume(pdrive, &left, &right) < 0 || left == -1) 0768 return WM_BALANCE_SYMMETRED; 0769 0770 if(pdrive->proto.unscale_volume) 0771 pdrive->proto.unscale_volume(&left, &right); 0772 0773 if (left < right) { 0774 pdrive->thiscd.cd_cur_balance = (right - left) / 2; 0775 if (pdrive->thiscd.cd_cur_balance > WM_BALANCE_ALL_RIGHTS) 0776 pdrive->thiscd.cd_cur_balance = WM_BALANCE_ALL_RIGHTS; 0777 } else if (left == right) { 0778 pdrive->thiscd.cd_cur_balance = WM_BALANCE_SYMMETRED; 0779 } else { 0780 pdrive->thiscd.cd_cur_balance = (right - left) / 2; 0781 if (pdrive->thiscd.cd_cur_balance < WM_BALANCE_ALL_LEFTS) 0782 pdrive->thiscd.cd_cur_balance = WM_BALANCE_ALL_LEFTS; 0783 } 0784 return pdrive->thiscd.cd_cur_balance; 0785 } 0786 0787 static const char *gen_status(int status) 0788 { 0789 static char tmp[250]; 0790 0791 switch(status) { 0792 case WM_CDM_TRACK_DONE: 0793 return "WM_CDM_TRACK_DONE"; 0794 case WM_CDM_PLAYING: 0795 return "WM_CDM_PLAYING"; 0796 case WM_CDM_FORWARD: 0797 return "WM_CDM_FORWARD"; 0798 case WM_CDM_PAUSED: 0799 return "WM_CDM_PAUSED"; 0800 case WM_CDM_STOPPED: 0801 return "WM_CDM_STOPPED"; 0802 case WM_CDM_EJECTED: 0803 return "WM_CDM_EJECTED"; 0804 case WM_CDM_DEVICECHANGED: 0805 return "WM_CDM_DEVICECHANGED"; 0806 case WM_CDM_NO_DISC: 0807 return "WM_CDM_NO_DISC"; 0808 case WM_CDM_UNKNOWN: 0809 return "WM_CDM_UNKNOWN"; 0810 case WM_CDM_CDDAERROR: 0811 return "WM_CDM_CDDAERROR"; 0812 case WM_CDM_CDDAACK: 0813 return "WM_CDM_CDDAACK"; 0814 case WM_CDM_LOADING: 0815 return "WM_CDM_LOADING"; 0816 case WM_CDM_BUFFERING: 0817 return "WM_CDM_BUFFERING"; 0818 default: 0819 sprintf(tmp, "unexpected status %i", status); 0820 return tmp; 0821 } 0822 }