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
)
45 for (i
=0; i
< MAX_DOS_DRIVES
; i
++)
46 if (DRIVE_GetType(i
) == TYPE_CDROM
)
58 WARN("No CD-ROM #%d found !\n", drive
);
61 if ((wcda
->devname
= DRIVE_GetDevice(drive
)) == NULL
)
63 WARN("No device entry for CD-ROM #%d (drive %c:) found !\n",
68 /* Test whether device can be opened */
69 dev
= CDROM_OpenDev(wcda
);
75 wcda
->cdaMode
= WINE_CDA_OPEN
; /* to force reading tracks info */
78 wcda
->dwFirstFrame
= 0;
79 wcda
->dwLastFrame
= 0;
80 wcda
->lpdwTrackLen
= NULL
;
81 wcda
->lpdwTrackPos
= NULL
;
82 wcda
->lpbTrackFlags
= NULL
;
83 TRACE("opened drive %c: (device %s)\n", 'A' + drive
, wcda
->devname
);
87 /**************************************************************************
88 * CDROM_OpenDev [internal]
91 int CDROM_OpenDev(WINE_CDAUDIO
* wcda
)
93 int dev
= open(wcda
->devname
, O_RDONLY
| O_NONBLOCK
, 0);
95 WARN("can't open device '%s'! (%s)\n", wcda
->devname
, strerror(errno
));
97 TRACE("-> %d\n", dev
);
101 /**************************************************************************
102 * CDROM_GetMediaType [internal]
104 int CDROM_GetMediaType(WINE_CDAUDIO
* wcda
, int parentdev
)
108 int dev
= CDROM_OPEN( wcda
, parentdev
);
109 type
= ioctl(dev
, CDROM_DISC_STATUS
);
110 CDROM_CLOSE( dev
, parentdev
);
112 TRACE("-> %d\n", type
);
116 /**************************************************************************
117 * CDROM_Close [internal]
119 int CDROM_CloseDev(int dev
)
125 /**************************************************************************
126 * CDROM_Close [internal]
128 int CDROM_Close(WINE_CDAUDIO
* wcda
)
130 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
131 if (wcda
->lpdwTrackLen
!= NULL
) free(wcda
->lpdwTrackLen
);
132 if (wcda
->lpdwTrackPos
!= NULL
) free(wcda
->lpdwTrackPos
);
133 if (wcda
->lpbTrackFlags
!= NULL
) free(wcda
->lpbTrackFlags
);
134 TRACE("%s\n", wcda
->devname
);
141 /**************************************************************************
142 * CDROM_Get_UPC [internal]
144 * upc has to be 14 bytes long
146 int CDROM_Get_UPC(WINE_CDAUDIO
* wcda
, LPSTR upc
, int parentdev
)
149 struct cdrom_mcn mcn
;
150 int dev
= CDROM_OPEN( wcda
, parentdev
);
151 int status
= ioctl(dev
, CDROM_GET_MCN
, &mcn
);
152 CDROM_CLOSE( dev
, parentdev
);
155 ERR("ioctl() failed with code %d\n",status
);
158 strcpy(upc
, mcn
.medium_catalog_number
);
165 /**************************************************************************
166 * CDROM_Audio_GetNumberOfTracks [internal]
168 UINT16
CDROM_Audio_GetNumberOfTracks(WINE_CDAUDIO
* wcda
, int parentdev
)
170 UINT16 ret
= (UINT16
)-1;
171 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
173 struct cdrom_tochdr hdr
;
175 struct ioc_toc_header hdr
;
177 int dev
= CDROM_OPEN( wcda
, parentdev
);
179 if (wcda
->nTracks
== 0) {
181 if (ioctl(dev
, CDROMREADTOCHDR
, &hdr
))
183 if (ioctl(dev
, CDIOREADTOCHEADER
, &hdr
))
186 WARN("(%p) -- Error occurred (%s)!\n", wcda
, strerror(errno
));
190 wcda
->nFirstTrack
= hdr
.cdth_trk0
;
191 wcda
->nLastTrack
= hdr
.cdth_trk1
;
193 wcda
->nFirstTrack
= hdr
.starting_track
;
194 wcda
->nLastTrack
= hdr
.ending_track
;
196 wcda
->nTracks
= wcda
->nLastTrack
- wcda
->nFirstTrack
+ 1;
200 CDROM_CLOSE( dev
, parentdev
);
205 /**************************************************************************
206 * CDROM_Audio_GetTracksInfo [internal]
208 BOOL
CDROM_Audio_GetTracksInfo(WINE_CDAUDIO
* wcda
, int parentdev
)
211 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
213 int start
, last_start
= 0;
214 int total_length
= 0;
216 struct cdrom_tocentry entry
;
218 struct ioc_read_toc_entry entry
;
219 struct cd_toc_entry toc_buffer
;
221 int dev
= CDROM_OPEN( wcda
, parentdev
);
223 if (wcda
->nTracks
== 0) {
224 if (CDROM_Audio_GetNumberOfTracks(wcda
, dev
) == (WORD
)-1)
227 TRACE("nTracks=%u\n", wcda
->nTracks
);
229 if (wcda
->lpdwTrackLen
!= NULL
)
230 free(wcda
->lpdwTrackLen
);
231 wcda
->lpdwTrackLen
= (LPDWORD
)malloc((wcda
->nTracks
+ 1) * sizeof(DWORD
));
232 if (wcda
->lpdwTrackPos
!= NULL
)
233 free(wcda
->lpdwTrackPos
);
234 wcda
->lpdwTrackPos
= (LPDWORD
)malloc((wcda
->nTracks
+ 1) * sizeof(DWORD
));
235 if (wcda
->lpbTrackFlags
!= NULL
)
236 free(wcda
->lpbTrackFlags
);
237 wcda
->lpbTrackFlags
= (LPBYTE
)malloc((wcda
->nTracks
+ 1) * sizeof(BYTE
));
238 if (wcda
->lpdwTrackLen
== NULL
|| wcda
->lpdwTrackPos
== NULL
||
239 wcda
->lpbTrackFlags
== NULL
) {
240 WARN("error allocating track table !\n");
243 memset(wcda
->lpdwTrackLen
, 0, (wcda
->nTracks
+ 1) * sizeof(DWORD
));
244 memset(wcda
->lpdwTrackPos
, 0, (wcda
->nTracks
+ 1) * sizeof(DWORD
));
245 memset(wcda
->lpbTrackFlags
, 0, (wcda
->nTracks
+ 1) * sizeof(BYTE
));
246 for (i
= 0; i
<= wcda
->nTracks
; i
++) {
247 if (i
== wcda
->nTracks
)
249 entry
.cdte_track
= CDROM_LEADOUT
;
252 entry
.starting_track
= LEADOUT
; /* FIXME */
256 entry
.cdte_track
= i
+ 1;
258 entry
.starting_track
= i
+ 1;
261 entry
.cdte_format
= CDROM_MSF
;
263 bzero((char *)&toc_buffer
, sizeof(toc_buffer
));
264 entry
.address_format
= CD_MSF_FORMAT
;
265 entry
.data_len
= sizeof(toc_buffer
);
266 entry
.data
= &toc_buffer
;
269 if (ioctl(dev
, CDROMREADTOCENTRY
, &entry
))
271 if (ioctl(dev
, CDIOREADTOCENTRYS
, &entry
))
274 WARN("error read entry (%s)\n", strerror(errno
));
275 /* update status according to new status */
276 CDROM_Audio_GetCDStatus(wcda
, dev
);
281 start
= CDFRAMES_PERSEC
* (SECONDS_PERMIN
*
282 entry
.cdte_addr
.msf
.minute
+ entry
.cdte_addr
.msf
.second
) +
283 entry
.cdte_addr
.msf
.frame
;
285 start
= CDFRAMES_PERSEC
* (SECONDS_PERMIN
*
286 toc_buffer
.addr
.msf
.minute
+ toc_buffer
.addr
.msf
.second
) +
287 toc_buffer
.addr
.msf
.frame
;
291 wcda
->dwFirstFrame
= start
;
292 TRACE("dwFirstOffset=%u\n", start
);
294 length
= start
- last_start
;
296 start
= last_start
- length
;
297 total_length
+= length
;
298 wcda
->lpdwTrackLen
[i
- 1] = length
;
299 wcda
->lpdwTrackPos
[i
- 1] = start
;
300 TRACE("track #%u start=%u len=%u\n", i
, start
, length
);
303 wcda
->lpbTrackFlags
[i
] =
304 (entry
.cdte_adr
<< 4) | (entry
.cdte_ctrl
& 0x0f);
306 wcda
->lpbTrackFlags
[i
] =
307 (toc_buffer
.addr_type
<< 4) | (toc_buffer
.control
& 0x0f);
309 TRACE("track #%u flags=%02x\n", i
+ 1, wcda
->lpbTrackFlags
[i
]);
311 wcda
->dwLastFrame
= last_start
;
312 TRACE("total_len=%u\n", total_length
);
315 CDROM_CLOSE( dev
, parentdev
);
320 /**************************************************************************
321 * CDROM_Audio_GetCDStatus [internal]
323 BOOL
CDROM_Audio_GetCDStatus(WINE_CDAUDIO
* wcda
, int parentdev
)
325 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
326 int oldmode
= wcda
->cdaMode
;
328 int dev
= CDROM_OPEN( wcda
, parentdev
);
330 wcda
->sc
.cdsc_format
= CDROM_MSF
;
332 struct ioc_read_subchannel read_sc
;
334 read_sc
.address_format
= CD_MSF_FORMAT
;
335 read_sc
.data_format
= CD_CURRENT_POSITION
;
337 read_sc
.data_len
= sizeof(wcda
->sc
);
338 read_sc
.data
= (struct cd_sub_channel_info
*)&wcda
->sc
;
341 if (ioctl(dev
, CDROMSUBCHNL
, &wcda
->sc
))
343 if (ioctl(dev
, CDIOCREADSUBCHANNEL
, &read_sc
))
346 TRACE("opened or no_media (%s)!\n", strerror(errno
));
347 wcda
->cdaMode
= WINE_CDA_OPEN
; /* was NOT_READY */
352 wcda
->sc
.cdsc_audiostatus
354 wcda
->sc
.header
.audio_status
358 case CDROM_AUDIO_INVALID
:
360 case CD_AS_AUDIO_INVALID
:
362 WARN("device doesn't support status.\n");
363 wcda
->cdaMode
= WINE_CDA_DONTKNOW
;
366 case CDROM_AUDIO_NO_STATUS
:
368 case CD_AS_NO_STATUS
:
370 wcda
->cdaMode
= WINE_CDA_STOP
;
371 TRACE("WINE_CDA_STOP !\n");
374 case CDROM_AUDIO_PLAY
:
376 case CD_AS_PLAY_IN_PROGRESS
:
378 wcda
->cdaMode
= WINE_CDA_PLAY
;
381 case CDROM_AUDIO_PAUSED
:
383 case CD_AS_PLAY_PAUSED
:
385 wcda
->cdaMode
= WINE_CDA_PAUSE
;
386 TRACE("WINE_CDA_PAUSE !\n");
390 TRACE("status=%02X !\n",
391 wcda
->sc
.cdsc_audiostatus
);
393 TRACE("status=%02X !\n",
394 wcda
->sc
.header
.audio_status
);
398 wcda
->nCurTrack
= wcda
->sc
.cdsc_trk
;
400 CDFRAMES_PERMIN
* wcda
->sc
.cdsc_absaddr
.msf
.minute
+
401 CDFRAMES_PERSEC
* wcda
->sc
.cdsc_absaddr
.msf
.second
+
402 wcda
->sc
.cdsc_absaddr
.msf
.frame
;
404 wcda
->nCurTrack
= wcda
->sc
.what
.position
.track_number
;
406 CDFRAMES_PERMIN
* wcda
->sc
.what
.position
.absaddr
.msf
.minute
+
407 CDFRAMES_PERSEC
* wcda
->sc
.what
.position
.absaddr
.msf
.second
+
408 wcda
->sc
.what
.position
.absaddr
.msf
.frame
;
411 TRACE("%02u-%02u:%02u:%02u\n",
413 wcda
->sc
.cdsc_absaddr
.msf
.minute
,
414 wcda
->sc
.cdsc_absaddr
.msf
.second
,
415 wcda
->sc
.cdsc_absaddr
.msf
.frame
);
417 TRACE("%02u-%02u:%02u:%02u\n",
418 wcda
->sc
.what
.position
.track_number
,
419 wcda
->sc
.what
.position
.absaddr
.msf
.minute
,
420 wcda
->sc
.what
.position
.absaddr
.msf
.second
,
421 wcda
->sc
.what
.position
.absaddr
.msf
.frame
);
424 if (oldmode
!= wcda
->cdaMode
&& oldmode
== WINE_CDA_OPEN
) {
425 if (!CDROM_Audio_GetTracksInfo(wcda
, dev
)) {
426 WARN("error updating TracksInfo !\n");
430 if (wcda
->cdaMode
!= WINE_CDA_OPEN
)
433 CDROM_CLOSE( dev
, parentdev
);
440 /**************************************************************************
441 * CDROM_Audio_Play [internal]
443 int CDROM_Audio_Play(WINE_CDAUDIO
* wcda
, DWORD start
, DWORD end
, int parentdev
)
446 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
448 struct cdrom_msf msf
;
450 struct ioc_play_msf msf
;
452 int dev
= CDROM_OPEN( wcda
, parentdev
);
455 msf
.cdmsf_min0
= start
/ CDFRAMES_PERMIN
;
456 msf
.cdmsf_sec0
= (start
% CDFRAMES_PERMIN
) / CDFRAMES_PERSEC
;
457 msf
.cdmsf_frame0
= start
% CDFRAMES_PERSEC
;
458 msf
.cdmsf_min1
= end
/ CDFRAMES_PERMIN
;
459 msf
.cdmsf_sec1
= (end
% CDFRAMES_PERMIN
) / CDFRAMES_PERSEC
;
460 msf
.cdmsf_frame1
= end
% CDFRAMES_PERSEC
;
462 msf
.start_m
= start
/ CDFRAMES_PERMIN
;
463 msf
.start_s
= (start
% CDFRAMES_PERMIN
) / CDFRAMES_PERSEC
;
464 msf
.start_f
= start
% CDFRAMES_PERSEC
;
465 msf
.end_m
= end
/ CDFRAMES_PERMIN
;
466 msf
.end_s
= (end
% CDFRAMES_PERMIN
) / CDFRAMES_PERSEC
;
467 msf
.end_f
= end
% CDFRAMES_PERSEC
;
470 if (ioctl(dev
, CDROMSTART
))
472 if (ioctl(dev
, CDIOCSTART
, NULL
))
475 WARN("motor doesn't start !\n");
479 if (ioctl(dev
, CDROMPLAYMSF
, &msf
))
481 if (ioctl(dev
, CDIOCPLAYMSF
, &msf
))
484 WARN("device doesn't play !\n");
488 TRACE("msf = %d:%d:%d %d:%d:%d\n",
489 msf
.cdmsf_min0
, msf
.cdmsf_sec0
, msf
.cdmsf_frame0
,
490 msf
.cdmsf_min1
, msf
.cdmsf_sec1
, msf
.cdmsf_frame1
);
492 TRACE("msf = %d:%d:%d %d:%d:%d\n",
493 msf
.start_m
, msf
.start_s
, msf
.start_f
,
494 msf
.end_m
, msf
.end_s
, msf
.end_f
);
498 CDROM_CLOSE( dev
, parentdev
);
503 /**************************************************************************
504 * CDROM_Audio_Stop [internal]
506 int CDROM_Audio_Stop(WINE_CDAUDIO
* wcda
, int parentdev
)
509 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
510 int dev
= CDROM_OPEN( wcda
, parentdev
);
512 ret
= ioctl(dev
, CDROMSTOP
);
514 ret
= ioctl(dev
, CDIOCSTOP
, NULL
);
516 CDROM_CLOSE( dev
, parentdev
);
521 /**************************************************************************
522 * CDROM_Audio_Pause [internal]
524 int CDROM_Audio_Pause(WINE_CDAUDIO
* wcda
, int pauseOn
, int parentdev
)
527 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
528 int dev
= CDROM_OPEN( wcda
, parentdev
);
530 ret
= ioctl(dev
, pauseOn
? CDROMPAUSE
: CDROMRESUME
);
532 ret
= ioctl(dev
, pauseOn
? CDIOCPAUSE
: CDIOCRESUME
, NULL
);
534 CDROM_CLOSE( dev
, parentdev
);
539 /**************************************************************************
540 * CDROM_Audio_Seek [internal]
542 int CDROM_Audio_Seek(WINE_CDAUDIO
* wcda
, DWORD at
, int parentdev
)
545 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
546 int dev
= CDROM_OPEN( wcda
, parentdev
);
548 struct cdrom_msf0 msf
;
549 msf
.minute
= at
/ CDFRAMES_PERMIN
;
550 msf
.second
= (at
% CDFRAMES_PERMIN
) / CDFRAMES_PERSEC
;
551 msf
.frame
= at
% CDFRAMES_PERSEC
;
553 ret
= ioctl(dev
, CDROMSEEK
, &msf
);
555 /* FIXME: the current end for play is lost
556 * use end of CD ROM instead
558 FIXME("Could a BSD expert implement the seek function ?\n");
559 CDROM_Audio_Play(wcda
, at
, wcda
->lpdwTrackPos
[wcda
->nTracks
] + wcda
->lpdwTrackLen
[wcda
->nTracks
], dev
);
561 CDROM_CLOSE( dev
, parentdev
);
566 /**************************************************************************
567 * CDROM_SetDoor [internal]
569 int CDROM_SetDoor(WINE_CDAUDIO
* wcda
, int open
, int parentdev
)
572 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
573 int dev
= CDROM_OPEN( wcda
, parentdev
);
578 ret
= ioctl(dev
, CDROMEJECT
);
580 ret
= ioctl(dev
, CDROMCLOSETRAY
);
583 ret
= (ioctl(dev
, CDIOCALLOW
, NULL
)) ||
584 (ioctl(dev
, open
? CDIOCEJECT
: CDIOCCLOSE
, NULL
)) ||
585 (ioctl(dev
, CDIOCPREVENT
, NULL
));
589 WARN("failed (%s)\n", strerror(errno
));
590 CDROM_CLOSE( dev
, parentdev
);
595 /**************************************************************************
596 * CDROM_Reset [internal]
598 int CDROM_Reset(WINE_CDAUDIO
* wcda
, int parentdev
)
601 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
602 int dev
= CDROM_OPEN( wcda
, parentdev
);
604 ret
= ioctl(dev
, CDROMRESET
);
606 ret
= ioctl(dev
, CDIOCRESET
, NULL
);
608 CDROM_CLOSE( dev
, parentdev
);
613 WORD
CDROM_Data_FindBestVoldesc(int fd
)
615 BYTE cur_vd_type
, max_vd_type
= 0;
616 unsigned int offs
, best_offs
= 0;
618 for (offs
=0x8000; offs
<= 0x9800; offs
+= 0x800)
620 lseek(fd
, offs
, SEEK_SET
);
621 read(fd
, &cur_vd_type
, 1);
622 if (cur_vd_type
== 0xff) /* voldesc set terminator */
624 if (cur_vd_type
> max_vd_type
)
626 max_vd_type
= cur_vd_type
;
633 /**************************************************************************
634 * CDROM_Audio_GetSerial [internal]
636 DWORD
CDROM_Audio_GetSerial(WINE_CDAUDIO
* wcda
)
638 unsigned long serial
= 0;
641 WORD wMinutes
, wSeconds
, wFrames
;
643 DWORD dwStart
, dwEnd
;
646 * wMagic collects the wFrames from track 1
647 * dwStart, dwEnd collect the beginning and end of the disc respectively, in
649 * There it is collected for correcting the serial when there are less than
655 for (i
= 0; i
< wcda
->nTracks
; i
++) {
656 dwFrame
= wcda
->lpdwTrackPos
[i
];
657 wMinutes
= dwFrame
/ CDFRAMES_PERMIN
;
658 wSeconds
= (dwFrame
- CDFRAMES_PERMIN
* wMinutes
) / CDFRAMES_PERSEC
;
659 wFrames
= dwFrame
- CDFRAMES_PERMIN
* wMinutes
- CDFRAMES_PERSEC
* wSeconds
;
660 msf
= CDROM_MAKE_MSF(wMinutes
, wSeconds
, wFrames
);
662 serial
+= (CDROM_MSF_MINUTE(msf
) << 16) +
663 (CDROM_MSF_SECOND(msf
) << 8) +
664 (CDROM_MSF_FRAME(msf
));
671 dwEnd
= dwFrame
+ wcda
->lpdwTrackLen
[i
];
675 if (wcda
->nTracks
< 3)
677 serial
+= wMagic
+ (dwEnd
- dwStart
);
682 /**************************************************************************
683 * CDROM_Data_GetSerial [internal]
685 DWORD
CDROM_Data_GetSerial(WINE_CDAUDIO
* wcda
, int parentdev
)
687 int dev
= CDROM_OPEN( wcda
, parentdev
);
688 WORD offs
= CDROM_Data_FindBestVoldesc(dev
);
693 BYTE b0
= 0, b1
= 1, b2
= 2, b3
= 3;
702 lseek(dev
,offs
,SEEK_SET
);
705 * OK, another braindead one... argh. Just believe it.
706 * Me$$ysoft chose to reverse the serial number in NT4/W2K.
707 * It's true and nobody will ever be able to change it.
709 ovi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
711 if ((ovi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
712 && (ovi
.dwMajorVersion
>= 4))
714 b0
= 3; b1
= 2; b2
= 1; b3
= 0;
716 for(i
=0; i
<2048; i
+=4)
718 /* DON'T optimize this into DWORD !! (breaks overflow) */
719 serial
.p
[b0
] += buf
[i
+b0
];
720 serial
.p
[b1
] += buf
[i
+b1
];
721 serial
.p
[b2
] += buf
[i
+b2
];
722 serial
.p
[b3
] += buf
[i
+b3
];
725 CDROM_CLOSE( dev
, parentdev
);
729 /**************************************************************************
730 * CDROM_GetSerial [internal]
732 DWORD
CDROM_GetSerial(int drive
)
737 /* EXPIRES 01.01.2002 */
738 WARN("CD-ROM serial number calculation might fail.\n");
739 WARN("Please test with as many exotic CDs as possible !\n");
741 if (!(CDROM_Open(&wcda
, drive
)))
743 int dev
= CDROM_OpenDev(&wcda
);
744 int media
= CDROM_GetMediaType(&wcda
, dev
);
749 case CDS_MIXED
: /* mixed is basically a mountable audio CD */
750 if (!(CDROM_Audio_GetCDStatus(&wcda
, dev
))) {
751 ERR("couldn't get CD status !\n");
754 serial
= CDROM_Audio_GetSerial(&wcda
);
760 case -1: /* ioctl() error: ISO9660 image file given ? */
761 /* hopefully a data CD */
762 serial
= CDROM_Data_GetSerial(&wcda
, dev
);
765 WARN("Strange CD type (%d) or empty ?\n", media
);
768 TRACE("CD serial number is %04x-%04x.\n",
769 HIWORD(serial
), LOWORD(serial
));
771 if (media
>= CDS_AUDIO
)
772 ERR("couldn't get CD serial !\n");
780 static const char empty_label
[] = " ";
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");
829 strcpy(label
, empty_label
);
833 /**************************************************************************
834 * CDROM_GetLabel [internal]
836 DWORD
CDROM_GetLabel(int drive
, char *label
)
841 if (!(CDROM_Open(&wcda
, drive
)))
843 int dev
= CDROM_OpenDev(&wcda
);
844 int media
= CDROM_GetMediaType(&wcda
, dev
);
851 strcpy(label
, "Audio CD ");
854 case CDS_DATA_1
: /* fall through for all data CD types !! */
855 if (!cdname
) cdname
= "Data_1";
857 if (!cdname
) cdname
= "Data_2";
859 if (!cdname
) cdname
= "XA 2.1";
861 if (!cdname
) cdname
= "XA 2.2";
863 if (!cdname
) cdname
= "Unknown/ISO file";
865 /* common code *here* !! */
866 /* hopefully a data CD */
867 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");
875 if (!cdname
) cdname
= "No_info";
876 strcpy(label
, empty_label
);
880 WARN("Strange CD type (%d) or empty ?\n", media
);
881 cdname
= "Strange/empty";
882 strcpy(label
, empty_label
);
889 TRACE("%s CD: label is '%s'.\n",