Release 950109
[wine] / multimedia / mcicda.c
1 /*
2  * Sample MCI CDAUDIO Wine Driver for Linux
3  *
4  * Copyright 1994 Martin Ayotte
5  *
6 static char Copyright[] = "Copyright  Martin Ayotte, 1994";
7 */
8 #ifndef WINELIB
9 #define BUILTIN_MMSYSTEM
10 #endif 
11
12 #ifdef BUILTIN_MMSYSTEM
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <string.h>
18 #include <fcntl.h>
19 #include <sys/ioctl.h>
20 #include "win.h"
21 #include "user.h"
22 #include "driver.h"
23 #include "mmsystem.h"
24 #include "stddebug.h"
25 /* #define DEBUG_CDAUDIO */
26 #include "debug.h"
27
28 #ifdef linux
29 #include <linux/soundcard.h>
30 #include <linux/cdrom.h>
31 #endif
32
33 #define SOUND_DEV "/dev/dsp"
34 #define CDAUDIO_DEV "/dev/sbpcd"
35
36 #ifdef SOUND_VERSION
37 #define IOCTL(a,b,c)            ioctl(a,b,&c)
38 #else
39 #define IOCTL(a,b,c)            (c = ioctl(a,b,c) )
40 #endif
41
42 #define MAX_CDAUDIODRV          2
43 #define MAX_CDAUDIO_TRACKS      256
44
45 #define CDFRAMES_PERSEC         75
46 #define CDFRAMES_PERMIN         4500
47 #define SECONDS_PERMIN          60
48
49 #ifdef linux
50 typedef struct {
51     int     nUseCount;          /* Incremented for each shared open */
52     BOOL    fShareable;         /* TRUE if first open was shareable */
53     WORD    wNotifyDeviceID;    /* MCI device ID with a pending notification */
54     HANDLE  hCallback;          /* Callback handle for pending notification */
55         MCI_OPEN_PARMS openParms;
56         DWORD   dwTimeFormat;
57         int             unixdev;
58         struct cdrom_subchnl    sc;
59         int             mode;
60         UINT    nCurTrack;
61         DWORD   dwCurFrame;
62         UINT    nTracks;
63         DWORD   dwTotalLen;
64         LPDWORD lpdwTrackLen;
65         LPDWORD lpdwTrackPos;
66         DWORD   dwFirstOffset;
67         } LINUX_CDAUDIO;
68
69 static LINUX_CDAUDIO    CDADev[MAX_CDAUDIODRV];
70 #endif
71
72 UINT CDAUDIO_GetNumberOfTracks(UINT wDevID);
73 BOOL CDAUDIO_GetTracksInfo(UINT wDevID);
74 BOOL CDAUDIO_GetCDStatus(UINT wDevID);
75 DWORD CDAUDIO_CalcTime(UINT wDevID, DWORD dwFormatType, DWORD dwFrame);
76
77
78 /*-----------------------------------------------------------------------*/
79
80
81 /**************************************************************************
82 *                               CDAUDIO_mciOpen                 [internal]
83 */
84 DWORD CDAUDIO_mciOpen(DWORD dwFlags, LPMCI_OPEN_PARMS lpParms)
85 {
86 #ifdef linux
87         UINT    wDevID;
88         dprintf_cdaudio(stddeb,"CDAUDIO_mciOpen(%08lX, %p);\n", 
89                 dwFlags, lpParms);
90         if (lpParms == NULL) return MCIERR_INTERNAL;
91         wDevID = lpParms->wDeviceID;
92         if (CDADev[wDevID].nUseCount > 0) {
93                 /* The driver already open on this channel */
94                 /* If the driver was opened shareable before and this open specifies */
95                 /* shareable then increment the use count */
96                 if (CDADev[wDevID].fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
97                         ++CDADev[wDevID].nUseCount;
98                 else
99                         return MCIERR_MUST_USE_SHAREABLE;
100                 }
101         else {
102                 CDADev[wDevID].nUseCount = 1;
103                 CDADev[wDevID].fShareable = dwFlags & MCI_OPEN_SHAREABLE;
104                 }
105     if (dwFlags & MCI_OPEN_ELEMENT) {
106         dprintf_cdaudio(stddeb,"CDAUDIO_mciOpen // MCI_OPEN_ELEMENT !\n");
107 /*              return MCIERR_NO_ELEMENT_ALLOWED; */
108                 }
109         memcpy(&CDADev[wDevID].openParms, lpParms, sizeof(MCI_OPEN_PARMS));
110         CDADev[wDevID].wNotifyDeviceID = lpParms->wDeviceID;
111         CDADev[wDevID].unixdev = open (CDAUDIO_DEV, O_RDONLY, 0);
112         if (CDADev[wDevID].unixdev == -1) {
113         fprintf(stderr,"CDAUDIO_mciOpen // can't open '%s' !\n", CDAUDIO_DEV);
114                 return MCIERR_HARDWARE;
115                 }
116         CDADev[wDevID].mode = 0;
117         CDADev[wDevID].dwTimeFormat = MCI_FORMAT_TMSF;
118         CDADev[wDevID].nCurTrack = 0;
119         CDADev[wDevID].nTracks = 0;
120         CDADev[wDevID].dwTotalLen = 0;
121         CDADev[wDevID].dwFirstOffset = 0;
122         CDADev[wDevID].lpdwTrackLen = NULL;
123         CDADev[wDevID].lpdwTrackPos = NULL;
124         if (!CDAUDIO_GetTracksInfo(wDevID)) {
125         fprintf(stderr,"CDAUDIO_mciOpen // error reading TracksInfo !\n");
126 /*              return MCIERR_INTERNAL; */
127                 }
128         if (dwFlags & MCI_NOTIFY) {
129                 dprintf_cdaudio(stddeb,
130                         "CDAUDIO_mciOpen // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
131                         lpParms->dwCallback);
132                 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
133                         CDADev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
134                 }
135         return 0;
136 #else
137         return MCIERR_HARDWARE;
138 #endif
139 }
140
141 /**************************************************************************
142 *                               CDAUDIO_mciClose                [internal]
143 */
144 DWORD CDAUDIO_mciClose(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
145 {
146 #ifdef linux
147         dprintf_cdaudio(stddeb,"CDAUDIO_mciClose(%u, %08lX, %p);\n", 
148                 wDevID, dwParam, lpParms);
149         if (CDADev[wDevID].lpdwTrackLen != NULL) free(CDADev[wDevID].lpdwTrackLen);
150         if (CDADev[wDevID].lpdwTrackPos != NULL) free(CDADev[wDevID].lpdwTrackPos);
151         close(CDADev[wDevID].unixdev);
152 #endif
153         return 0;
154 }
155
156 /**************************************************************************
157 *                               CDAUDIO_mciGetDevCaps   [internal]
158 */
159 DWORD CDAUDIO_mciGetDevCaps(UINT wDevID, DWORD dwFlags, 
160                                                 LPMCI_GETDEVCAPS_PARMS lpParms)
161 {
162 #ifdef linux
163         dprintf_cdaudio(stddeb,"CDAUDIO_mciGetDevCaps(%u, %08lX, %p);\n", 
164                 wDevID, dwFlags, lpParms);
165         if (lpParms == NULL) return MCIERR_INTERNAL;
166         if (dwFlags & MCI_GETDEVCAPS_ITEM) {
167                 dprintf_cdaudio(stddeb,
168                 "CDAUDIO_mciGetDevCaps // MCI_GETDEVCAPS_ITEM dwItem=%08lX;\n",
169                                 lpParms->dwItem);
170                 switch(lpParms->dwItem) {
171                         case MCI_GETDEVCAPS_CAN_RECORD:
172                                 lpParms->dwReturn = FALSE;
173                                 break;
174                         case MCI_GETDEVCAPS_HAS_AUDIO:
175                                 lpParms->dwReturn = TRUE;
176                                 break;
177                         case MCI_GETDEVCAPS_HAS_VIDEO:
178                                 lpParms->dwReturn = FALSE;
179                                 break;
180                         case MCI_GETDEVCAPS_DEVICE_TYPE:
181                                 lpParms->dwReturn = MCI_DEVTYPE_CD_AUDIO;
182                                 break;
183                         case MCI_GETDEVCAPS_USES_FILES:
184                                 lpParms->dwReturn = FALSE;
185                                 break;
186                         case MCI_GETDEVCAPS_COMPOUND_DEVICE:
187                                 lpParms->dwReturn = FALSE;
188                                 break;
189                         case MCI_GETDEVCAPS_CAN_EJECT:
190                                 lpParms->dwReturn = TRUE;
191                                 break;
192                         case MCI_GETDEVCAPS_CAN_PLAY:
193                                 lpParms->dwReturn = TRUE;
194                                 break;
195                         case MCI_GETDEVCAPS_CAN_SAVE:
196                                 lpParms->dwReturn = FALSE;
197                                 break;
198                         default:
199                                 return MCIERR_UNRECOGNIZED_COMMAND;
200                         }
201                 }
202         dprintf_cdaudio(stddeb,
203                 "CDAUDIO_mciGetDevCaps // lpParms->dwReturn=%08lX;\n", 
204                 lpParms->dwReturn);
205         return 0;
206 #else
207         return MCIERR_INTERNAL;
208 #endif
209 }
210
211 /**************************************************************************
212 *                               CDAUDIO_mciInfo                 [internal]
213 */
214 DWORD CDAUDIO_mciInfo(UINT wDevID, DWORD dwFlags, LPMCI_INFO_PARMS lpParms)
215 {
216 #ifdef linux
217         dprintf_cdaudio(stddeb,"CDAUDIO_mciInfo(%u, %08lX, %p);\n", 
218                 wDevID, dwFlags, lpParms);
219         if (lpParms == NULL) return MCIERR_INTERNAL;
220         lpParms->lpstrReturn = NULL;
221         switch(dwFlags) {
222                 case MCI_INFO_PRODUCT:
223                         lpParms->lpstrReturn = "Linux CDROM 0.5";
224                         break;
225                 default:
226                         return MCIERR_UNRECOGNIZED_COMMAND;
227                 }
228         if (lpParms->lpstrReturn != NULL)
229                 lpParms->dwRetSize = strlen(lpParms->lpstrReturn);
230         else
231                 lpParms->dwRetSize = 0;
232         return 0;
233 #else
234         return MCIERR_INTERNAL;
235 #endif
236 }
237
238 /**************************************************************************
239 *                               CDAUDIO_mciStatus               [internal]
240 */
241 DWORD CDAUDIO_mciStatus(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
242 {
243 #ifdef linux
244         dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus(%u, %08lX, %p);\n", 
245                 wDevID, dwFlags, lpParms);
246         if (lpParms == NULL) return MCIERR_INTERNAL;
247         if (CDADev[wDevID].unixdev == 0) return MMSYSERR_NOTENABLED;
248         if (dwFlags & MCI_NOTIFY) {
249                 dprintf_cdaudio(stddeb,
250                         "CDAUDIO_mciStatus // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
251                         lpParms->dwCallback);
252                 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
253                         CDADev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
254                 }
255         if (dwFlags & MCI_STATUS_ITEM) {
256                 switch(lpParms->dwItem) {
257                         case MCI_STATUS_CURRENT_TRACK:
258                                 if (!CDAUDIO_GetCDStatus(wDevID)) return MCIERR_INTERNAL;
259                                 lpParms->dwReturn = CDADev[wDevID].nCurTrack;
260                                 dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // CURRENT_TRACK=%lu!\n", lpParms->dwReturn);
261                                 return 0;
262                         case MCI_STATUS_LENGTH:
263                                 if (CDADev[wDevID].nTracks == 0) {
264                                         if (!CDAUDIO_GetTracksInfo(wDevID)) {
265                                                 fprintf(stderr,"CDAUDIO_mciStatus // error reading TracksInfo !\n");
266                                                 return MCIERR_INTERNAL;
267                                                 }
268                                         }
269                                 if (dwFlags & MCI_TRACK) {
270                                         dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // MCI_TRACK #%lu LENGTH=??? !\n",
271                                                                                                                 lpParms->dwTrack);
272                                         if (lpParms->dwTrack > CDADev[wDevID].nTracks)
273                                                 return MCIERR_OUTOFRANGE;
274                                         lpParms->dwReturn = CDADev[wDevID].lpdwTrackLen[lpParms->dwTrack];
275                                         }
276                                 else
277                                         lpParms->dwReturn = CDADev[wDevID].dwTotalLen;
278                                 lpParms->dwReturn = CDAUDIO_CalcTime(wDevID, 
279                                         CDADev[wDevID].dwTimeFormat, lpParms->dwReturn);
280                                 dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // LENGTH=%lu !\n", lpParms->dwReturn);
281                                 return 0;
282                         case MCI_STATUS_MODE:
283                                 if (!CDAUDIO_GetCDStatus(wDevID)) return MCIERR_INTERNAL;
284                                 lpParms->dwReturn = CDADev[wDevID].mode;
285                                 dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // MCI_STATUS_MODE=%08lX !\n",
286                                                                                                 lpParms->dwReturn);
287                                 return 0;
288                         case MCI_STATUS_MEDIA_PRESENT:
289                                 lpParms->dwReturn = (CDADev[wDevID].nTracks > 0) ? TRUE : FALSE;
290                                 if (lpParms->dwReturn == FALSE)
291                                         fprintf(stderr,"CDAUDIO_mciStatus // MEDIA_NOT_PRESENT !\n");
292                                 else
293                                         dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // MCI_STATUS_MEDIA_PRESENT !\n");
294                                 return 0;
295                         case MCI_STATUS_NUMBER_OF_TRACKS:
296                                 lpParms->dwReturn = CDAUDIO_GetNumberOfTracks(wDevID);
297                                 dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // MCI_STATUS_NUMBER_OF_TRACKS = %lu !\n",
298                                                                                                         lpParms->dwReturn);
299                                 if (lpParms->dwReturn == (WORD)-1) return MCIERR_INTERNAL;
300                                 return 0;
301                         case MCI_STATUS_POSITION:
302                                 if (!CDAUDIO_GetCDStatus(wDevID)) return MCIERR_INTERNAL;
303                                 lpParms->dwReturn = CDADev[wDevID].dwCurFrame;
304                                 if (dwFlags & MCI_STATUS_START) {
305                                         lpParms->dwReturn = CDADev[wDevID].dwFirstOffset;
306                                         dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // get MCI_STATUS_START !\n");
307                                         }
308                                 if (dwFlags & MCI_TRACK) {
309                                         if (lpParms->dwTrack > CDADev[wDevID].nTracks)
310                                                 return MCIERR_OUTOFRANGE;
311                                         lpParms->dwReturn = CDADev[wDevID].lpdwTrackPos[lpParms->dwTrack - 1];
312                                         dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // get MCI_TRACK #%lu !\n", lpParms->dwTrack);
313                                         }
314                                 lpParms->dwReturn = CDAUDIO_CalcTime(wDevID, 
315                                         CDADev[wDevID].dwTimeFormat, lpParms->dwReturn);
316                                         dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // MCI_STATUS_POSITION=%08lX !\n",
317                                                                                                                 lpParms->dwReturn);
318                                 return 0;
319                         case MCI_STATUS_READY:
320                                 dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // MCI_STATUS_READY !\n");
321                                 lpParms->dwReturn = TRUE;
322                                 return 0;
323                         case MCI_STATUS_TIME_FORMAT:
324                                 dprintf_cdaudio(stddeb,"CDAUDIO_mciStatus // MCI_STATUS_TIME_FORMAT !\n");
325                                 lpParms->dwReturn = MCI_FORMAT_MILLISECONDS;
326                                 return 0;
327                         default:
328                                 fprintf(stderr,"CDAUDIO_mciStatus // unknown command %08lX !\n", lpParms->dwItem);
329                                 return MCIERR_UNRECOGNIZED_COMMAND;
330                         }
331                 }
332     fprintf(stderr,"CDAUDIO_mciStatus // not MCI_STATUS_ITEM !\n");
333         return 0;
334 #else
335         return MMSYSERR_NOTENABLED;
336 #endif
337 }
338
339
340 /**************************************************************************
341 *                               CDAUDIO_CalcTime                        [internal]
342 */
343 DWORD CDAUDIO_CalcTime(UINT wDevID, DWORD dwFormatType, DWORD dwFrame)
344 {
345         DWORD   dwTime = 0;
346 #ifdef linux
347         UINT    wTrack;
348         UINT    wMinutes;
349         UINT    wSeconds;
350         UINT    wFrames;
351         dprintf_cdaudio(stddeb,"CDAUDIO_CalcTime(%u, %08lX, %lu);\n", 
352                 wDevID, dwFormatType, dwFrame);
353 TryAGAIN:
354         switch (dwFormatType) {
355                 case MCI_FORMAT_MILLISECONDS:
356                         dwTime = dwFrame / CDFRAMES_PERSEC * 1000;
357                         dprintf_cdaudio(stddeb,
358                                 "CDAUDIO_CalcTime // MILLISECONDS %lu\n", 
359                                 dwTime);
360                         break;
361                 case MCI_FORMAT_MSF:
362                         wMinutes = dwFrame / CDFRAMES_PERMIN;
363                         wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
364                         wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - 
365                                                                 CDFRAMES_PERSEC * wSeconds;
366                         dwTime = MCI_MAKE_MSF(wMinutes, wSeconds, wFrames);
367                         dprintf_cdaudio(stddeb,"CDAUDIO_CalcTime // MSF %02u:%02u:%02u -> dwTime=%lu\n",
368                                                                 wMinutes, wSeconds, wFrames, dwTime);
369                         break;
370                 case MCI_FORMAT_TMSF:
371                         for (wTrack = 0; wTrack < CDADev[wDevID].nTracks; wTrack++) {
372 /*                              dwTime += CDADev[wDevID].lpdwTrackLen[wTrack - 1];
373                                 printf("Adding trk#%u curpos=%u \n", dwTime);
374                                 if (dwTime >= dwFrame) break; */
375                                 if (CDADev[wDevID].lpdwTrackPos[wTrack - 1] >= dwFrame) break;
376                                 }
377                         wMinutes = dwFrame / CDFRAMES_PERMIN;
378                         wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
379                         wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - 
380                                                                 CDFRAMES_PERSEC * wSeconds;
381                         dwTime = MCI_MAKE_TMSF(wTrack, wMinutes, wSeconds, wFrames);
382                         dprintf_cdaudio(stddeb,
383                                 "CDAUDIO_CalcTime // %02u-%02u:%02u:%02u\n",
384                                         wTrack, wMinutes, wSeconds, wFrames);
385                         break;
386                 default:
387                         /* unknown format ! force TMSF ! ... */
388                         dwFormatType = MCI_FORMAT_TMSF;
389                         goto TryAGAIN;
390                 }
391 #endif
392         return dwTime;
393 }
394
395
396 /**************************************************************************
397 *                               CDAUDIO_CalcFrame                       [internal]
398 */
399 DWORD CDAUDIO_CalcFrame(UINT wDevID, DWORD dwFormatType, DWORD dwTime)
400 {
401         DWORD   dwFrame = 0;
402 #ifdef linux
403         UINT    wTrack;
404         dprintf_cdaudio(stddeb,"CDAUDIO_CalcFrame(%u, %08lX, %lu);\n", 
405                 wDevID, dwFormatType, dwTime);
406 TryAGAIN:
407         switch (dwFormatType) {
408                 case MCI_FORMAT_MILLISECONDS:
409                         dwFrame = dwTime * CDFRAMES_PERSEC / 1000;
410                         dprintf_cdaudio(stddeb,
411                                 "CDAUDIO_CalcFrame // MILLISECONDS %lu\n", 
412                                 dwFrame);
413                         break;
414                 case MCI_FORMAT_MSF:
415                         dprintf_cdaudio(stddeb,
416                                 "CDAUDIO_CalcFrame // MSF %02u:%02u:%02u\n",
417                                 MCI_MSF_MINUTE(dwTime), MCI_MSF_SECOND(dwTime), 
418                                 MCI_MSF_FRAME(dwTime));
419                         dwFrame += CDFRAMES_PERMIN * MCI_MSF_MINUTE(dwTime);
420                         dwFrame += CDFRAMES_PERSEC * MCI_MSF_SECOND(dwTime);
421                         dwFrame += MCI_MSF_FRAME(dwTime);
422                         break;
423                 case MCI_FORMAT_TMSF:
424                         wTrack = MCI_TMSF_TRACK(dwTime);
425                         dprintf_cdaudio(stddeb,
426                         "CDAUDIO_CalcFrame // TMSF %02u-%02u:%02u:%02u\n",
427                                         MCI_TMSF_TRACK(dwTime), MCI_TMSF_MINUTE(dwTime), 
428                                         MCI_TMSF_SECOND(dwTime), MCI_TMSF_FRAME(dwTime));
429                         dprintf_cdaudio(stddeb,
430                                 "CDAUDIO_CalcFrame // TMSF trackpos[%u]=%lu\n",
431                                 wTrack, CDADev[wDevID].lpdwTrackPos[wTrack - 1]);
432                         dwFrame = CDADev[wDevID].lpdwTrackPos[wTrack - 1];
433                         dwFrame += CDFRAMES_PERMIN * MCI_TMSF_MINUTE(dwTime);
434                         dwFrame += CDFRAMES_PERSEC * MCI_TMSF_SECOND(dwTime);
435                         dwFrame += MCI_TMSF_FRAME(dwTime);
436                         break;
437                 default:
438                         /* unknown format ! force TMSF ! ... */
439                         dwFormatType = MCI_FORMAT_TMSF;
440                         goto TryAGAIN;
441                 }
442 #endif
443         return dwFrame;
444 }
445
446
447 /**************************************************************************
448 *                               CDAUDIO_GetNumberOfTracks               [internal]
449 */
450 UINT CDAUDIO_GetNumberOfTracks(UINT wDevID)
451 {
452 #ifdef linux
453         struct cdrom_tochdr     hdr;
454         if (CDADev[wDevID].nTracks == 0) {
455                 if (ioctl(CDADev[wDevID].unixdev, CDROMREADTOCHDR, &hdr)) {
456                         fprintf(stderr,
457                                 "GetNumberOfTracks(%u) // Error occured !\n", 
458                                 wDevID);
459                         return (WORD)-1;
460                         }
461                 CDADev[wDevID].nTracks = hdr.cdth_trk1;
462                 }
463         return CDADev[wDevID].nTracks;
464 #else
465         return (WORD)-1;
466 #endif
467 }
468
469 /**************************************************************************
470 *                               CDAUDIO_GetTracksInfo                   [internal]
471 */
472 BOOL CDAUDIO_GetTracksInfo(UINT wDevID)
473 {
474 #ifdef linux
475         int             i, length;
476         int             start, last_start;
477         int             total_length = 0;
478         struct cdrom_tocentry   entry;
479         if (CDADev[wDevID].nTracks == 0) {
480                 if (CDAUDIO_GetNumberOfTracks(wDevID) == (WORD)-1) return FALSE;
481                 }
482         dprintf_cdaudio(stddeb,"CDAUDIO_GetTracksInfo // nTracks=%u\n", 
483                 CDADev[wDevID].nTracks);
484         if (CDADev[wDevID].lpdwTrackLen != NULL) 
485                 free(CDADev[wDevID].lpdwTrackLen);
486         CDADev[wDevID].lpdwTrackLen = (LPDWORD)malloc(
487                 (CDADev[wDevID].nTracks + 1) * sizeof(DWORD));
488         if (CDADev[wDevID].lpdwTrackPos != NULL) 
489                 free(CDADev[wDevID].lpdwTrackPos);
490         CDADev[wDevID].lpdwTrackPos = (LPDWORD)malloc(
491                 (CDADev[wDevID].nTracks + 1) * sizeof(DWORD));
492         if (CDADev[wDevID].lpdwTrackLen == NULL ||
493                 CDADev[wDevID].lpdwTrackPos == NULL) {
494                         fprintf(stderr,
495                                 "CDAUDIO_GetTracksInfo // error allocating track table !\n");
496                 return FALSE;
497                 }
498         memset(CDADev[wDevID].lpdwTrackLen, 0, 
499                 (CDADev[wDevID].nTracks + 1) * sizeof(DWORD));
500         memset(CDADev[wDevID].lpdwTrackPos, 0, 
501                 (CDADev[wDevID].nTracks + 1) * sizeof(DWORD));
502         for (i = 0; i <= CDADev[wDevID].nTracks; i++) {
503                 if (i == CDADev[wDevID].nTracks)
504                         entry.cdte_track = CDROM_LEADOUT;
505                 else
506                         entry.cdte_track = i + 1;
507                 entry.cdte_format = CDROM_MSF;
508                 if (ioctl(CDADev[wDevID].unixdev, CDROMREADTOCENTRY, &entry)) {
509                         fprintf(stderr,
510                                 "CDAUDIO_GetTracksInfo // error read entry\n");
511                         return FALSE;
512                         }
513                 start = CDFRAMES_PERSEC * (SECONDS_PERMIN * 
514                         entry.cdte_addr.msf.minute + entry.cdte_addr.msf.second) + 
515                         entry.cdte_addr.msf.frame;
516                 if (i == 0) {
517                         CDADev[wDevID].dwFirstOffset = last_start = start;
518                         dprintf_cdaudio(stddeb,
519                                 "CDAUDIO_GetTracksInfo // dwFirstOffset=%u\n", 
520                                 start);
521                         }
522                 else {
523                         length = start - last_start;
524                         last_start = start;
525                         start = last_start - length;
526                         total_length += length;
527                         CDADev[wDevID].lpdwTrackLen[i - 1] = length;
528                         CDADev[wDevID].lpdwTrackPos[i - 1] = start;
529                         dprintf_cdaudio(stddeb,
530                         "CDAUDIO_GetTracksInfo // track #%u start=%u len=%u\n",
531                                 i, start, length);
532                         }
533                 }
534         CDADev[wDevID].dwTotalLen = total_length;
535         dprintf_cdaudio(stddeb,"CDAUDIO_GetTracksInfo // total_len=%u\n", 
536                 total_length);
537         fflush(stdout);
538         return TRUE;
539 #else
540         return FALSE;
541 #endif
542 }
543
544
545 /**************************************************************************
546 *                               CDAUDIO_GetCDStatus                             [internal]
547 */
548 BOOL CDAUDIO_GetCDStatus(UINT wDevID)
549 {
550 #ifdef linux
551         int             oldmode = CDADev[wDevID].mode;
552         CDADev[wDevID].sc.cdsc_format = CDROM_MSF;
553         if (ioctl(CDADev[wDevID].unixdev, CDROMSUBCHNL, &CDADev[wDevID].sc)) {
554                 fprintf(stderr,"CDAUDIO_GetCDStatus // opened or no_media !\n");
555                 CDADev[wDevID].mode = MCI_MODE_NOT_READY;
556                 return TRUE;
557                 }
558         switch (CDADev[wDevID].sc.cdsc_audiostatus) {
559                 case CDROM_AUDIO_INVALID:
560                         fprintf(stderr,"CDAUDIO_GetCDStatus // device doesn't support status !\n");
561                         return FALSE;
562                 case CDROM_AUDIO_NO_STATUS: 
563                         CDADev[wDevID].mode = MCI_MODE_STOP;
564                         dprintf_cdaudio(stddeb,"CDAUDIO_GetCDStatus // MCI_MODE_STOP !\n");
565                         break;
566                 case CDROM_AUDIO_PLAY: 
567                         CDADev[wDevID].mode = MCI_MODE_PLAY;
568                         dprintf_cdaudio(stddeb,"CDAUDIO_GetCDStatus // MCI_MODE_PLAY !\n");
569                         break;
570                 case CDROM_AUDIO_PAUSED:
571                         CDADev[wDevID].mode = MCI_MODE_PAUSE;
572                         dprintf_cdaudio(stddeb,"CDAUDIO_GetCDStatus // MCI_MODE_PAUSE !\n");
573                         break;
574                 default:
575                         dprintf_cdaudio(stddeb,"CDAUDIO_GetCDStatus // status=%02X !\n",
576                                         CDADev[wDevID].sc.cdsc_audiostatus);
577                 }
578         CDADev[wDevID].nCurTrack = CDADev[wDevID].sc.cdsc_trk;
579         CDADev[wDevID].dwCurFrame = 
580                 CDFRAMES_PERMIN * CDADev[wDevID].sc.cdsc_absaddr.msf.minute +
581                 CDFRAMES_PERSEC * CDADev[wDevID].sc.cdsc_absaddr.msf.second +
582                 CDADev[wDevID].sc.cdsc_absaddr.msf.frame;
583         dprintf_cdaudio(stddeb,"CDAUDIO_GetCDStatus // %02u-%02u:%02u:%02u \n",
584                 CDADev[wDevID].sc.cdsc_trk,
585                 CDADev[wDevID].sc.cdsc_absaddr.msf.minute,
586                 CDADev[wDevID].sc.cdsc_absaddr.msf.second,
587                 CDADev[wDevID].sc.cdsc_absaddr.msf.frame);
588         if (oldmode != CDADev[wDevID].mode && oldmode == MCI_MODE_OPEN) {
589                 if (!CDAUDIO_GetTracksInfo(wDevID)) {
590             fprintf(stderr,"CDAUDIO_GetCDStatus // error updating TracksInfo !\n");
591                         return MCIERR_INTERNAL;
592                         }
593                 }
594         return TRUE;
595 #else
596         return FALSE;
597 #endif
598 }
599
600 /**************************************************************************
601 *                               CDAUDIO_mciPlay                 [internal]
602 */
603 DWORD CDAUDIO_mciPlay(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
604 {
605 #ifdef linux
606         int     start, end;
607         struct  cdrom_msf       msf;
608         dprintf_cdaudio(stddeb,"CDAUDIO_mciPlay(%u, %08lX, %p);\n", 
609                 wDevID, dwFlags, lpParms);
610         if (lpParms == NULL) return MCIERR_INTERNAL;
611         if (CDADev[wDevID].unixdev == 0) return MMSYSERR_NOTENABLED;
612         start = 0;              end = CDADev[wDevID].dwTotalLen;
613         CDADev[wDevID].nCurTrack = 1;
614         if (dwFlags & MCI_FROM) {
615                 start = CDAUDIO_CalcFrame(wDevID, 
616                         CDADev[wDevID].dwTimeFormat, lpParms->dwFrom); 
617         dprintf_cdaudio(stddeb,"CDAUDIO_mciPlay // MCI_FROM=%08lX -> %u \n",
618                                 lpParms->dwFrom, start);
619                 }
620         if (dwFlags & MCI_TO) {
621                 end = CDAUDIO_CalcFrame(wDevID, 
622                         CDADev[wDevID].dwTimeFormat, lpParms->dwTo);
623                 dprintf_cdaudio(stddeb,
624                         "CDAUDIO_mciPlay // MCI_TO=%08lX -> %u \n",
625                         lpParms->dwTo, end);
626                 }
627         start += CDADev[wDevID].dwFirstOffset;  
628         end += CDADev[wDevID].dwFirstOffset;
629         msf.cdmsf_min0 = start / CDFRAMES_PERMIN;
630         msf.cdmsf_sec0 = (start % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
631         msf.cdmsf_frame0 = start % CDFRAMES_PERSEC;
632         msf.cdmsf_min1 = end / CDFRAMES_PERMIN;
633         msf.cdmsf_sec1 = (end % CDFRAMES_PERMIN) / CDFRAMES_PERSEC;
634         msf.cdmsf_frame1 = end % CDFRAMES_PERSEC;
635         if (ioctl(CDADev[wDevID].unixdev, CDROMSTART)) {
636                 fprintf(stderr,"CDAUDIO_mciPlay // motor doesn't start !\n");
637                 return MCIERR_HARDWARE;
638                 }
639         if (ioctl(CDADev[wDevID].unixdev, CDROMPLAYMSF, &msf)) {
640                 fprintf(stderr,"CDAUDIO_mciPlay // device doesn't play !\n");
641                 return MCIERR_HARDWARE;
642                 }
643         dprintf_cdaudio(stddeb,"CDAUDIO_mciPlay // msf = %d:%d:%d %d:%d:%d\n",
644                 msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0,
645                 msf.cdmsf_min1, msf.cdmsf_sec1, msf.cdmsf_frame1);
646         CDADev[wDevID].mode = MCI_MODE_PLAY;
647         if (dwFlags & MCI_NOTIFY) {
648                 dprintf_cdaudio(stddeb,
649                         "CDAUDIO_mciPlay // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
650                         lpParms->dwCallback);
651                 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
652                         CDADev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
653                 }
654         return 0;
655 #else
656         return MCIERR_HARDWARE;
657 #endif
658 }
659
660 /**************************************************************************
661 *                               CDAUDIO_mciStop                 [internal]
662 */
663 DWORD CDAUDIO_mciStop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
664 {
665 #ifdef linux
666         dprintf_cdaudio(stddeb,"CDAUDIO_mciStop(%u, %08lX, %p);\n", 
667                 wDevID, dwFlags, lpParms);
668         if (lpParms == NULL) return MCIERR_INTERNAL;
669         if (ioctl(CDADev[wDevID].unixdev, CDROMSTOP)) return MCIERR_HARDWARE;
670         CDADev[wDevID].mode = MCI_MODE_STOP;
671         if (dwFlags & MCI_NOTIFY) {
672                 dprintf_cdaudio(stddeb,
673                         "CDAUDIO_mciStop // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
674                         lpParms->dwCallback);
675                 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
676                         CDADev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
677                 }
678         return 0;
679 #else
680         return MCIERR_HARDWARE;
681 #endif
682 }
683
684 /**************************************************************************
685 *                               CDAUDIO_mciPause                [internal]
686 */
687 DWORD CDAUDIO_mciPause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
688 {
689 #ifdef linux
690         dprintf_cdaudio(stddeb,"CDAUDIO_mciPause(%u, %08lX, %p);\n", 
691                 wDevID, dwFlags, lpParms);
692         if (lpParms == NULL) return MCIERR_INTERNAL;
693         if (ioctl(CDADev[wDevID].unixdev, CDROMPAUSE)) return MCIERR_HARDWARE;
694         CDADev[wDevID].mode = MCI_MODE_PAUSE;
695         if (dwFlags & MCI_NOTIFY) {
696         dprintf_cdaudio(stddeb,
697                 "CDAUDIO_mciPause // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
698                 lpParms->dwCallback);
699                 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
700                         CDADev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
701                 }
702         return 0;
703 #else
704         return MCIERR_HARDWARE;
705 #endif
706 }
707
708 /**************************************************************************
709 *                               CDAUDIO_mciResume               [internal]
710 */
711 DWORD CDAUDIO_mciResume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
712 {
713 #ifdef linux
714         dprintf_cdaudio(stddeb,"CDAUDIO_mciResume(%u, %08lX, %p);\n", 
715                 wDevID, dwFlags, lpParms);
716         if (lpParms == NULL) return MCIERR_INTERNAL;
717         if (ioctl(CDADev[wDevID].unixdev, CDROMRESUME)) return MCIERR_HARDWARE;
718         CDADev[wDevID].mode = MCI_MODE_STOP;
719         if (dwFlags & MCI_NOTIFY) {
720                 dprintf_cdaudio(stddeb,
721                         "CDAUDIO_mciResume // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
722                         lpParms->dwCallback);
723                 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
724                         CDADev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
725                 }
726         return 0;
727 #else
728         return MCIERR_HARDWARE;
729 #endif
730 }
731
732 /**************************************************************************
733 *                               CDAUDIO_mciSeek                 [internal]
734 */
735 DWORD CDAUDIO_mciSeek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
736 {
737 #ifdef linux
738         DWORD   dwRet;
739         MCI_PLAY_PARMS PlayParms;
740         dprintf_cdaudio(stddeb,"CDAUDIO_mciSeek(%u, %08lX, %p);\n", 
741                 wDevID, dwFlags, lpParms);
742         if (lpParms == NULL) return MCIERR_INTERNAL;
743         if (ioctl(CDADev[wDevID].unixdev, CDROMRESUME)) return MCIERR_HARDWARE;
744         CDADev[wDevID].mode = MCI_MODE_SEEK;
745         switch(dwFlags) {
746                 case MCI_SEEK_TO_START:
747                         PlayParms.dwFrom = 0;
748                         break;
749                 case MCI_SEEK_TO_END:
750                         PlayParms.dwFrom = CDADev[wDevID].dwTotalLen;
751                         break;
752                 case MCI_TO:
753                         PlayParms.dwFrom = lpParms->dwTo;
754                         break;
755                 }
756         dwRet = CDAUDIO_mciPlay(wDevID, MCI_WAIT | MCI_FROM, &PlayParms);
757         if (dwRet != 0) return dwRet;
758         dwRet = CDAUDIO_mciStop(wDevID, MCI_WAIT, (LPMCI_GENERIC_PARMS)&PlayParms);
759         if (dwFlags & MCI_NOTIFY) {
760                 dprintf_cdaudio(stddeb,
761                         "CDAUDIO_mciSeek // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
762                         lpParms->dwCallback);
763                 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
764                         CDADev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
765                 }
766         return dwRet;
767 #else
768         return MCIERR_HARDWARE;
769 #endif
770 }
771
772
773 /**************************************************************************
774 *                               CDAUDIO_mciSet                  [internal]
775 */
776 DWORD CDAUDIO_mciSet(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
777 {
778 #ifdef linux
779         dprintf_cdaudio(stddeb,"CDAUDIO_mciSet(%u, %08lX, %p);\n", 
780                 wDevID, dwFlags, lpParms);
781         if (lpParms == NULL) return MCIERR_INTERNAL;
782 /*
783         printf("CDAUDIO_mciSet // dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
784         printf("CDAUDIO_mciSet // dwAudio=%08lX\n", lpParms->dwAudio);
785 */
786         if (dwFlags & MCI_SET_TIME_FORMAT) {
787                 switch (lpParms->dwTimeFormat) {
788                         case MCI_FORMAT_MILLISECONDS:
789                                 dprintf_cdaudio(stddeb,
790                                 "CDAUDIO_mciSet // MCI_FORMAT_MILLISECONDS !\n");
791                                 break;
792                         case MCI_FORMAT_MSF:
793                                 dprintf_cdaudio(stddeb,"CDAUDIO_mciSet // MCI_FORMAT_MSF !\n");
794                                 break;
795                         case MCI_FORMAT_TMSF:
796                                 dprintf_cdaudio(stddeb,"CDAUDIO_mciSet // MCI_FORMAT_TMSF !\n");
797                                 break;
798                         default:
799                                 fprintf(stderr,"CDAUDIO_mciSet // bad time format !\n");
800                                 return MCIERR_BAD_TIME_FORMAT;
801                         }
802                 CDADev[wDevID].dwTimeFormat = lpParms->dwTimeFormat;
803                 }
804         if (dwFlags & MCI_SET_DOOR_OPEN) {
805                 dprintf_cdaudio(stddeb,
806                         "CDAUDIO_mciSet // MCI_SET_DOOR_OPEN !\n");
807                 if (ioctl(CDADev[wDevID].unixdev, CDROMEJECT)) return MCIERR_HARDWARE;
808                 CDADev[wDevID].nTracks = 0;
809                 }
810         if (dwFlags & MCI_SET_DOOR_CLOSED) {
811                 dprintf_cdaudio(stddeb,
812                         "CDAUDIO_mciSet // MCI_SET_DOOR_CLOSED !\n");
813                 if (ioctl(CDADev[wDevID].unixdev, CDROMEJECT)) return MCIERR_HARDWARE;
814                 CDADev[wDevID].nTracks = 0;
815                 }
816         if (dwFlags & MCI_SET_VIDEO) return MCIERR_UNSUPPORTED_FUNCTION;
817         if (dwFlags & MCI_SET_ON) return MCIERR_UNSUPPORTED_FUNCTION;
818         if (dwFlags & MCI_SET_OFF) return MCIERR_UNSUPPORTED_FUNCTION;
819         if (dwFlags & MCI_NOTIFY) {
820                 dprintf_cdaudio(stddeb,
821                         "CDAUDIO_mciSet // MCI_NOTIFY_SUCCESSFUL %08lX !\n", 
822                         lpParms->dwCallback);
823                 mciDriverNotify((HWND)LOWORD(lpParms->dwCallback), 
824                         CDADev[wDevID].wNotifyDeviceID, MCI_NOTIFY_SUCCESSFUL);
825                 }
826         return 0;
827 #else
828         return MCIERR_HARDWARE;
829 #endif
830 }
831
832
833 /**************************************************************************
834 *                               CDAUDIO_DriverProc              [sample driver]
835 */
836 LRESULT CDAUDIO_DriverProc(DWORD dwDevID, HDRVR hDriv, WORD wMsg, 
837                                                         DWORD dwParam1, DWORD dwParam2)
838 {
839 #ifdef linux
840         switch(wMsg) {
841                 case DRV_LOAD:
842                         return (LRESULT)1L;
843                 case DRV_FREE:
844                         return (LRESULT)1L;
845                 case DRV_OPEN:
846                 case MCI_OPEN_DRIVER:
847                 case MCI_OPEN:
848                         return CDAUDIO_mciOpen(dwParam1, (LPMCI_OPEN_PARMS)dwParam2); 
849                 case DRV_CLOSE:
850                 case MCI_CLOSE_DRIVER:
851                 case MCI_CLOSE:
852                         return CDAUDIO_mciClose(dwDevID, dwParam1, 
853                                         (LPMCI_GENERIC_PARMS)dwParam2);
854                 case DRV_ENABLE:
855                         return (LRESULT)1L;
856                 case DRV_DISABLE:
857                         return (LRESULT)1L;
858                 case DRV_QUERYCONFIGURE:
859                         return (LRESULT)1L;
860                 case DRV_CONFIGURE:
861                         MessageBox((HWND)NULL, "Sample MultiMedia Linux Driver !", 
862                                                                 "MMLinux Driver", MB_OK);
863                         return (LRESULT)1L;
864                 case DRV_INSTALL:
865                         return (LRESULT)DRVCNF_RESTART;
866                 case DRV_REMOVE:
867                         return (LRESULT)DRVCNF_RESTART;
868                 case MCI_GETDEVCAPS:
869                         return CDAUDIO_mciGetDevCaps(dwDevID, dwParam1, 
870                                         (LPMCI_GETDEVCAPS_PARMS)dwParam2);
871                 case MCI_INFO:
872                         return CDAUDIO_mciInfo(dwDevID, dwParam1, 
873                                                 (LPMCI_INFO_PARMS)dwParam2);
874                 case MCI_STATUS:
875                         return CDAUDIO_mciStatus(dwDevID, dwParam1, 
876                                                 (LPMCI_STATUS_PARMS)dwParam2);
877                 case MCI_SET:
878                         return CDAUDIO_mciSet(dwDevID, dwParam1, 
879                                                 (LPMCI_SET_PARMS)dwParam2);
880                 case MCI_PLAY:
881                         return CDAUDIO_mciPlay(dwDevID, dwParam1, 
882                                                 (LPMCI_PLAY_PARMS)dwParam2);
883                 case MCI_STOP:
884                         return CDAUDIO_mciStop(dwDevID, dwParam1, 
885                                         (LPMCI_GENERIC_PARMS)dwParam2);
886                 case MCI_PAUSE:
887                         return CDAUDIO_mciPause(dwDevID, dwParam1, 
888                                         (LPMCI_GENERIC_PARMS)dwParam2);
889                 case MCI_RESUME:
890                         return CDAUDIO_mciResume(dwDevID, dwParam1, 
891                                         (LPMCI_GENERIC_PARMS)dwParam2);
892                 case MCI_SEEK:
893                         return CDAUDIO_mciSeek(dwDevID, dwParam1, 
894                                         (LPMCI_SEEK_PARMS)dwParam2);
895                 case MCI_SET_DOOR_OPEN:
896                         dprintf_cdaudio(stddeb,
897                                 "CDAUDIO_DriverProc // MCI_SET_DOOR_OPEN !\n");
898                         if (ioctl(CDADev[dwDevID].unixdev, CDROMEJECT)) return MCIERR_HARDWARE;
899                         CDADev[dwDevID].nTracks = 0;
900                         return 0;
901                 case MCI_SET_DOOR_CLOSED:
902                         dprintf_cdaudio(stddeb,"CDAUDIO_DriverProc // MCI_SET_DOOR_CLOSED !\n");
903                         if (ioctl(CDADev[dwDevID].unixdev, CDROMEJECT, 1)) return MCIERR_HARDWARE;
904                         CDADev[dwDevID].nTracks = 0;
905                         return 0;
906                 default:
907                         return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
908                 }
909 #else
910         return MCIERR_HARDWARE;
911 #endif
912 }
913
914
915 /*-----------------------------------------------------------------------*/
916
917 #endif /* #ifdef BUILTIN_MMSYSTEM */