1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
3 * Sample CDAUDIO Wine Driver for Linux
5 * Copyright 1994 Martin Ayotte
6 * Copyright 1999 Eric Pouech
12 #include <sys/ioctl.h>
16 #if defined(__NetBSD__)
17 # define CDAUDIO_DEV "/dev/rcd0d"
18 #elif defined(__FreeBSD__)
19 # define CDAUDIO_DEV "/dev/rcd0c"
21 # define CDAUDIO_DEV "/dev/cdrom"
24 #define MAX_CDAUDIO_TRACKS 256
26 /**************************************************************************
27 * CDAUDIO_Open [internal]
29 int CDAUDIO_Open(WINE_CDAUDIO
* wcda
)
31 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
32 wcda
->unixdev
= open(CDAUDIO_DEV
, O_RDONLY
, 0);
33 if (wcda
->unixdev
== -1) {
34 WARN(cdaudio
,"can't open '%s'!. errno=%d\n", CDAUDIO_DEV
, errno
);
37 wcda
->cdaMode
= WINE_CDA_OPEN
; /* to force reading tracks info */
41 wcda
->dwFirstOffset
= 0;
42 wcda
->lpdwTrackLen
= NULL
;
43 wcda
->lpdwTrackPos
= NULL
;
44 wcda
->lpbTrackFlags
= NULL
;
52 /**************************************************************************
53 * CDAUDIO_Close [internal]
55 int CDAUDIO_Close(WINE_CDAUDIO
* wcda
)
57 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
58 if (wcda
->lpdwTrackLen
!= NULL
) free(wcda
->lpdwTrackLen
);
59 if (wcda
->lpdwTrackPos
!= NULL
) free(wcda
->lpdwTrackPos
);
60 if (wcda
->lpbTrackFlags
!= NULL
) free(wcda
->lpbTrackFlags
);
68 /**************************************************************************
69 * CDAUDIO_GetNumberOfTracks [internal]
71 UINT16
CDAUDIO_GetNumberOfTracks(WINE_CDAUDIO
* wcda
)
73 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
75 struct cdrom_tochdr hdr
;
77 struct ioc_toc_header hdr
;
80 if (wcda
->nTracks
== 0) {
82 if (ioctl(wcda
->unixdev
, CDROMREADTOCHDR
, &hdr
))
84 if (ioctl(wcda
->unixdev
, CDIOREADTOCHEADER
, &hdr
))
87 WARN(cdaudio
, "(%p) -- Error occured (%d)!\n", wcda
, errno
);
91 wcda
->nFirstTrack
= hdr
.cdth_trk0
;
92 wcda
->nLastTrack
= hdr
.cdth_trk1
;
94 wcda
->nFirstTrack
= hdr
.starting_track
;
95 wcda
->nLastTrack
= hdr
.ending_track
;
97 wcda
->nTracks
= wcda
->nLastTrack
- wcda
->nFirstTrack
+ 1;
105 /**************************************************************************
106 * CDAUDIO_GetTracksInfo [internal]
108 BOOL32
CDAUDIO_GetTracksInfo(WINE_CDAUDIO
* wcda
)
110 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
112 int start
, last_start
= 0;
113 int total_length
= 0;
115 struct cdrom_tocentry entry
;
117 struct ioc_read_toc_entry entry
;
118 struct cd_toc_entry toc_buffer
;
121 if (wcda
->nTracks
== 0) {
122 if (CDAUDIO_GetNumberOfTracks(wcda
) == (WORD
)-1) return FALSE
;
124 TRACE(cdaudio
,"nTracks=%u\n", wcda
->nTracks
);
126 if (wcda
->lpdwTrackLen
!= NULL
)
127 free(wcda
->lpdwTrackLen
);
128 wcda
->lpdwTrackLen
= (LPDWORD
)malloc((wcda
->nTracks
+ 1) * sizeof(DWORD
));
129 if (wcda
->lpdwTrackPos
!= NULL
)
130 free(wcda
->lpdwTrackPos
);
131 wcda
->lpdwTrackPos
= (LPDWORD
)malloc((wcda
->nTracks
+ 1) * sizeof(DWORD
));
132 if (wcda
->lpbTrackFlags
!= NULL
)
133 free(wcda
->lpbTrackFlags
);
134 wcda
->lpbTrackFlags
= (LPBYTE
)malloc((wcda
->nTracks
+ 1) * sizeof(BYTE
));
135 if (wcda
->lpdwTrackLen
== NULL
|| wcda
->lpdwTrackPos
== NULL
||
136 wcda
->lpbTrackFlags
== NULL
) {
137 WARN(cdaudio
, "error allocating track table !\n");
140 memset(wcda
->lpdwTrackLen
, 0, (wcda
->nTracks
+ 1) * sizeof(DWORD
));
141 memset(wcda
->lpdwTrackPos
, 0, (wcda
->nTracks
+ 1) * sizeof(DWORD
));
142 memset(wcda
->lpbTrackFlags
, 0, (wcda
->nTracks
+ 1) * sizeof(BYTE
));
143 for (i
= 0; i
<= wcda
->nTracks
; i
++) {
144 if (i
== wcda
->nTracks
)
146 entry
.cdte_track
= CDROM_LEADOUT
;
149 entry
.starting_track
= LEADOUT
; /* XXX */
153 entry
.cdte_track
= i
+ 1;
155 entry
.starting_track
= i
+ 1;
158 entry
.cdte_format
= CDROM_MSF
;
160 bzero((char *)&toc_buffer
, sizeof(toc_buffer
));
161 entry
.address_format
= CD_MSF_FORMAT
;
162 entry
.data_len
= sizeof(toc_buffer
);
163 entry
.data
= &toc_buffer
;
166 if (ioctl(wcda
->unixdev
, CDROMREADTOCENTRY
, &entry
))
168 if (ioctl(wcda
->unixdev
, CDIOREADTOCENTRYS
, &entry
))
171 WARN(cdaudio
, "error read entry (%d)\n", errno
);
172 /* update status according to new status */
173 CDAUDIO_GetCDStatus(wcda
);
178 start
= CDFRAMES_PERSEC
* (SECONDS_PERMIN
*
179 entry
.cdte_addr
.msf
.minute
+ entry
.cdte_addr
.msf
.second
) +
180 entry
.cdte_addr
.msf
.frame
;
182 start
= CDFRAMES_PERSEC
* (SECONDS_PERMIN
*
183 toc_buffer
.addr
.msf
.minute
+ toc_buffer
.addr
.msf
.second
) +
184 toc_buffer
.addr
.msf
.frame
;
188 wcda
->dwFirstOffset
= start
;
189 TRACE(cdaudio
, "dwFirstOffset=%u\n", start
);
191 length
= start
- last_start
;
193 start
= last_start
- length
;
194 total_length
+= length
;
195 wcda
->lpdwTrackLen
[i
- 1] = length
;
196 wcda
->lpdwTrackPos
[i
- 1] = start
;
197 TRACE(cdaudio
, "track #%u start=%u len=%u\n", i
, start
, length
);
200 wcda
->lpbTrackFlags
[i
] =
201 (entry
.cdte_adr
<< 4) | (entry
.cdte_ctrl
& 0x0f);
203 wcda
->lpbTrackFlags
[i
] =
204 (toc_buffer
.addr_type
<< 4) | (toc_buffer
.control
& 0x0f);
206 TRACE(cdaudio
, "track #%u flags=%02x\n", i
+ 1, wcda
->lpbTrackFlags
[i
]);
208 wcda
->dwTotalLen
= total_length
;
209 TRACE(cdaudio
,"total_len=%u\n", total_length
);
216 /**************************************************************************
217 * CDAUDIO_GetCDStatus [internal]
219 BOOL32
CDAUDIO_GetCDStatus(WINE_CDAUDIO
* wcda
)
221 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
222 int oldmode
= wcda
->cdaMode
;
224 wcda
->sc
.cdsc_format
= CDROM_MSF
;
226 struct ioc_read_subchannel read_sc
;
228 read_sc
.address_format
= CD_MSF_FORMAT
;
229 read_sc
.data_format
= CD_CURRENT_POSITION
;
231 read_sc
.data_len
= sizeof(wcda
->sc
);
232 read_sc
.data
= (struct cd_sub_channel_info
*)&wcda
->sc
;
235 if (ioctl(wcda
->unixdev
, CDROMSUBCHNL
, &wcda
->sc
))
237 if (ioctl(wcda
->unixdev
, CDIOCREADSUBCHANNEL
, &read_sc
))
240 TRACE(cdaudio
,"opened or no_media (%d)!\n", errno
);
241 wcda
->cdaMode
= WINE_CDA_OPEN
; /* was NOT_READY */
246 wcda
->sc
.cdsc_audiostatus
248 wcda
->sc
.header
.audio_status
252 case CDROM_AUDIO_INVALID
:
254 case CD_AS_AUDIO_INVALID
:
256 WARN(cdaudio
, "device doesn't support status.\n");
257 wcda
->cdaMode
= WINE_CDA_DONTKNOW
;
260 case CDROM_AUDIO_NO_STATUS
:
262 case CD_AS_NO_STATUS
:
264 wcda
->cdaMode
= WINE_CDA_STOP
;
265 TRACE(cdaudio
,"WINE_CDA_STOP !\n");
268 case CDROM_AUDIO_PLAY
:
270 case CD_AS_PLAY_IN_PROGRESS
:
272 wcda
->cdaMode
= WINE_CDA_PLAY
;
275 case CDROM_AUDIO_PAUSED
:
277 case CD_AS_PLAY_PAUSED
:
279 wcda
->cdaMode
= WINE_CDA_PAUSE
;
280 TRACE(cdaudio
,"WINE_CDA_PAUSE !\n");
284 TRACE(cdaudio
,"status=%02X !\n",
285 wcda
->sc
.cdsc_audiostatus
);
287 TRACE(cdaudio
,"status=%02X !\n",
288 wcda
->sc
.header
.audio_status
);
292 wcda
->nCurTrack
= wcda
->sc
.cdsc_trk
;
294 CDFRAMES_PERMIN
* wcda
->sc
.cdsc_absaddr
.msf
.minute
+
295 CDFRAMES_PERSEC
* wcda
->sc
.cdsc_absaddr
.msf
.second
+
296 wcda
->sc
.cdsc_absaddr
.msf
.frame
;
298 wcda
->nCurTrack
= wcda
->sc
.what
.position
.track_number
;
300 CDFRAMES_PERMIN
* wcda
->sc
.what
.position
.absaddr
.msf
.minute
+
301 CDFRAMES_PERSEC
* wcda
->sc
.what
.position
.absaddr
.msf
.second
+
302 wcda
->sc
.what
.position
.absaddr
.msf
.frame
;
305 TRACE(cdaudio
,"%02u-%02u:%02u:%02u \n",
307 wcda
->sc
.cdsc_absaddr
.msf
.minute
,
308 wcda
->sc
.cdsc_absaddr
.msf
.second
,
309 wcda
->sc
.cdsc_absaddr
.msf
.frame
);
311 TRACE(cdaudio
,"%02u-%02u:%02u:%02u \n",
312 wcda
->sc
.what
.position
.track_number
,
313 wcda
->sc
.what
.position
.absaddr
.msf
.minute
,
314 wcda
->sc
.what
.position
.absaddr
.msf
.second
,
315 wcda
->sc
.what
.position
.absaddr
.msf
.frame
);
318 if (oldmode
!= wcda
->cdaMode
&& oldmode
== WINE_CDA_OPEN
) {
319 if (!CDAUDIO_GetTracksInfo(wcda
)) {
320 WARN(cdaudio
, "error updating TracksInfo !\n");
330 /**************************************************************************
331 * CDAUDIO_Play [internal]
333 int CDAUDIO_Play(WINE_CDAUDIO
* wcda
, DWORD start
, DWORD end
)
335 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
337 struct cdrom_msf msf
;
339 struct ioc_play_msf msf
;
343 msf
.cdmsf_min0
= start
/ CDFRAMES_PERMIN
;
344 msf
.cdmsf_sec0
= (start
% CDFRAMES_PERMIN
) / CDFRAMES_PERSEC
;
345 msf
.cdmsf_frame0
= start
% CDFRAMES_PERSEC
;
346 msf
.cdmsf_min1
= end
/ CDFRAMES_PERMIN
;
347 msf
.cdmsf_sec1
= (end
% CDFRAMES_PERMIN
) / CDFRAMES_PERSEC
;
348 msf
.cdmsf_frame1
= end
% CDFRAMES_PERSEC
;
350 msf
.start_m
= start
/ CDFRAMES_PERMIN
;
351 msf
.start_s
= (start
% CDFRAMES_PERMIN
) / CDFRAMES_PERSEC
;
352 msf
.start_f
= start
% CDFRAMES_PERSEC
;
353 msf
.end_m
= end
/ CDFRAMES_PERMIN
;
354 msf
.end_s
= (end
% CDFRAMES_PERMIN
) / CDFRAMES_PERSEC
;
355 msf
.end_f
= end
% CDFRAMES_PERSEC
;
358 if (ioctl(wcda
->unixdev
, CDROMSTART
))
360 if (ioctl(wcda
->unixdev
, CDIOCSTART
, NULL
))
363 WARN(cdaudio
, "motor doesn't start !\n");
367 if (ioctl(wcda
->unixdev
, CDROMPLAYMSF
, &msf
))
369 if (ioctl(wcda
->unixdev
, CDIOCPLAYMSF
, &msf
))
372 WARN(cdaudio
, "device doesn't play !\n");
376 TRACE(cdaudio
,"msf = %d:%d:%d %d:%d:%d\n",
377 msf
.cdmsf_min0
, msf
.cdmsf_sec0
, msf
.cdmsf_frame0
,
378 msf
.cdmsf_min1
, msf
.cdmsf_sec1
, msf
.cdmsf_frame1
);
380 TRACE(cdaudio
,"msf = %d:%d:%d %d:%d:%d\n",
381 msf
.start_m
, msf
.start_s
, msf
.start_f
,
382 msf
.end_m
, msf
.end_s
, msf
.end_f
);
390 /**************************************************************************
391 * CDAUDIO_Stop [internal]
393 int CDAUDIO_Stop(WINE_CDAUDIO
* wcda
)
395 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
398 ret
= ioctl(wcda
->unixdev
, CDROMSTOP
);
400 ret
= ioctl(wcda
->unixdev
, CDIOCSTOP
, NULL
);
408 /**************************************************************************
409 * CDAUDIO_Pause [internal]
411 int CDAUDIO_Pause(WINE_CDAUDIO
* wcda
, int pauseOn
)
413 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
416 ret
= ioctl(wcda
->unixdev
, pauseOn
? CDROMPAUSE
: CDROMRESUME
);
418 ret
= ioctl(wcda
->unixdev
, pauseOn
? CDIOCPAUSE
: CDIOCRESUME
, NULL
);
426 /**************************************************************************
427 * CDAUDIO_SetDoor [internal]
429 int CDAUDIO_SetDoor(WINE_CDAUDIO
* wcda
, int open
)
431 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
435 ret
= ioctl(wcda
->unixdev
, CDROMEJECT
);
437 ret
= ioctl(wcda
->unixdev
, CDROMEJECT
, 1);
440 ret
= (ioctl(wcda
->unixdev
, CDIOCALLOW
, NULL
)) ||
441 (ioctl(wcda
->unixdev
, open
? CDIOCEJECT
: CDIOCCLOSE
, NULL
)) ||
442 (ioctl(wcda
->unixdev
, CDIOCPREVENT
, NULL
));
451 /**************************************************************************
452 * CDAUDIO_Reset [internal]
454 int CDAUDIO_Reset(WINE_CDAUDIO
* wcda
)
456 #if defined(linux) || defined(__FreeBSD__) || defined(__NetBSD__)
459 ret
= ioctl(wcda
->unixdev
, CDROMRESET
);
461 ret
= ioctl(wcda
->unixdev
, CDIOCRESET
, NULL
);