If we have a drive pointing to /, we must not remove the final / or we
[wine.git] / misc / cdrom.c
blobadc7337c3fe6a5fea9bcb5c684d32d4c514842b7
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3 * Main file for CD-ROM support
5 * Copyright 1994 Martin Ayotte
6 * Copyright 1999 Eric Pouech
7 * Copyright 2000 Andreas Mohr
8 */
10 #include "config.h"
12 #include <errno.h>
13 #include <string.h>
14 #include <fcntl.h>
15 #include <sys/ioctl.h>
16 #include "cdrom.h"
17 #include "drive.h"
18 #include "debugtools.h"
19 #include "winbase.h"
20 #include "wine/winestring.h"
22 DEFAULT_DEBUG_CHANNEL(cdrom);
24 #define MAX_CDAUDIO_TRACKS 256
26 /**************************************************************************
27 * CDROM_Open [internal]
29 * drive = 0, 1, ...
30 * or -1 (figure it out)
32 int CDROM_Open(WINE_CDAUDIO* wcda, int drive)
34 int i;
35 BOOL avail = FALSE;
36 const char *dev;
38 if (drive == -1)
40 for (i=0; i < MAX_DOS_DRIVES; i++)
41 if (DRIVE_GetType(i) == TYPE_CDROM)
43 drive = i;
44 avail = TRUE;
45 break;
48 else
49 avail = TRUE;
51 if (avail == FALSE)
53 WARN("No CD-ROM #%d found !\n", drive);
54 return -1;
56 if ((dev = DRIVE_GetDevice(drive)) == NULL)
58 WARN("No device entry for CD-ROM #%d (drive %c:) found !\n",
59 drive, 'A' + drive);
60 return -1;
63 wcda->unixdev = open(dev, O_RDONLY | O_NONBLOCK, 0);
64 if (wcda->unixdev == -1) {
65 WARN("can't open '%s'!. %s\n", dev, strerror(errno));
66 return -1;
68 wcda->cdaMode = WINE_CDA_OPEN; /* to force reading tracks info */
69 wcda->nCurTrack = 0;
70 wcda->nTracks = 0;
71 wcda->dwFirstFrame = 0;
72 wcda->dwLastFrame = 0;
73 wcda->lpdwTrackLen = NULL;
74 wcda->lpdwTrackPos = NULL;
75 wcda->lpbTrackFlags = NULL;
76 return 0;
79 /**************************************************************************
80 * CDROM_GetMediaType [internal]
82 int CDROM_GetMediaType(WINE_CDAUDIO* wcda)
84 #ifdef linux
85 return ioctl(wcda->unixdev, CDROM_DISC_STATUS);
86 #else
87 return -1;
88 #endif
91 /**************************************************************************
92 * CDROM_Close [internal]
94 int CDROM_Close(WINE_CDAUDIO* wcda)
96 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
97 if (wcda->lpdwTrackLen != NULL) free(wcda->lpdwTrackLen);
98 if (wcda->lpdwTrackPos != NULL) free(wcda->lpdwTrackPos);
99 if (wcda->lpbTrackFlags != NULL) free(wcda->lpbTrackFlags);
100 close(wcda->unixdev);
101 return 0;
102 #else
103 return -1;
104 #endif
107 /**************************************************************************
108 * CDROM_Get_UPC [internal]
110 * upc has to be 14 bytes long
112 int CDROM_Get_UPC(WINE_CDAUDIO* wcda, LPSTR upc)
114 #ifdef linux
115 struct cdrom_mcn mcn;
116 int status = ioctl(wcda->unixdev, CDROM_GET_MCN, &mcn);
117 if (status)
119 ERR("ioctl() failed with code %d\n",status);
120 return -1;
122 strcpy(upc, mcn.medium_catalog_number);
123 return 0;
124 #else
125 return -1;
126 #endif
129 /**************************************************************************
130 * CDROM_Audio_GetNumberOfTracks [internal]
132 UINT16 CDROM_Audio_GetNumberOfTracks(WINE_CDAUDIO* wcda)
134 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
135 #ifdef linux
136 struct cdrom_tochdr hdr;
137 #else
138 struct ioc_toc_header hdr;
139 #endif
141 if (wcda->nTracks == 0) {
142 #ifdef linux
143 if (ioctl(wcda->unixdev, CDROMREADTOCHDR, &hdr))
144 #else
145 if (ioctl(wcda->unixdev, CDIOREADTOCHEADER, &hdr))
146 #endif
148 WARN("(%p) -- Error occurred (%d)!\n", wcda, errno);
149 return (WORD)-1;
151 #ifdef linux
152 wcda->nFirstTrack = hdr.cdth_trk0;
153 wcda->nLastTrack = hdr.cdth_trk1;
154 #else
155 wcda->nFirstTrack = hdr.starting_track;
156 wcda->nLastTrack = hdr.ending_track;
157 #endif
158 wcda->nTracks = wcda->nLastTrack - wcda->nFirstTrack + 1;
160 return wcda->nTracks;
161 #else
162 return (WORD)-1;
163 #endif
166 /**************************************************************************
167 * CDROM_Audio_GetTracksInfo [internal]
169 BOOL CDROM_Audio_GetTracksInfo(WINE_CDAUDIO* wcda)
171 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
172 int i, length;
173 int start, last_start = 0;
174 int total_length = 0;
175 #ifdef linux
176 struct cdrom_tocentry entry;
177 #else
178 struct ioc_read_toc_entry entry;
179 struct cd_toc_entry toc_buffer;
180 #endif
182 if (wcda->nTracks == 0) {
183 if (CDROM_Audio_GetNumberOfTracks(wcda) == (WORD)-1) return FALSE;
185 TRACE("nTracks=%u\n", wcda->nTracks);
187 if (wcda->lpdwTrackLen != NULL)
188 free(wcda->lpdwTrackLen);
189 wcda->lpdwTrackLen = (LPDWORD)malloc((wcda->nTracks + 1) * sizeof(DWORD));
190 if (wcda->lpdwTrackPos != NULL)
191 free(wcda->lpdwTrackPos);
192 wcda->lpdwTrackPos = (LPDWORD)malloc((wcda->nTracks + 1) * sizeof(DWORD));
193 if (wcda->lpbTrackFlags != NULL)
194 free(wcda->lpbTrackFlags);
195 wcda->lpbTrackFlags = (LPBYTE)malloc((wcda->nTracks + 1) * sizeof(BYTE));
196 if (wcda->lpdwTrackLen == NULL || wcda->lpdwTrackPos == NULL ||
197 wcda->lpbTrackFlags == NULL) {
198 WARN("error allocating track table !\n");
199 return FALSE;
201 memset(wcda->lpdwTrackLen, 0, (wcda->nTracks + 1) * sizeof(DWORD));
202 memset(wcda->lpdwTrackPos, 0, (wcda->nTracks + 1) * sizeof(DWORD));
203 memset(wcda->lpbTrackFlags, 0, (wcda->nTracks + 1) * sizeof(BYTE));
204 for (i = 0; i <= wcda->nTracks; i++) {
205 if (i == wcda->nTracks)
206 #ifdef linux
207 entry.cdte_track = CDROM_LEADOUT;
208 #else
209 #define LEADOUT 0xaa
210 entry.starting_track = LEADOUT; /* FIXME */
211 #endif
212 else
213 #ifdef linux
214 entry.cdte_track = i + 1;
215 #else
216 entry.starting_track = i + 1;
217 #endif
218 #ifdef linux
219 entry.cdte_format = CDROM_MSF;
220 #else
221 bzero((char *)&toc_buffer, sizeof(toc_buffer));
222 entry.address_format = CD_MSF_FORMAT;
223 entry.data_len = sizeof(toc_buffer);
224 entry.data = &toc_buffer;
225 #endif
226 #ifdef linux
227 if (ioctl(wcda->unixdev, CDROMREADTOCENTRY, &entry))
228 #else
229 if (ioctl(wcda->unixdev, CDIOREADTOCENTRYS, &entry))
230 #endif
232 WARN("error read entry (%s)\n", strerror(errno));
233 /* update status according to new status */
234 CDROM_Audio_GetCDStatus(wcda);
236 return FALSE;
238 #ifdef linux
239 start = CDFRAMES_PERSEC * (SECONDS_PERMIN *
240 entry.cdte_addr.msf.minute + entry.cdte_addr.msf.second) +
241 entry.cdte_addr.msf.frame;
242 #else
243 start = CDFRAMES_PERSEC * (SECONDS_PERMIN *
244 toc_buffer.addr.msf.minute + toc_buffer.addr.msf.second) +
245 toc_buffer.addr.msf.frame;
246 #endif
247 if (i == 0) {
248 last_start = start;
249 wcda->dwFirstFrame = start;
250 TRACE("dwFirstOffset=%u\n", start);
251 } else {
252 length = start - last_start;
253 last_start = start;
254 start = last_start - length;
255 total_length += length;
256 wcda->lpdwTrackLen[i - 1] = length;
257 wcda->lpdwTrackPos[i - 1] = start;
258 TRACE("track #%u start=%u len=%u\n", i, start, length);
260 #ifdef linux
261 wcda->lpbTrackFlags[i] =
262 (entry.cdte_adr << 4) | (entry.cdte_ctrl & 0x0f);
263 #else
264 wcda->lpbTrackFlags[i] =
265 (toc_buffer.addr_type << 4) | (toc_buffer.control & 0x0f);
266 #endif
267 TRACE("track #%u flags=%02x\n", i + 1, wcda->lpbTrackFlags[i]);
269 wcda->dwLastFrame = last_start;
270 TRACE("total_len=%u\n", total_length);
271 return TRUE;
272 #else
273 return FALSE;
274 #endif
277 /**************************************************************************
278 * CDROM_Audio_GetCDStatus [internal]
280 BOOL CDROM_Audio_GetCDStatus(WINE_CDAUDIO* wcda)
282 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
283 int oldmode = wcda->cdaMode;
284 #ifdef linux
285 wcda->sc.cdsc_format = CDROM_MSF;
286 #else
287 struct ioc_read_subchannel read_sc;
289 read_sc.address_format = CD_MSF_FORMAT;
290 read_sc.data_format = CD_CURRENT_POSITION;
291 read_sc.track = 0;
292 read_sc.data_len = sizeof(wcda->sc);
293 read_sc.data = (struct cd_sub_channel_info *)&wcda->sc;
294 #endif
295 #ifdef linux
296 if (ioctl(wcda->unixdev, CDROMSUBCHNL, &wcda->sc))
297 #else
298 if (ioctl(wcda->unixdev, CDIOCREADSUBCHANNEL, &read_sc))
299 #endif
301 TRACE("opened or no_media (%s)!\n", strerror(errno));
302 wcda->cdaMode = WINE_CDA_OPEN; /* was NOT_READY */
303 return TRUE;
305 switch (
306 #ifdef linux
307 wcda->sc.cdsc_audiostatus
308 #else
309 wcda->sc.header.audio_status
310 #endif
312 #ifdef linux
313 case CDROM_AUDIO_INVALID:
314 #else
315 case CD_AS_AUDIO_INVALID:
316 #endif
317 WARN("device doesn't support status.\n");
318 wcda->cdaMode = WINE_CDA_DONTKNOW;
319 break;
320 #ifdef linux
321 case CDROM_AUDIO_NO_STATUS:
322 #else
323 case CD_AS_NO_STATUS:
324 #endif
325 wcda->cdaMode = WINE_CDA_STOP;
326 TRACE("WINE_CDA_STOP !\n");
327 break;
328 #ifdef linux
329 case CDROM_AUDIO_PLAY:
330 #else
331 case CD_AS_PLAY_IN_PROGRESS:
332 #endif
333 wcda->cdaMode = WINE_CDA_PLAY;
334 break;
335 #ifdef linux
336 case CDROM_AUDIO_PAUSED:
337 #else
338 case CD_AS_PLAY_PAUSED:
339 #endif
340 wcda->cdaMode = WINE_CDA_PAUSE;
341 TRACE("WINE_CDA_PAUSE !\n");
342 break;
343 default:
344 #ifdef linux
345 TRACE("status=%02X !\n",
346 wcda->sc.cdsc_audiostatus);
347 #else
348 TRACE("status=%02X !\n",
349 wcda->sc.header.audio_status);
350 #endif
352 #ifdef linux
353 wcda->nCurTrack = wcda->sc.cdsc_trk;
354 wcda->dwCurFrame =
355 CDFRAMES_PERMIN * wcda->sc.cdsc_absaddr.msf.minute +
356 CDFRAMES_PERSEC * wcda->sc.cdsc_absaddr.msf.second +
357 wcda->sc.cdsc_absaddr.msf.frame;
358 #else
359 wcda->nCurTrack = wcda->sc.what.position.track_number;
360 wcda->dwCurFrame =
361 CDFRAMES_PERMIN * wcda->sc.what.position.absaddr.msf.minute +
362 CDFRAMES_PERSEC * wcda->sc.what.position.absaddr.msf.second +
363 wcda->sc.what.position.absaddr.msf.frame;
364 #endif
365 #ifdef linux
366 TRACE("%02u-%02u:%02u:%02u\n",
367 wcda->sc.cdsc_trk,
368 wcda->sc.cdsc_absaddr.msf.minute,
369 wcda->sc.cdsc_absaddr.msf.second,
370 wcda->sc.cdsc_absaddr.msf.frame);
371 #else
372 TRACE("%02u-%02u:%02u:%02u\n",
373 wcda->sc.what.position.track_number,
374 wcda->sc.what.position.absaddr.msf.minute,
375 wcda->sc.what.position.absaddr.msf.second,
376 wcda->sc.what.position.absaddr.msf.frame);
377 #endif
379 if (oldmode != wcda->cdaMode && oldmode == WINE_CDA_OPEN) {
380 if (!CDROM_Audio_GetTracksInfo(wcda)) {
381 WARN("error updating TracksInfo !\n");
382 return FALSE;
385 return TRUE;
386 #else
387 return FALSE;
388 #endif
391 /**************************************************************************
392 * CDROM_Audio_Play [internal]
394 int CDROM_Audio_Play(WINE_CDAUDIO* wcda, DWORD start, DWORD end)
396 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
397 #ifdef linux
398 struct cdrom_msf msf;
399 #else
400 struct ioc_play_msf msf;
401 #endif
403 #ifdef linux
404 msf.cdmsf_min0 = start / CDFRAMES_PERMIN;
405 msf.cdmsf_sec0 = (start % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
406 msf.cdmsf_frame0 = start % CDFRAMES_PERSEC;
407 msf.cdmsf_min1 = end / CDFRAMES_PERMIN;
408 msf.cdmsf_sec1 = (end % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
409 msf.cdmsf_frame1 = end % CDFRAMES_PERSEC;
410 #else
411 msf.start_m = start / CDFRAMES_PERMIN;
412 msf.start_s = (start % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
413 msf.start_f = start % CDFRAMES_PERSEC;
414 msf.end_m = end / CDFRAMES_PERMIN;
415 msf.end_s = (end % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
416 msf.end_f = end % CDFRAMES_PERSEC;
417 #endif
418 #ifdef linux
419 if (ioctl(wcda->unixdev, CDROMSTART))
420 #else
421 if (ioctl(wcda->unixdev, CDIOCSTART, NULL))
422 #endif
424 WARN("motor doesn't start !\n");
425 return -1;
427 #ifdef linux
428 if (ioctl(wcda->unixdev, CDROMPLAYMSF, &msf))
429 #else
430 if (ioctl(wcda->unixdev, CDIOCPLAYMSF, &msf))
431 #endif
433 WARN("device doesn't play !\n");
434 return -1;
436 #ifdef linux
437 TRACE("msf = %d:%d:%d %d:%d:%d\n",
438 msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0,
439 msf.cdmsf_min1, msf.cdmsf_sec1, msf.cdmsf_frame1);
440 #else
441 TRACE("msf = %d:%d:%d %d:%d:%d\n",
442 msf.start_m, msf.start_s, msf.start_f,
443 msf.end_m, msf.end_s, msf.end_f);
444 #endif
445 return 0;
446 #else
447 return -1;
448 #endif
451 /**************************************************************************
452 * CDROM_Audio_Stop [internal]
454 int CDROM_Audio_Stop(WINE_CDAUDIO* wcda)
456 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
457 int ret = 0;
458 #ifdef linux
459 ret = ioctl(wcda->unixdev, CDROMSTOP);
460 #else
461 ret = ioctl(wcda->unixdev, CDIOCSTOP, NULL);
462 #endif
463 return ret;
464 #else
465 return -1;
466 #endif
469 /**************************************************************************
470 * CDROM_Audio_Pause [internal]
472 int CDROM_Audio_Pause(WINE_CDAUDIO* wcda, int pauseOn)
474 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
475 int ret = 0;
476 #ifdef linux
477 ret = ioctl(wcda->unixdev, pauseOn ? CDROMPAUSE : CDROMRESUME);
478 #else
479 ret = ioctl(wcda->unixdev, pauseOn ? CDIOCPAUSE : CDIOCRESUME, NULL);
480 #endif
481 return ret;
482 #else
483 return -1;
484 #endif
487 /**************************************************************************
488 * CDROM_Audio_Seek [internal]
490 int CDROM_Audio_Seek(WINE_CDAUDIO* wcda, DWORD at)
492 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
493 int ret = 0;
494 #ifdef linux
495 struct cdrom_msf0 msf;
496 msf.minute = at / CDFRAMES_PERMIN;
497 msf.second = (at % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
498 msf.frame = at % CDFRAMES_PERSEC;
500 ret = ioctl(wcda->unixdev, CDROMSEEK, &msf);
501 #else
502 /* FIXME: the current end for play is lost
503 * use end of CD ROM instead
505 FIXME("Could a BSD expert implement the seek function ?\n");
506 CDROM_Audio_Play(wcda, at, wcda->lpdwTrackPos[wcda->nTracks] + wcda->lpdwTrackLen[wcda->nTracks]);
508 #endif
509 return ret;
510 #else
511 return -1;
512 #endif
515 /**************************************************************************
516 * CDROM_SetDoor [internal]
518 int CDROM_SetDoor(WINE_CDAUDIO* wcda, int open)
520 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
521 int ret = 0;
522 #ifdef linux
523 if (open) {
524 ret = ioctl(wcda->unixdev, CDROMEJECT);
525 } else {
526 ret = ioctl(wcda->unixdev, CDROMEJECT, 1);
528 #else
529 ret = (ioctl(wcda->unixdev, CDIOCALLOW, NULL)) ||
530 (ioctl(wcda->unixdev, open ? CDIOCEJECT : CDIOCCLOSE, NULL)) ||
531 (ioctl(wcda->unixdev, CDIOCPREVENT, NULL));
532 #endif
533 wcda->nTracks = 0;
534 return ret;
535 #else
536 return -1;
537 #endif
540 /**************************************************************************
541 * CDROM_Reset [internal]
543 int CDROM_Reset(WINE_CDAUDIO* wcda)
545 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
546 int ret = 0;
547 #ifdef linux
548 ret = ioctl(wcda->unixdev, CDROMRESET);
549 #else
550 ret = ioctl(wcda->unixdev, CDIOCRESET, NULL);
551 #endif
552 return ret;
553 #else
554 return -1;
555 #endif
558 WORD CDROM_Data_FindBestVoldesc(int fd)
560 BYTE cur_vd_type, max_vd_type = 0;
561 unsigned int offs, best_offs = 0;
563 for (offs=0x8000; offs <= 0x9800; offs += 0x800)
565 lseek(fd, offs, SEEK_SET);
566 read(fd, &cur_vd_type, 1);
567 if (cur_vd_type == 0xff) /* voldesc set terminator */
568 break;
569 if (cur_vd_type > max_vd_type)
571 max_vd_type = cur_vd_type;
572 best_offs = offs;
575 return best_offs;
578 /**************************************************************************
579 * CDROM_Audio_GetSerial [internal]
581 DWORD CDROM_Audio_GetSerial(WINE_CDAUDIO* wcda)
583 unsigned long serial = 0;
584 int i;
585 DWORD dwFrame, msf;
586 WORD wMinutes, wSeconds, wFrames;
587 WORD wMagic;
588 DWORD dwStart, dwEnd;
591 * wMagic collects the wFrames from track 1
592 * dwStart, dwEnd collect the beginning and end of the disc respectively, in
593 * frames.
594 * There it is collected for correcting the serial when there are less than
595 * 3 tracks.
597 wMagic = 0;
598 dwStart = dwEnd = 0;
600 for (i = 0; i < wcda->nTracks; i++) {
601 dwFrame = wcda->lpdwTrackPos[i];
602 wMinutes = dwFrame / CDFRAMES_PERMIN;
603 wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
604 wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;
605 msf = CDROM_MAKE_MSF(wMinutes, wSeconds, wFrames);
607 serial += (CDROM_MSF_MINUTE(msf) << 16) +
608 (CDROM_MSF_SECOND(msf) << 8) +
609 (CDROM_MSF_FRAME(msf));
611 if (i==0)
613 wMagic = wFrames;
614 dwStart = dwFrame;
616 dwEnd = dwFrame + wcda->lpdwTrackLen[i];
620 if (wcda->nTracks < 3)
622 serial += wMagic + (dwEnd - dwStart);
624 return serial;
627 /**************************************************************************
628 * CDROM_Data_GetSerial [internal]
630 DWORD CDROM_Data_GetSerial(WINE_CDAUDIO* wcda)
632 WORD offs = CDROM_Data_FindBestVoldesc(wcda->unixdev);
633 union {
634 unsigned long val;
635 unsigned char p[4];
636 } serial;
637 BYTE b0 = 0, b1 = 1, b2 = 2, b3 = 3;
639 serial.val = 0;
640 if (offs)
642 BYTE buf[2048];
643 OSVERSIONINFOA ovi;
644 int i;
646 lseek(wcda->unixdev,offs,SEEK_SET);
647 read(wcda->unixdev,buf,2048);
649 * OK, another braindead one... argh. Just believe it.
650 * Me$$ysoft chose to reverse the serial number in NT4/W2K.
651 * It's true and nobody will ever be able to change it.
653 ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
654 GetVersionExA(&ovi);
655 if ((ovi.dwPlatformId == VER_PLATFORM_WIN32_NT)
656 && (ovi.dwMajorVersion >= 4))
658 b0 = 3; b1 = 2; b2 = 1; b3 = 0;
660 for(i=0; i<2048; i+=4)
662 /* DON'T optimize this into DWORD !! (breaks overflow) */
663 serial.p[b0] += buf[i+b0];
664 serial.p[b1] += buf[i+b1];
665 serial.p[b2] += buf[i+b2];
666 serial.p[b3] += buf[i+b3];
669 return serial.val;
672 /**************************************************************************
673 * CDROM_GetSerial [internal]
675 DWORD CDROM_GetSerial(int drive)
677 WINE_CDAUDIO wcda;
678 DWORD serial = 0;
680 /* EXPIRES 01.01.2002 */
681 WARN("CD-ROM serial number calculation might fail.\n");
682 WARN("Please test with as many exotic CDs as possible !\n");
684 if (!(CDROM_Open(&wcda, drive)))
686 int media = CDROM_GetMediaType(&wcda);
687 LPSTR p;
689 if (media == CDS_AUDIO)
691 if (!(CDROM_Audio_GetCDStatus(&wcda))) {
692 ERR("couldn't get CD status !\n");
693 CDROM_Close(&wcda);
694 return 0;
696 serial = CDROM_Audio_GetSerial(&wcda);
698 else
699 if ((media > CDS_AUDIO)
700 || (media == -1) /* ioctl() error: ISO9660 image file given ? */
702 /* hopefully a data CD */
703 serial = CDROM_Data_GetSerial(&wcda);
704 else
705 WARN("Strange CD type (%d) or empty ?\n", media);
707 p = (media == CDS_AUDIO) ? "Audio " :
708 (media > CDS_AUDIO) ? "Data " : "";
709 if (serial)
710 TRACE("%sCD serial number is %04x-%04x.\n",
711 p, HIWORD(serial), LOWORD(serial));
712 else
713 if (media >= CDS_AUDIO)
714 ERR("couldn't get %sCD serial !\n", p);
715 CDROM_Close(&wcda);
717 return serial;
720 static const char empty_label[] = " ";
722 /**************************************************************************
723 * CDROM_Data_GetLabel [internal]
725 DWORD CDROM_Data_GetLabel(WINE_CDAUDIO* wcda, char *label)
727 #define LABEL_LEN 32+1
728 WORD offs = CDROM_Data_FindBestVoldesc(wcda->unixdev);
729 WCHAR label_read[LABEL_LEN]; /* Unicode possible, too */
730 DWORD unicode_id = 0;
732 if (offs)
734 if ((lseek(wcda->unixdev, offs+0x58, SEEK_SET) == offs+0x58)
735 && (read(wcda->unixdev, &unicode_id, 3) == 3))
737 int ver = (unicode_id & 0xff0000) >> 16;
739 if ((lseek(wcda->unixdev, offs+0x28, SEEK_SET) != offs+0x28)
740 || (read(wcda->unixdev, &label_read, LABEL_LEN) != LABEL_LEN))
741 goto failure;
743 if ((LOWORD(unicode_id) == 0x2f25) /* Unicode ID */
744 && ((ver == 0x40) || (ver == 0x43) || (ver == 0x45)))
745 { /* yippee, unicode */
746 int i;
747 WORD ch;
748 for (i=0; i<LABEL_LEN;i++)
749 { /* Motorola -> Intel Unicode conversion :-\ */
750 ch = label_read[i];
751 label_read[i] = (ch << 8) | (ch >> 8);
753 lstrcpynWtoA(label, label_read, 11);
755 else
757 strncpy(label, (LPSTR)label_read, 11);
758 label[11] = '\0';
760 return 0;
763 failure:
764 ERR("error reading label !\n");
765 strcpy(label, empty_label);
766 return 0;
769 /**************************************************************************
770 * CDROM_GetLabel [internal]
772 DWORD CDROM_GetLabel(int drive, char *label)
774 WINE_CDAUDIO wcda;
775 DWORD res = 1;
777 if (!(CDROM_Open(&wcda, drive)))
779 int media = CDROM_GetMediaType(&wcda);
780 LPSTR p;
782 if (media == CDS_AUDIO)
784 strcpy(label, "Audio CD ");
786 else
787 if (media == CDS_NO_INFO)
789 strcpy(label, empty_label);
791 else
792 if ((media > CDS_AUDIO)
793 || (media == -1) /* ioctl() error: ISO9660 image file given ? */
795 /* hopefully a data CD */
796 CDROM_Data_GetLabel(&wcda, label);
797 else
799 WARN("Strange CD type (%d) or empty ?\n", media);
800 strcpy(label, empty_label);
801 res = 0;
804 p = (media == CDS_AUDIO) ? "Audio " :
805 (media > CDS_AUDIO) ? "Data " : "";
806 TRACE("%sCD label is '%s'.\n",
807 p, label);
808 CDROM_Close(&wcda);
810 else
811 res = 0;
813 return res;