1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 * Main file for CD-ROM support
5 * Copyright 1994 Martin Ayotte
6 * Copyright 1999 Eric Pouech
7 * Copyright 2000 Andreas Mohr
15 #include <sys/ioctl.h>
19 #include "debugtools.h"
22 DEFAULT_DEBUG_CHANNEL(cdrom
);
24 #define MAX_CDAUDIO_TRACKS 256
26 #define CDROM_OPEN(wcda,parentdev) \
27 (((parentdev) == -1) ? CDROM_OpenDev(wcda) : (parentdev))
29 #define CDROM_CLOSE(dev,parentdev) \
30 (((parentdev) == -1) ? CDROM_CloseDev(dev) : 0)
32 /**************************************************************************
33 * CDROM_Open [internal]
36 * or -1 (figure it out)
38 int CDROM_Open(WINE_CDAUDIO
* wcda
, int drive
)
46 for (i
=0; i
< MAX_DOS_DRIVES
; i
++, root
[0]++)
47 if (GetDriveTypeA(root
) == DRIVE_CDROM
)
59 WARN("No CD-ROM #%d found !\n", drive
);
62 if ((wcda
->devname
= DRIVE_GetDevice(drive
)) == NULL
)
64 WARN("No device entry for CD-ROM #%d (drive %c:) found !\n",
69 /* Test whether device can be opened */
70 dev
= CDROM_OpenDev(wcda
);
76 wcda
->cdaMode
= WINE_CDA_OPEN
; /* to force reading tracks info */
79 wcda
->dwFirstFrame
= 0;
80 wcda
->dwLastFrame
= 0;
81 wcda
->lpdwTrackLen
= NULL
;
82 wcda
->lpdwTrackPos
= NULL
;
83 wcda
->lpbTrackFlags
= NULL
;
84 TRACE("opened drive %c: (device %s)\n", 'A' + drive
, wcda
->devname
);
88 /**************************************************************************
89 * CDROM_OpenDev [internal]
92 int CDROM_OpenDev(WINE_CDAUDIO
* wcda
)
94 int dev
= open(wcda
->devname
, O_RDONLY
| O_NONBLOCK
, 0);
96 WARN("can't open device '%s'! (%s)\n", wcda
->devname
, strerror(errno
));
98 TRACE("-> %d\n", dev
);
102 /**************************************************************************
103 * CDROM_GetMediaType [internal]
105 int CDROM_GetMediaType(WINE_CDAUDIO
* wcda
, int parentdev
)
109 int dev
= CDROM_OPEN( wcda
, parentdev
);
110 type
= ioctl(dev
, CDROM_DISC_STATUS
);
111 CDROM_CLOSE( dev
, parentdev
);
113 TRACE("-> %d\n", type
);
117 /**************************************************************************
118 * CDROM_Close [internal]
120 int CDROM_CloseDev(int dev
)
126 /**************************************************************************
127 * CDROM_Close [internal]
129 int CDROM_Close(WINE_CDAUDIO
* wcda
)
131 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
132 if (wcda
->lpdwTrackLen
!= NULL
) free(wcda
->lpdwTrackLen
);
133 if (wcda
->lpdwTrackPos
!= NULL
) free(wcda
->lpdwTrackPos
);
134 if (wcda
->lpbTrackFlags
!= NULL
) free(wcda
->lpbTrackFlags
);
135 TRACE("%s\n", wcda
->devname
);
142 /**************************************************************************
143 * CDROM_Get_UPC [internal]
145 * upc has to be 14 bytes long
147 int CDROM_Get_UPC(WINE_CDAUDIO
* wcda
, LPSTR upc
, int parentdev
)
150 struct cdrom_mcn mcn
;
151 int dev
= CDROM_OPEN( wcda
, parentdev
);
152 int status
= ioctl(dev
, CDROM_GET_MCN
, &mcn
);
153 CDROM_CLOSE( dev
, parentdev
);
156 ERR("ioctl() failed with code %d\n",status
);
159 strcpy(upc
, mcn
.medium_catalog_number
);
166 /**************************************************************************
167 * CDROM_Audio_GetNumberOfTracks [internal]
169 UINT16
CDROM_Audio_GetNumberOfTracks(WINE_CDAUDIO
* wcda
, int parentdev
)
171 UINT16 ret
= (UINT16
)-1;
172 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
174 struct cdrom_tochdr hdr
;
176 struct ioc_toc_header hdr
;
178 int dev
= CDROM_OPEN( wcda
, parentdev
);
180 if (wcda
->nTracks
== 0) {
182 if (ioctl(dev
, CDROMREADTOCHDR
, &hdr
))
184 if (ioctl(dev
, CDIOREADTOCHEADER
, &hdr
))
187 WARN("(%p) -- Error occurred (%s)!\n", wcda
, strerror(errno
));
191 wcda
->nFirstTrack
= hdr
.cdth_trk0
;
192 wcda
->nLastTrack
= hdr
.cdth_trk1
;
194 wcda
->nFirstTrack
= hdr
.starting_track
;
195 wcda
->nLastTrack
= hdr
.ending_track
;
197 wcda
->nTracks
= wcda
->nLastTrack
- wcda
->nFirstTrack
+ 1;
201 CDROM_CLOSE( dev
, parentdev
);
206 /**************************************************************************
207 * CDROM_Audio_GetTracksInfo [internal]
209 BOOL
CDROM_Audio_GetTracksInfo(WINE_CDAUDIO
* wcda
, int parentdev
)
212 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
214 int start
, last_start
= 0;
215 int total_length
= 0;
217 struct cdrom_tocentry entry
;
219 struct ioc_read_toc_entry entry
;
220 struct cd_toc_entry toc_buffer
;
222 int dev
= CDROM_OPEN( wcda
, parentdev
);
224 if (wcda
->nTracks
== 0) {
225 if (CDROM_Audio_GetNumberOfTracks(wcda
, dev
) == (WORD
)-1)
228 TRACE("nTracks=%u\n", wcda
->nTracks
);
230 if (wcda
->lpdwTrackLen
!= NULL
)
231 free(wcda
->lpdwTrackLen
);
232 wcda
->lpdwTrackLen
= (LPDWORD
)malloc((wcda
->nTracks
+ 1) * sizeof(DWORD
));
233 if (wcda
->lpdwTrackPos
!= NULL
)
234 free(wcda
->lpdwTrackPos
);
235 wcda
->lpdwTrackPos
= (LPDWORD
)malloc((wcda
->nTracks
+ 1) * sizeof(DWORD
));
236 if (wcda
->lpbTrackFlags
!= NULL
)
237 free(wcda
->lpbTrackFlags
);
238 wcda
->lpbTrackFlags
= (LPBYTE
)malloc((wcda
->nTracks
+ 1) * sizeof(BYTE
));
239 if (wcda
->lpdwTrackLen
== NULL
|| wcda
->lpdwTrackPos
== NULL
||
240 wcda
->lpbTrackFlags
== NULL
) {
241 WARN("error allocating track table !\n");
244 memset(wcda
->lpdwTrackLen
, 0, (wcda
->nTracks
+ 1) * sizeof(DWORD
));
245 memset(wcda
->lpdwTrackPos
, 0, (wcda
->nTracks
+ 1) * sizeof(DWORD
));
246 memset(wcda
->lpbTrackFlags
, 0, (wcda
->nTracks
+ 1) * sizeof(BYTE
));
247 for (i
= 0; i
<= wcda
->nTracks
; i
++) {
248 if (i
== wcda
->nTracks
)
250 entry
.cdte_track
= CDROM_LEADOUT
;
253 entry
.starting_track
= LEADOUT
; /* FIXME */
257 entry
.cdte_track
= i
+ 1;
259 entry
.starting_track
= i
+ 1;
262 entry
.cdte_format
= CDROM_MSF
;
264 memset((char *)&toc_buffer
, 0, sizeof(toc_buffer
));
265 entry
.address_format
= CD_MSF_FORMAT
;
266 entry
.data_len
= sizeof(toc_buffer
);
267 entry
.data
= &toc_buffer
;
270 if (ioctl(dev
, CDROMREADTOCENTRY
, &entry
))
272 if (ioctl(dev
, CDIOREADTOCENTRYS
, &entry
))
275 WARN("error read entry (%s)\n", strerror(errno
));
276 /* update status according to new status */
277 CDROM_Audio_GetCDStatus(wcda
, dev
);
282 start
= CDFRAMES_PERSEC
* (SECONDS_PERMIN
*
283 entry
.cdte_addr
.msf
.minute
+ entry
.cdte_addr
.msf
.second
) +
284 entry
.cdte_addr
.msf
.frame
;
286 start
= CDFRAMES_PERSEC
* (SECONDS_PERMIN
*
287 toc_buffer
.addr
.msf
.minute
+ toc_buffer
.addr
.msf
.second
) +
288 toc_buffer
.addr
.msf
.frame
;
292 wcda
->dwFirstFrame
= start
;
293 TRACE("dwFirstOffset=%u\n", start
);
295 length
= start
- last_start
;
297 start
= last_start
- length
;
298 total_length
+= length
;
299 wcda
->lpdwTrackLen
[i
- 1] = length
;
300 wcda
->lpdwTrackPos
[i
- 1] = start
;
301 TRACE("track #%u start=%u len=%u\n", i
, start
, length
);
304 wcda
->lpbTrackFlags
[i
] =
305 (entry
.cdte_adr
<< 4) | (entry
.cdte_ctrl
& 0x0f);
307 wcda
->lpbTrackFlags
[i
] =
308 (toc_buffer
.addr_type
<< 4) | (toc_buffer
.control
& 0x0f);
310 TRACE("track #%u flags=%02x\n", i
+ 1, wcda
->lpbTrackFlags
[i
]);
312 wcda
->dwLastFrame
= last_start
;
313 TRACE("total_len=%u\n", total_length
);
316 CDROM_CLOSE( dev
, parentdev
);
321 /**************************************************************************
322 * CDROM_Audio_GetCDStatus [internal]
324 BOOL
CDROM_Audio_GetCDStatus(WINE_CDAUDIO
* wcda
, int parentdev
)
326 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
327 int oldmode
= wcda
->cdaMode
;
329 int dev
= CDROM_OPEN( wcda
, parentdev
);
331 wcda
->sc
.cdsc_format
= CDROM_MSF
;
333 struct ioc_read_subchannel read_sc
;
335 read_sc
.address_format
= CD_MSF_FORMAT
;
336 read_sc
.data_format
= CD_CURRENT_POSITION
;
338 read_sc
.data_len
= sizeof(wcda
->sc
);
339 read_sc
.data
= (struct cd_sub_channel_info
*)&wcda
->sc
;
342 if (ioctl(dev
, CDROMSUBCHNL
, &wcda
->sc
))
344 if (ioctl(dev
, CDIOCREADSUBCHANNEL
, &read_sc
))
347 TRACE("opened or no_media (%s)!\n", strerror(errno
));
348 wcda
->cdaMode
= WINE_CDA_OPEN
; /* was NOT_READY */
353 wcda
->sc
.cdsc_audiostatus
355 wcda
->sc
.header
.audio_status
359 case CDROM_AUDIO_INVALID
:
361 case CD_AS_AUDIO_INVALID
:
363 /* seems that this means stop for ide drives */
364 wcda
->cdaMode
= WINE_CDA_STOP
;
365 TRACE("AUDIO_INVALID -> WINE_CDA_STOP\n");
368 case CDROM_AUDIO_NO_STATUS
:
370 case CD_AS_NO_STATUS
:
372 wcda
->cdaMode
= WINE_CDA_STOP
;
373 TRACE("WINE_CDA_STOP !\n");
376 case CDROM_AUDIO_PLAY
:
378 case CD_AS_PLAY_IN_PROGRESS
:
380 wcda
->cdaMode
= WINE_CDA_PLAY
;
383 case CDROM_AUDIO_PAUSED
:
385 case CD_AS_PLAY_PAUSED
:
387 wcda
->cdaMode
= WINE_CDA_PAUSE
;
388 TRACE("WINE_CDA_PAUSE !\n");
392 TRACE("status=%02X !\n",
393 wcda
->sc
.cdsc_audiostatus
);
395 TRACE("status=%02X !\n",
396 wcda
->sc
.header
.audio_status
);
400 wcda
->nCurTrack
= wcda
->sc
.cdsc_trk
;
402 CDFRAMES_PERMIN
* wcda
->sc
.cdsc_absaddr
.msf
.minute
+
403 CDFRAMES_PERSEC
* wcda
->sc
.cdsc_absaddr
.msf
.second
+
404 wcda
->sc
.cdsc_absaddr
.msf
.frame
;
406 wcda
->nCurTrack
= wcda
->sc
.what
.position
.track_number
;
408 CDFRAMES_PERMIN
* wcda
->sc
.what
.position
.absaddr
.msf
.minute
+
409 CDFRAMES_PERSEC
* wcda
->sc
.what
.position
.absaddr
.msf
.second
+
410 wcda
->sc
.what
.position
.absaddr
.msf
.frame
;
413 TRACE("%02u-%02u:%02u:%02u\n",
415 wcda
->sc
.cdsc_absaddr
.msf
.minute
,
416 wcda
->sc
.cdsc_absaddr
.msf
.second
,
417 wcda
->sc
.cdsc_absaddr
.msf
.frame
);
419 TRACE("%02u-%02u:%02u:%02u\n",
420 wcda
->sc
.what
.position
.track_number
,
421 wcda
->sc
.what
.position
.absaddr
.msf
.minute
,
422 wcda
->sc
.what
.position
.absaddr
.msf
.second
,
423 wcda
->sc
.what
.position
.absaddr
.msf
.frame
);
426 if (oldmode
!= wcda
->cdaMode
&& oldmode
== WINE_CDA_OPEN
) {
427 if (!CDROM_Audio_GetTracksInfo(wcda
, dev
)) {
428 WARN("error updating TracksInfo !\n");
432 if (wcda
->cdaMode
!= WINE_CDA_OPEN
)
435 CDROM_CLOSE( dev
, parentdev
);
442 /**************************************************************************
443 * CDROM_Audio_Play [internal]
445 int CDROM_Audio_Play(WINE_CDAUDIO
* wcda
, DWORD start
, DWORD end
, int parentdev
)
448 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
450 struct cdrom_msf msf
;
452 struct ioc_play_msf msf
;
454 int dev
= CDROM_OPEN( wcda
, parentdev
);
457 msf
.cdmsf_min0
= start
/ CDFRAMES_PERMIN
;
458 msf
.cdmsf_sec0
= (start
% CDFRAMES_PERMIN
) / CDFRAMES_PERSEC
;
459 msf
.cdmsf_frame0
= start
% CDFRAMES_PERSEC
;
460 msf
.cdmsf_min1
= end
/ CDFRAMES_PERMIN
;
461 msf
.cdmsf_sec1
= (end
% CDFRAMES_PERMIN
) / CDFRAMES_PERSEC
;
462 msf
.cdmsf_frame1
= end
% CDFRAMES_PERSEC
;
464 msf
.start_m
= start
/ CDFRAMES_PERMIN
;
465 msf
.start_s
= (start
% CDFRAMES_PERMIN
) / CDFRAMES_PERSEC
;
466 msf
.start_f
= start
% CDFRAMES_PERSEC
;
467 msf
.end_m
= end
/ CDFRAMES_PERMIN
;
468 msf
.end_s
= (end
% CDFRAMES_PERMIN
) / CDFRAMES_PERSEC
;
469 msf
.end_f
= end
% CDFRAMES_PERSEC
;
472 if (ioctl(dev
, CDROMSTART
))
474 if (ioctl(dev
, CDIOCSTART
, NULL
))
477 WARN("motor doesn't start !\n");
481 if (ioctl(dev
, CDROMPLAYMSF
, &msf
))
483 if (ioctl(dev
, CDIOCPLAYMSF
, &msf
))
486 WARN("device doesn't play !\n");
490 TRACE("msf = %d:%d:%d %d:%d:%d\n",
491 msf
.cdmsf_min0
, msf
.cdmsf_sec0
, msf
.cdmsf_frame0
,
492 msf
.cdmsf_min1
, msf
.cdmsf_sec1
, msf
.cdmsf_frame1
);
494 TRACE("msf = %d:%d:%d %d:%d:%d\n",
495 msf
.start_m
, msf
.start_s
, msf
.start_f
,
496 msf
.end_m
, msf
.end_s
, msf
.end_f
);
500 CDROM_CLOSE( dev
, parentdev
);
505 /**************************************************************************
506 * CDROM_Audio_Stop [internal]
508 int CDROM_Audio_Stop(WINE_CDAUDIO
* wcda
, int parentdev
)
511 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
512 int dev
= CDROM_OPEN( wcda
, parentdev
);
514 ret
= ioctl(dev
, CDROMSTOP
);
516 ret
= ioctl(dev
, CDIOCSTOP
, NULL
);
518 CDROM_CLOSE( dev
, parentdev
);
523 /**************************************************************************
524 * CDROM_Audio_Pause [internal]
526 int CDROM_Audio_Pause(WINE_CDAUDIO
* wcda
, int pauseOn
, int parentdev
)
529 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
530 int dev
= CDROM_OPEN( wcda
, parentdev
);
532 ret
= ioctl(dev
, pauseOn
? CDROMPAUSE
: CDROMRESUME
);
534 ret
= ioctl(dev
, pauseOn
? CDIOCPAUSE
: CDIOCRESUME
, NULL
);
536 CDROM_CLOSE( dev
, parentdev
);
541 /**************************************************************************
542 * CDROM_Audio_Seek [internal]
544 int CDROM_Audio_Seek(WINE_CDAUDIO
* wcda
, DWORD at
, int parentdev
)
547 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
548 int dev
= CDROM_OPEN( wcda
, parentdev
);
550 struct cdrom_msf0 msf
;
551 msf
.minute
= at
/ CDFRAMES_PERMIN
;
552 msf
.second
= (at
% CDFRAMES_PERMIN
) / CDFRAMES_PERSEC
;
553 msf
.frame
= at
% CDFRAMES_PERSEC
;
555 ret
= ioctl(dev
, CDROMSEEK
, &msf
);
557 /* FIXME: the current end for play is lost
558 * use end of CD ROM instead
560 FIXME("Could a BSD expert implement the seek function ?\n");
561 CDROM_Audio_Play(wcda
, at
, wcda
->lpdwTrackPos
[wcda
->nTracks
] + wcda
->lpdwTrackLen
[wcda
->nTracks
], dev
);
563 CDROM_CLOSE( dev
, parentdev
);
568 /**************************************************************************
569 * CDROM_SetDoor [internal]
571 int CDROM_SetDoor(WINE_CDAUDIO
* wcda
, int open
, int parentdev
)
574 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
575 int dev
= CDROM_OPEN( wcda
, parentdev
);
580 ret
= ioctl(dev
, CDROMEJECT
);
582 ret
= ioctl(dev
, CDROMCLOSETRAY
);
585 ret
= (ioctl(dev
, CDIOCALLOW
, NULL
)) ||
586 (ioctl(dev
, open
? CDIOCEJECT
: CDIOCCLOSE
, NULL
)) ||
587 (ioctl(dev
, CDIOCPREVENT
, NULL
));
591 WARN("failed (%s)\n", strerror(errno
));
592 CDROM_CLOSE( dev
, parentdev
);
597 /**************************************************************************
598 * CDROM_Reset [internal]
600 int CDROM_Reset(WINE_CDAUDIO
* wcda
, int parentdev
)
603 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
604 int dev
= CDROM_OPEN( wcda
, parentdev
);
606 ret
= ioctl(dev
, CDROMRESET
);
608 ret
= ioctl(dev
, CDIOCRESET
, NULL
);
610 CDROM_CLOSE( dev
, parentdev
);
615 WORD
CDROM_Data_FindBestVoldesc(int fd
)
617 BYTE cur_vd_type
, max_vd_type
= 0;
618 unsigned int offs
, best_offs
= 0;
620 for (offs
=0x8000; offs
<= 0x9800; offs
+= 0x800)
622 lseek(fd
, offs
, SEEK_SET
);
623 read(fd
, &cur_vd_type
, 1);
624 if (cur_vd_type
== 0xff) /* voldesc set terminator */
626 if (cur_vd_type
> max_vd_type
)
628 max_vd_type
= cur_vd_type
;
635 /**************************************************************************
636 * CDROM_Audio_GetSerial [internal]
638 DWORD
CDROM_Audio_GetSerial(WINE_CDAUDIO
* wcda
)
640 unsigned long serial
= 0;
643 WORD wMinutes
, wSeconds
, wFrames
;
645 DWORD dwStart
, dwEnd
;
648 * wMagic collects the wFrames from track 1
649 * dwStart, dwEnd collect the beginning and end of the disc respectively, in
651 * There it is collected for correcting the serial when there are less than
657 for (i
= 0; i
< wcda
->nTracks
; i
++) {
658 dwFrame
= wcda
->lpdwTrackPos
[i
];
659 wMinutes
= dwFrame
/ CDFRAMES_PERMIN
;
660 wSeconds
= (dwFrame
- CDFRAMES_PERMIN
* wMinutes
) / CDFRAMES_PERSEC
;
661 wFrames
= dwFrame
- CDFRAMES_PERMIN
* wMinutes
- CDFRAMES_PERSEC
* wSeconds
;
662 msf
= CDROM_MAKE_MSF(wMinutes
, wSeconds
, wFrames
);
664 serial
+= (CDROM_MSF_MINUTE(msf
) << 16) +
665 (CDROM_MSF_SECOND(msf
) << 8) +
666 (CDROM_MSF_FRAME(msf
));
673 dwEnd
= dwFrame
+ wcda
->lpdwTrackLen
[i
];
677 if (wcda
->nTracks
< 3)
679 serial
+= wMagic
+ (dwEnd
- dwStart
);
684 /**************************************************************************
685 * CDROM_Data_GetSerial [internal]
687 DWORD
CDROM_Data_GetSerial(WINE_CDAUDIO
* wcda
, int parentdev
)
689 int dev
= CDROM_OPEN( wcda
, parentdev
);
690 WORD offs
= CDROM_Data_FindBestVoldesc(dev
);
695 BYTE b0
= 0, b1
= 1, b2
= 2, b3
= 3;
704 lseek(dev
,offs
,SEEK_SET
);
707 * OK, another braindead one... argh. Just believe it.
708 * Me$$ysoft chose to reverse the serial number in NT4/W2K.
709 * It's true and nobody will ever be able to change it.
711 ovi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
713 if ((ovi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
714 && (ovi
.dwMajorVersion
>= 4))
716 b0
= 3; b1
= 2; b2
= 1; b3
= 0;
718 for(i
=0; i
<2048; i
+=4)
720 /* DON'T optimize this into DWORD !! (breaks overflow) */
721 serial
.p
[b0
] += buf
[i
+b0
];
722 serial
.p
[b1
] += buf
[i
+b1
];
723 serial
.p
[b2
] += buf
[i
+b2
];
724 serial
.p
[b3
] += buf
[i
+b3
];
727 CDROM_CLOSE( dev
, parentdev
);
731 /**************************************************************************
732 * CDROM_GetSerial [internal]
734 DWORD
CDROM_GetSerial(int drive
)
739 /* EXPIRES 01.01.2002 */
740 WARN("CD-ROM serial number calculation might fail.\n");
741 WARN("Please test with as many exotic CDs as possible !\n");
743 if (!(CDROM_Open(&wcda
, drive
)))
745 int dev
= CDROM_OpenDev(&wcda
);
746 int media
= CDROM_GetMediaType(&wcda
, dev
);
751 case CDS_MIXED
: /* mixed is basically a mountable audio CD */
752 if (!(CDROM_Audio_GetCDStatus(&wcda
, dev
))) {
753 ERR("couldn't get CD status !\n");
756 serial
= CDROM_Audio_GetSerial(&wcda
);
762 case -1: /* ioctl() error: ISO9660 image file given ? */
763 /* hopefully a data CD */
764 serial
= CDROM_Data_GetSerial(&wcda
, dev
);
767 WARN("Strange CD type (%d) or empty ?\n", media
);
770 TRACE("CD serial number is %04x-%04x.\n",
771 HIWORD(serial
), LOWORD(serial
));
773 if (media
>= CDS_AUDIO
)
774 ERR("couldn't get CD serial !\n");
782 /**************************************************************************
783 * CDROM_Data_GetLabel [internal]
785 DWORD
CDROM_Data_GetLabel(WINE_CDAUDIO
* wcda
, char *label
, int parentdev
)
787 #define LABEL_LEN 32+1
788 int dev
= CDROM_OPEN( wcda
, parentdev
);
789 WORD offs
= CDROM_Data_FindBestVoldesc(dev
);
790 WCHAR label_read
[LABEL_LEN
]; /* Unicode possible, too */
791 DWORD unicode_id
= 0;
795 if ((lseek(dev
, offs
+0x58, SEEK_SET
) == offs
+0x58)
796 && (read(dev
, &unicode_id
, 3) == 3))
798 int ver
= (unicode_id
& 0xff0000) >> 16;
800 if ((lseek(dev
, offs
+0x28, SEEK_SET
) != offs
+0x28)
801 || (read(dev
, &label_read
, LABEL_LEN
) != LABEL_LEN
))
804 CDROM_CLOSE( dev
, parentdev
);
805 if ((LOWORD(unicode_id
) == 0x2f25) /* Unicode ID */
806 && ((ver
== 0x40) || (ver
== 0x43) || (ver
== 0x45)))
807 { /* yippee, unicode */
810 for (i
=0; i
<LABEL_LEN
;i
++)
811 { /* Motorola -> Intel Unicode conversion :-\ */
813 label_read
[i
] = (ch
<< 8) | (ch
>> 8);
815 WideCharToMultiByte( CP_ACP
, 0, label_read
, -1, label
, 12, NULL
, NULL
);
820 strncpy(label
, (LPSTR
)label_read
, 11);
827 CDROM_CLOSE( dev
, parentdev
);
828 ERR("error reading label !\n");
832 /**************************************************************************
833 * CDROM_GetLabel [internal]
835 DWORD
CDROM_GetLabel(int drive
, char *label
)
840 if (!(CDROM_Open(&wcda
, drive
)))
842 int dev
= CDROM_OpenDev(&wcda
);
843 int media
= CDROM_GetMediaType(&wcda
, dev
);
850 strcpy(label
, "Audio CD ");
853 case CDS_DATA_1
: /* fall through for all data CD types !! */
854 if (!cdname
) cdname
= "Data_1";
856 if (!cdname
) cdname
= "Data_2";
858 if (!cdname
) cdname
= "XA 2.1";
860 if (!cdname
) cdname
= "XA 2.2";
862 if (!cdname
) cdname
= "Unknown/ISO file";
864 /* common code *here* !! */
865 /* hopefully a data CD */
866 if (!CDROM_Data_GetLabel(&wcda
, label
, dev
))
871 cdname
= "Mixed mode";
872 ERR("We don't have a way of determining the label of a mixed mode CD - Linux doesn't allow raw access !!\n");
876 if (!cdname
) cdname
= "No_info";
881 WARN("Strange CD type (%d) or empty ?\n", media
);
882 cdname
= "Strange/empty";
889 TRACE("%s CD: label is '%s'.\n",