1c2c66affSColin Finck /*
2c2c66affSColin Finck * MCI driver for audio CD (MCICDA)
3c2c66affSColin Finck *
4c2c66affSColin Finck * Copyright 1994 Martin Ayotte
5c2c66affSColin Finck * Copyright 1998-99 Eric Pouech
6c2c66affSColin Finck * Copyright 2000 Andreas Mohr
7c2c66affSColin Finck *
8c2c66affSColin Finck * This library is free software; you can redistribute it and/or
9c2c66affSColin Finck * modify it under the terms of the GNU Lesser General Public
10c2c66affSColin Finck * License as published by the Free Software Foundation; either
11c2c66affSColin Finck * version 2.1 of the License, or (at your option) any later version.
12c2c66affSColin Finck *
13c2c66affSColin Finck * This library is distributed in the hope that it will be useful,
14c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of
15c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16c2c66affSColin Finck * Lesser General Public License for more details.
17c2c66affSColin Finck *
18c2c66affSColin Finck * You should have received a copy of the GNU Lesser General Public
19c2c66affSColin Finck * License along with this library; if not, write to the Free Software
20c2c66affSColin Finck * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21c2c66affSColin Finck */
22c2c66affSColin Finck
23*122f1078SAmine Khaldi #include "config.h"
24c2c66affSColin Finck #include <stdarg.h>
25*122f1078SAmine Khaldi #include <stdio.h>
26*122f1078SAmine Khaldi #include <string.h>
27c2c66affSColin Finck
28c2c66affSColin Finck #define WIN32_NO_STATUS
29*122f1078SAmine Khaldi #include "windef.h"
30*122f1078SAmine Khaldi #include "winbase.h"
31*122f1078SAmine Khaldi #include "wingdi.h"
32*122f1078SAmine Khaldi #include "winuser.h"
33*122f1078SAmine Khaldi #include "wownt32.h"
34*122f1078SAmine Khaldi #include "mmddk.h"
35*122f1078SAmine Khaldi #include "winioctl.h"
36*122f1078SAmine Khaldi #include "ntddcdrm.h"
37*122f1078SAmine Khaldi #include "wine/winternl.h"
38*122f1078SAmine Khaldi #include "wine/debug.h"
39*122f1078SAmine Khaldi #include "wine/unicode.h"
40*122f1078SAmine Khaldi #include "dsound.h"
41c2c66affSColin Finck
42c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(mcicda);
43c2c66affSColin Finck
44c2c66affSColin Finck #define CDFRAMES_PERSEC 75
45c2c66affSColin Finck #define CDFRAMES_PERMIN (CDFRAMES_PERSEC * 60)
46c2c66affSColin Finck #define FRAME_OF_ADDR(a) ((a)[1] * CDFRAMES_PERMIN + (a)[2] * CDFRAMES_PERSEC + (a)[3])
47c2c66affSColin Finck #define FRAME_OF_TOC(toc, idx) FRAME_OF_ADDR((toc).TrackData[idx - (toc).FirstTrack].Address)
48c2c66affSColin Finck
49c2c66affSColin Finck /* Defined by red-book standard; do not change! */
50c2c66affSColin Finck #define RAW_SECTOR_SIZE (2352)
51c2c66affSColin Finck
52c2c66affSColin Finck /* Must be >= RAW_SECTOR_SIZE */
53c2c66affSColin Finck #define CDDA_FRAG_SIZE (32768)
54c2c66affSColin Finck /* Must be >= 2 */
55c2c66affSColin Finck #define CDDA_FRAG_COUNT (3)
56c2c66affSColin Finck
57c2c66affSColin Finck typedef struct {
58c2c66affSColin Finck UINT wDevID;
59c2c66affSColin Finck int nUseCount; /* Incremented for each shared open */
60c2c66affSColin Finck BOOL fShareable; /* TRUE if first open was shareable */
61c2c66affSColin Finck MCIDEVICEID wNotifyDeviceID; /* MCI device ID with a pending notification */
62c2c66affSColin Finck HANDLE hCallback; /* Callback handle for pending notification */
63c2c66affSColin Finck DWORD dwTimeFormat;
64c2c66affSColin Finck HANDLE handle;
65c2c66affSColin Finck
66c2c66affSColin Finck /* The following are used for digital playback only */
67c2c66affSColin Finck HANDLE hThread;
68c2c66affSColin Finck HANDLE stopEvent;
69c2c66affSColin Finck DWORD start, end;
70c2c66affSColin Finck
71c2c66affSColin Finck IDirectSound *dsObj;
72c2c66affSColin Finck IDirectSoundBuffer *dsBuf;
73c2c66affSColin Finck
74c2c66affSColin Finck CRITICAL_SECTION cs;
75c2c66affSColin Finck } WINE_MCICDAUDIO;
76c2c66affSColin Finck
77c2c66affSColin Finck /*-----------------------------------------------------------------------*/
78c2c66affSColin Finck
79c2c66affSColin Finck typedef HRESULT(WINAPI*LPDIRECTSOUNDCREATE)(LPCGUID,LPDIRECTSOUND*,LPUNKNOWN);
80c2c66affSColin Finck static LPDIRECTSOUNDCREATE pDirectSoundCreate;
81c2c66affSColin Finck
device_io(HANDLE dev,DWORD code,void * inbuffer,DWORD insize,void * outbuffer,DWORD outsize,DWORD * retsize,OVERLAPPED * overlapped)82c2c66affSColin Finck static BOOL device_io(HANDLE dev, DWORD code, void *inbuffer, DWORD insize, void *outbuffer, DWORD outsize, DWORD *retsize, OVERLAPPED *overlapped)
83c2c66affSColin Finck {
84c2c66affSColin Finck const char *str;
85c2c66affSColin Finck BOOL ret = DeviceIoControl(dev, code, inbuffer, insize, outbuffer, outsize, retsize, overlapped);
86c2c66affSColin Finck
87c2c66affSColin Finck #define XX(x) case (x): str = #x; break
88c2c66affSColin Finck switch (code)
89c2c66affSColin Finck {
90c2c66affSColin Finck XX(IOCTL_CDROM_RAW_READ);
91c2c66affSColin Finck XX(IOCTL_CDROM_READ_TOC);
92c2c66affSColin Finck XX(IOCTL_CDROM_READ_Q_CHANNEL);
93c2c66affSColin Finck XX(IOCTL_CDROM_SEEK_AUDIO_MSF);
94c2c66affSColin Finck XX(IOCTL_CDROM_PLAY_AUDIO_MSF);
95c2c66affSColin Finck XX(IOCTL_CDROM_STOP_AUDIO);
96c2c66affSColin Finck XX(IOCTL_CDROM_PAUSE_AUDIO);
97c2c66affSColin Finck XX(IOCTL_CDROM_RESUME_AUDIO);
98c2c66affSColin Finck XX(IOCTL_STORAGE_EJECT_MEDIA);
99c2c66affSColin Finck XX(IOCTL_STORAGE_LOAD_MEDIA);
100c2c66affSColin Finck default: str = wine_dbg_sprintf("UNKNOWN (0x%x)", code);
101c2c66affSColin Finck };
102c2c66affSColin Finck #undef XX
103c2c66affSColin Finck TRACE("Device %p, Code %s -> Return %d, Bytes %u\n", dev, str, ret, *retsize);
104c2c66affSColin Finck return ret;
105c2c66affSColin Finck }
106c2c66affSColin Finck
MCICDA_playLoop(void * ptr)107c2c66affSColin Finck static DWORD CALLBACK MCICDA_playLoop(void *ptr)
108c2c66affSColin Finck {
109c2c66affSColin Finck WINE_MCICDAUDIO *wmcda = (WINE_MCICDAUDIO*)ptr;
110c2c66affSColin Finck DWORD lastPos, curPos, endPos, br;
111c2c66affSColin Finck void *cdData;
112c2c66affSColin Finck DWORD lockLen, fragLen;
113c2c66affSColin Finck DSBCAPS caps;
114c2c66affSColin Finck RAW_READ_INFO rdInfo;
115c2c66affSColin Finck HRESULT hr = DS_OK;
116c2c66affSColin Finck
117c2c66affSColin Finck memset(&caps, 0, sizeof(caps));
118c2c66affSColin Finck caps.dwSize = sizeof(caps);
119c2c66affSColin Finck hr = IDirectSoundBuffer_GetCaps(wmcda->dsBuf, &caps);
120c2c66affSColin Finck
121c2c66affSColin Finck fragLen = caps.dwBufferBytes/CDDA_FRAG_COUNT;
122c2c66affSColin Finck curPos = lastPos = 0;
123c2c66affSColin Finck endPos = ~0u;
124c2c66affSColin Finck while (SUCCEEDED(hr) && endPos != lastPos &&
125c2c66affSColin Finck WaitForSingleObject(wmcda->stopEvent, 0) != WAIT_OBJECT_0) {
126c2c66affSColin Finck hr = IDirectSoundBuffer_GetCurrentPosition(wmcda->dsBuf, &curPos, NULL);
127c2c66affSColin Finck if ((curPos-lastPos+caps.dwBufferBytes)%caps.dwBufferBytes < fragLen) {
128c2c66affSColin Finck Sleep(1);
129c2c66affSColin Finck continue;
130c2c66affSColin Finck }
131c2c66affSColin Finck
132c2c66affSColin Finck EnterCriticalSection(&wmcda->cs);
133c2c66affSColin Finck rdInfo.DiskOffset.QuadPart = wmcda->start<<11;
134c2c66affSColin Finck rdInfo.SectorCount = min(fragLen/RAW_SECTOR_SIZE, wmcda->end-wmcda->start);
135c2c66affSColin Finck rdInfo.TrackMode = CDDA;
136c2c66affSColin Finck
137c2c66affSColin Finck hr = IDirectSoundBuffer_Lock(wmcda->dsBuf, lastPos, fragLen, &cdData, &lockLen, NULL, NULL, 0);
138c2c66affSColin Finck if (hr == DSERR_BUFFERLOST) {
139c2c66affSColin Finck if(FAILED(IDirectSoundBuffer_Restore(wmcda->dsBuf)) ||
140c2c66affSColin Finck FAILED(IDirectSoundBuffer_Play(wmcda->dsBuf, 0, 0, DSBPLAY_LOOPING))) {
141c2c66affSColin Finck LeaveCriticalSection(&wmcda->cs);
142c2c66affSColin Finck break;
143c2c66affSColin Finck }
144c2c66affSColin Finck hr = IDirectSoundBuffer_Lock(wmcda->dsBuf, lastPos, fragLen, &cdData, &lockLen, NULL, NULL, 0);
145c2c66affSColin Finck }
146c2c66affSColin Finck
147c2c66affSColin Finck if (SUCCEEDED(hr)) {
148c2c66affSColin Finck if (rdInfo.SectorCount > 0) {
149c2c66affSColin Finck if (!device_io(wmcda->handle, IOCTL_CDROM_RAW_READ, &rdInfo, sizeof(rdInfo), cdData, lockLen, &br, NULL))
150c2c66affSColin Finck WARN("CD read failed at sector %d: 0x%x\n", wmcda->start, GetLastError());
151c2c66affSColin Finck }
152c2c66affSColin Finck if (rdInfo.SectorCount*RAW_SECTOR_SIZE < lockLen) {
153c2c66affSColin Finck if(endPos == ~0u) endPos = lastPos;
154c2c66affSColin Finck memset((BYTE*)cdData + rdInfo.SectorCount*RAW_SECTOR_SIZE, 0,
155c2c66affSColin Finck lockLen - rdInfo.SectorCount*RAW_SECTOR_SIZE);
156c2c66affSColin Finck }
157c2c66affSColin Finck hr = IDirectSoundBuffer_Unlock(wmcda->dsBuf, cdData, lockLen, NULL, 0);
158c2c66affSColin Finck }
159c2c66affSColin Finck
160c2c66affSColin Finck lastPos += fragLen;
161c2c66affSColin Finck lastPos %= caps.dwBufferBytes;
162c2c66affSColin Finck wmcda->start += rdInfo.SectorCount;
163c2c66affSColin Finck
164c2c66affSColin Finck LeaveCriticalSection(&wmcda->cs);
165c2c66affSColin Finck }
166c2c66affSColin Finck IDirectSoundBuffer_Stop(wmcda->dsBuf);
167c2c66affSColin Finck SetEvent(wmcda->stopEvent);
168c2c66affSColin Finck
169c2c66affSColin Finck /* A design bug in native: the independent CD player called by the
170c2c66affSColin Finck * MCI has no means to signal end of playing, therefore the MCI
171c2c66affSColin Finck * notification is left hanging. MCI_NOTIFY_SUPERSEDED will be
172c2c66affSColin Finck * signaled by the next command that has MCI_NOTIFY set (or
173c2c66affSColin Finck * MCI_NOTIFY_ABORTED for MCI_PLAY). */
174c2c66affSColin Finck
175c2c66affSColin Finck return 0;
176c2c66affSColin Finck }
177c2c66affSColin Finck
178c2c66affSColin Finck
179c2c66affSColin Finck
180c2c66affSColin Finck /**************************************************************************
181c2c66affSColin Finck * MCICDA_drvOpen [internal]
182c2c66affSColin Finck */
MCICDA_drvOpen(LPCWSTR str,LPMCI_OPEN_DRIVER_PARMSW modp)183c2c66affSColin Finck static DWORD MCICDA_drvOpen(LPCWSTR str, LPMCI_OPEN_DRIVER_PARMSW modp)
184c2c66affSColin Finck {
185c2c66affSColin Finck static HMODULE dsHandle;
186c2c66affSColin Finck WINE_MCICDAUDIO* wmcda;
187c2c66affSColin Finck
188c2c66affSColin Finck if (!modp) return 0xFFFFFFFF;
189c2c66affSColin Finck /* FIXME: MCIERR_CANNOT_LOAD_DRIVER if there's no drive of type CD-ROM */
190c2c66affSColin Finck
191c2c66affSColin Finck wmcda = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINE_MCICDAUDIO));
192c2c66affSColin Finck
193c2c66affSColin Finck if (!wmcda)
194c2c66affSColin Finck return 0;
195c2c66affSColin Finck
196c2c66affSColin Finck if (!dsHandle) {
197c2c66affSColin Finck dsHandle = LoadLibraryA("dsound.dll");
198c2c66affSColin Finck if(dsHandle)
199c2c66affSColin Finck pDirectSoundCreate = (LPDIRECTSOUNDCREATE)GetProcAddress(dsHandle, "DirectSoundCreate");
200c2c66affSColin Finck }
201c2c66affSColin Finck
202c2c66affSColin Finck wmcda->wDevID = modp->wDeviceID;
203c2c66affSColin Finck mciSetDriverData(wmcda->wDevID, (DWORD_PTR)wmcda);
204c2c66affSColin Finck modp->wCustomCommandTable = MCI_NO_COMMAND_TABLE;
205c2c66affSColin Finck modp->wType = MCI_DEVTYPE_CD_AUDIO;
206c2c66affSColin Finck InitializeCriticalSection(&wmcda->cs);
207c2c66affSColin Finck wmcda->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": WINE_MCICDAUDIO.cs");
208c2c66affSColin Finck return modp->wDeviceID;
209c2c66affSColin Finck }
210c2c66affSColin Finck
211c2c66affSColin Finck /**************************************************************************
212c2c66affSColin Finck * MCICDA_drvClose [internal]
213c2c66affSColin Finck */
MCICDA_drvClose(DWORD dwDevID)214c2c66affSColin Finck static DWORD MCICDA_drvClose(DWORD dwDevID)
215c2c66affSColin Finck {
216c2c66affSColin Finck WINE_MCICDAUDIO* wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(dwDevID);
217c2c66affSColin Finck
218c2c66affSColin Finck if (wmcda) {
219c2c66affSColin Finck wmcda->cs.DebugInfo->Spare[0] = 0;
220c2c66affSColin Finck DeleteCriticalSection(&wmcda->cs);
221c2c66affSColin Finck HeapFree(GetProcessHeap(), 0, wmcda);
222c2c66affSColin Finck mciSetDriverData(dwDevID, 0);
223c2c66affSColin Finck }
224c2c66affSColin Finck return (dwDevID == 0xFFFFFFFF) ? 1 : 0;
225c2c66affSColin Finck }
226c2c66affSColin Finck
227c2c66affSColin Finck /**************************************************************************
228c2c66affSColin Finck * MCICDA_GetOpenDrv [internal]
229c2c66affSColin Finck */
MCICDA_GetOpenDrv(UINT wDevID)230c2c66affSColin Finck static WINE_MCICDAUDIO* MCICDA_GetOpenDrv(UINT wDevID)
231c2c66affSColin Finck {
232c2c66affSColin Finck WINE_MCICDAUDIO* wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(wDevID);
233c2c66affSColin Finck
234c2c66affSColin Finck if (wmcda == NULL || wmcda->nUseCount == 0) {
235c2c66affSColin Finck WARN("Invalid wDevID=%u\n", wDevID);
236c2c66affSColin Finck return 0;
237c2c66affSColin Finck }
238c2c66affSColin Finck return wmcda;
239c2c66affSColin Finck }
240c2c66affSColin Finck
241c2c66affSColin Finck /**************************************************************************
242c2c66affSColin Finck * MCICDA_mciNotify [internal]
243c2c66affSColin Finck *
244c2c66affSColin Finck * Notifications in MCI work like a 1-element queue.
245c2c66affSColin Finck * Each new notification request supersedes the previous one.
246c2c66affSColin Finck */
MCICDA_Notify(DWORD_PTR hWndCallBack,WINE_MCICDAUDIO * wmcda,UINT wStatus)247c2c66affSColin Finck static void MCICDA_Notify(DWORD_PTR hWndCallBack, WINE_MCICDAUDIO* wmcda, UINT wStatus)
248c2c66affSColin Finck {
249c2c66affSColin Finck MCIDEVICEID wDevID = wmcda->wNotifyDeviceID;
250c2c66affSColin Finck HANDLE old = InterlockedExchangePointer(&wmcda->hCallback, NULL);
251c2c66affSColin Finck if (old) mciDriverNotify(old, wDevID, MCI_NOTIFY_SUPERSEDED);
252c2c66affSColin Finck mciDriverNotify(HWND_32(LOWORD(hWndCallBack)), wDevID, wStatus);
253c2c66affSColin Finck }
254c2c66affSColin Finck
255c2c66affSColin Finck /**************************************************************************
256c2c66affSColin Finck * MCICDA_ReadTOC [internal]
257c2c66affSColin Finck */
MCICDA_ReadTOC(WINE_MCICDAUDIO * wmcda,CDROM_TOC * toc,DWORD * br)258c2c66affSColin Finck static BOOL MCICDA_ReadTOC(WINE_MCICDAUDIO* wmcda, CDROM_TOC *toc, DWORD *br)
259c2c66affSColin Finck {
260c2c66affSColin Finck if (!device_io(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0, toc, sizeof(*toc), br, NULL)) {
261c2c66affSColin Finck WARN("error reading TOC !\n");
262c2c66affSColin Finck return FALSE;
263c2c66affSColin Finck }
264c2c66affSColin Finck return TRUE;
265c2c66affSColin Finck }
266c2c66affSColin Finck
267c2c66affSColin Finck /**************************************************************************
268c2c66affSColin Finck * MCICDA_GetStatus [internal]
269c2c66affSColin Finck */
MCICDA_GetStatus(WINE_MCICDAUDIO * wmcda)270c2c66affSColin Finck static DWORD MCICDA_GetStatus(WINE_MCICDAUDIO* wmcda)
271c2c66affSColin Finck {
272c2c66affSColin Finck CDROM_SUB_Q_DATA_FORMAT fmt;
273c2c66affSColin Finck SUB_Q_CHANNEL_DATA data;
274c2c66affSColin Finck DWORD br;
275c2c66affSColin Finck DWORD mode = MCI_MODE_NOT_READY;
276c2c66affSColin Finck
277c2c66affSColin Finck fmt.Format = IOCTL_CDROM_CURRENT_POSITION;
278c2c66affSColin Finck if(wmcda->hThread != 0) {
279c2c66affSColin Finck DWORD status;
280c2c66affSColin Finck HRESULT hr;
281c2c66affSColin Finck
282c2c66affSColin Finck hr = IDirectSoundBuffer_GetStatus(wmcda->dsBuf, &status);
283c2c66affSColin Finck if(SUCCEEDED(hr)) {
284c2c66affSColin Finck if(!(status&DSBSTATUS_PLAYING)) {
285c2c66affSColin Finck if(WaitForSingleObject(wmcda->stopEvent, 0) == WAIT_OBJECT_0)
286c2c66affSColin Finck mode = MCI_MODE_STOP;
287c2c66affSColin Finck else
288c2c66affSColin Finck mode = MCI_MODE_PAUSE;
289c2c66affSColin Finck }
290c2c66affSColin Finck else
291c2c66affSColin Finck mode = MCI_MODE_PLAY;
292c2c66affSColin Finck }
293c2c66affSColin Finck }
294c2c66affSColin Finck else if (!device_io(wmcda->handle, IOCTL_CDROM_READ_Q_CHANNEL, &fmt, sizeof(fmt),
295c2c66affSColin Finck &data, sizeof(data), &br, NULL)) {
296c2c66affSColin Finck if (GetLastError() == ERROR_NOT_READY) mode = MCI_MODE_OPEN;
297c2c66affSColin Finck } else {
298c2c66affSColin Finck switch (data.CurrentPosition.Header.AudioStatus)
299c2c66affSColin Finck {
300c2c66affSColin Finck case AUDIO_STATUS_IN_PROGRESS: mode = MCI_MODE_PLAY; break;
301c2c66affSColin Finck case AUDIO_STATUS_PAUSED: mode = MCI_MODE_PAUSE; break;
302c2c66affSColin Finck case AUDIO_STATUS_NO_STATUS:
303c2c66affSColin Finck case AUDIO_STATUS_PLAY_COMPLETE: mode = MCI_MODE_STOP; break;
304c2c66affSColin Finck case AUDIO_STATUS_PLAY_ERROR:
305c2c66affSColin Finck case AUDIO_STATUS_NOT_SUPPORTED:
306c2c66affSColin Finck default:
307c2c66affSColin Finck break;
308c2c66affSColin Finck }
309c2c66affSColin Finck }
310c2c66affSColin Finck return mode;
311c2c66affSColin Finck }
312c2c66affSColin Finck
313c2c66affSColin Finck /**************************************************************************
314c2c66affSColin Finck * MCICDA_GetError [internal]
315c2c66affSColin Finck */
MCICDA_GetError(WINE_MCICDAUDIO * wmcda)316c2c66affSColin Finck static int MCICDA_GetError(WINE_MCICDAUDIO* wmcda)
317c2c66affSColin Finck {
318c2c66affSColin Finck switch (GetLastError())
319c2c66affSColin Finck {
320c2c66affSColin Finck case ERROR_NOT_READY: return MCIERR_DEVICE_NOT_READY;
321c2c66affSColin Finck case ERROR_NOT_SUPPORTED:
322c2c66affSColin Finck case ERROR_IO_DEVICE: return MCIERR_HARDWARE;
323c2c66affSColin Finck default:
324c2c66affSColin Finck FIXME("Unknown mode %u\n", GetLastError());
325c2c66affSColin Finck }
326c2c66affSColin Finck return MCIERR_DRIVER_INTERNAL;
327c2c66affSColin Finck }
328c2c66affSColin Finck
329c2c66affSColin Finck /**************************************************************************
330c2c66affSColin Finck * MCICDA_CalcFrame [internal]
331c2c66affSColin Finck */
MCICDA_CalcFrame(WINE_MCICDAUDIO * wmcda,DWORD dwTime)332c2c66affSColin Finck static DWORD MCICDA_CalcFrame(WINE_MCICDAUDIO* wmcda, DWORD dwTime)
333c2c66affSColin Finck {
334c2c66affSColin Finck DWORD dwFrame = 0;
335c2c66affSColin Finck UINT wTrack;
336c2c66affSColin Finck CDROM_TOC toc;
337c2c66affSColin Finck DWORD br;
338c2c66affSColin Finck BYTE* addr;
339c2c66affSColin Finck
340c2c66affSColin Finck TRACE("(%p, %08X, %u);\n", wmcda, wmcda->dwTimeFormat, dwTime);
341c2c66affSColin Finck
342c2c66affSColin Finck switch (wmcda->dwTimeFormat) {
343c2c66affSColin Finck case MCI_FORMAT_MILLISECONDS:
344c2c66affSColin Finck dwFrame = ((dwTime - 1) * CDFRAMES_PERSEC + 500) / 1000;
345c2c66affSColin Finck TRACE("MILLISECONDS %u\n", dwFrame);
346c2c66affSColin Finck break;
347c2c66affSColin Finck case MCI_FORMAT_MSF:
348c2c66affSColin Finck TRACE("MSF %02u:%02u:%02u\n",
349c2c66affSColin Finck MCI_MSF_MINUTE(dwTime), MCI_MSF_SECOND(dwTime), MCI_MSF_FRAME(dwTime));
350c2c66affSColin Finck dwFrame += CDFRAMES_PERMIN * MCI_MSF_MINUTE(dwTime);
351c2c66affSColin Finck dwFrame += CDFRAMES_PERSEC * MCI_MSF_SECOND(dwTime);
352c2c66affSColin Finck dwFrame += MCI_MSF_FRAME(dwTime);
353c2c66affSColin Finck break;
354c2c66affSColin Finck case MCI_FORMAT_TMSF:
355c2c66affSColin Finck default: /* unknown format ! force TMSF ! ... */
356c2c66affSColin Finck wTrack = MCI_TMSF_TRACK(dwTime);
357c2c66affSColin Finck if (!device_io(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0,
358c2c66affSColin Finck &toc, sizeof(toc), &br, NULL))
359c2c66affSColin Finck return 0;
360c2c66affSColin Finck if (wTrack < toc.FirstTrack || wTrack > toc.LastTrack)
361c2c66affSColin Finck return 0;
362c2c66affSColin Finck TRACE("MSF %02u-%02u:%02u:%02u\n",
363c2c66affSColin Finck MCI_TMSF_TRACK(dwTime), MCI_TMSF_MINUTE(dwTime),
364c2c66affSColin Finck MCI_TMSF_SECOND(dwTime), MCI_TMSF_FRAME(dwTime));
365c2c66affSColin Finck addr = toc.TrackData[wTrack - toc.FirstTrack].Address;
366c2c66affSColin Finck TRACE("TMSF trackpos[%u]=%d:%d:%d\n",
367c2c66affSColin Finck wTrack, addr[1], addr[2], addr[3]);
368c2c66affSColin Finck dwFrame = CDFRAMES_PERMIN * (addr[1] + MCI_TMSF_MINUTE(dwTime)) +
369c2c66affSColin Finck CDFRAMES_PERSEC * (addr[2] + MCI_TMSF_SECOND(dwTime)) +
370c2c66affSColin Finck addr[3] + MCI_TMSF_FRAME(dwTime);
371c2c66affSColin Finck break;
372c2c66affSColin Finck }
373c2c66affSColin Finck return dwFrame;
374c2c66affSColin Finck }
375c2c66affSColin Finck
376c2c66affSColin Finck /**************************************************************************
377c2c66affSColin Finck * MCICDA_CalcTime [internal]
378c2c66affSColin Finck */
MCICDA_CalcTime(WINE_MCICDAUDIO * wmcda,DWORD tf,DWORD dwFrame,LPDWORD lpRet)379c2c66affSColin Finck static DWORD MCICDA_CalcTime(WINE_MCICDAUDIO* wmcda, DWORD tf, DWORD dwFrame, LPDWORD lpRet)
380c2c66affSColin Finck {
381c2c66affSColin Finck DWORD dwTime = 0;
382c2c66affSColin Finck UINT wTrack;
383c2c66affSColin Finck UINT wMinutes;
384c2c66affSColin Finck UINT wSeconds;
385c2c66affSColin Finck UINT wFrames;
386c2c66affSColin Finck CDROM_TOC toc;
387c2c66affSColin Finck DWORD br;
388c2c66affSColin Finck
389c2c66affSColin Finck TRACE("(%p, %08X, %u);\n", wmcda, tf, dwFrame);
390c2c66affSColin Finck
391c2c66affSColin Finck switch (tf) {
392c2c66affSColin Finck case MCI_FORMAT_MILLISECONDS:
393c2c66affSColin Finck dwTime = (dwFrame * 1000) / CDFRAMES_PERSEC + 1;
394c2c66affSColin Finck TRACE("MILLISECONDS %u\n", dwTime);
395c2c66affSColin Finck *lpRet = 0;
396c2c66affSColin Finck break;
397c2c66affSColin Finck case MCI_FORMAT_MSF:
398c2c66affSColin Finck wMinutes = dwFrame / CDFRAMES_PERMIN;
399c2c66affSColin Finck wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
400c2c66affSColin Finck wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;
401c2c66affSColin Finck dwTime = MCI_MAKE_MSF(wMinutes, wSeconds, wFrames);
402c2c66affSColin Finck TRACE("MSF %02u:%02u:%02u -> dwTime=%u\n",
403c2c66affSColin Finck wMinutes, wSeconds, wFrames, dwTime);
404c2c66affSColin Finck *lpRet = MCI_COLONIZED3_RETURN;
405c2c66affSColin Finck break;
406c2c66affSColin Finck case MCI_FORMAT_TMSF:
407c2c66affSColin Finck default: /* unknown format ! force TMSF ! ... */
408c2c66affSColin Finck if (!device_io(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0,
409c2c66affSColin Finck &toc, sizeof(toc), &br, NULL))
410c2c66affSColin Finck return 0;
411c2c66affSColin Finck if (dwFrame < FRAME_OF_TOC(toc, toc.FirstTrack) ||
412c2c66affSColin Finck dwFrame > FRAME_OF_TOC(toc, toc.LastTrack + 1)) {
413c2c66affSColin Finck ERR("Out of range value %u [%u,%u]\n",
414c2c66affSColin Finck dwFrame, FRAME_OF_TOC(toc, toc.FirstTrack),
415c2c66affSColin Finck FRAME_OF_TOC(toc, toc.LastTrack + 1));
416c2c66affSColin Finck *lpRet = 0;
417c2c66affSColin Finck return 0;
418c2c66affSColin Finck }
419c2c66affSColin Finck for (wTrack = toc.FirstTrack; wTrack <= toc.LastTrack; wTrack++) {
420c2c66affSColin Finck if (FRAME_OF_TOC(toc, wTrack) > dwFrame)
421c2c66affSColin Finck break;
422c2c66affSColin Finck }
423c2c66affSColin Finck wTrack--;
424c2c66affSColin Finck dwFrame -= FRAME_OF_TOC(toc, wTrack);
425c2c66affSColin Finck wMinutes = dwFrame / CDFRAMES_PERMIN;
426c2c66affSColin Finck wSeconds = (dwFrame - CDFRAMES_PERMIN * wMinutes) / CDFRAMES_PERSEC;
427c2c66affSColin Finck wFrames = dwFrame - CDFRAMES_PERMIN * wMinutes - CDFRAMES_PERSEC * wSeconds;
428c2c66affSColin Finck dwTime = MCI_MAKE_TMSF(wTrack, wMinutes, wSeconds, wFrames);
429c2c66affSColin Finck TRACE("%02u-%02u:%02u:%02u\n", wTrack, wMinutes, wSeconds, wFrames);
430c2c66affSColin Finck *lpRet = MCI_COLONIZED4_RETURN;
431c2c66affSColin Finck break;
432c2c66affSColin Finck }
433c2c66affSColin Finck return dwTime;
434c2c66affSColin Finck }
435c2c66affSColin Finck
436c2c66affSColin Finck static DWORD MCICDA_Stop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms);
437c2c66affSColin Finck
438c2c66affSColin Finck /**************************************************************************
439c2c66affSColin Finck * MCICDA_Open [internal]
440c2c66affSColin Finck */
MCICDA_Open(UINT wDevID,DWORD dwFlags,LPMCI_OPEN_PARMSW lpOpenParms)441c2c66affSColin Finck static DWORD MCICDA_Open(UINT wDevID, DWORD dwFlags, LPMCI_OPEN_PARMSW lpOpenParms)
442c2c66affSColin Finck {
443c2c66affSColin Finck MCIDEVICEID dwDeviceID;
444c2c66affSColin Finck DWORD ret;
445c2c66affSColin Finck WINE_MCICDAUDIO* wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(wDevID);
446c2c66affSColin Finck WCHAR root[7], drive = 0;
447c2c66affSColin Finck
448c2c66affSColin Finck TRACE("(%04X, %08X, %p);\n", wDevID, dwFlags, lpOpenParms);
449c2c66affSColin Finck
450c2c66affSColin Finck if (lpOpenParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
451c2c66affSColin Finck if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
452c2c66affSColin Finck
453c2c66affSColin Finck dwDeviceID = lpOpenParms->wDeviceID;
454c2c66affSColin Finck
455c2c66affSColin Finck if (wmcda->nUseCount > 0) {
456c2c66affSColin Finck /* The driver is already open on this channel */
457c2c66affSColin Finck /* If the driver was opened shareable before and this open specifies */
458c2c66affSColin Finck /* shareable then increment the use count */
459c2c66affSColin Finck if (wmcda->fShareable && (dwFlags & MCI_OPEN_SHAREABLE))
460c2c66affSColin Finck ++wmcda->nUseCount;
461c2c66affSColin Finck else
462c2c66affSColin Finck return MCIERR_MUST_USE_SHAREABLE;
463c2c66affSColin Finck } else {
464c2c66affSColin Finck wmcda->nUseCount = 1;
465c2c66affSColin Finck wmcda->fShareable = dwFlags & MCI_OPEN_SHAREABLE;
466c2c66affSColin Finck }
467c2c66affSColin Finck if (dwFlags & MCI_OPEN_ELEMENT) {
468c2c66affSColin Finck if (dwFlags & MCI_OPEN_ELEMENT_ID) {
469c2c66affSColin Finck WARN("MCI_OPEN_ELEMENT_ID %p! Abort\n", lpOpenParms->lpstrElementName);
470c2c66affSColin Finck ret = MCIERR_FLAGS_NOT_COMPATIBLE;
471c2c66affSColin Finck goto the_error;
472c2c66affSColin Finck }
473c2c66affSColin Finck TRACE("MCI_OPEN_ELEMENT element name: %s\n", debugstr_w(lpOpenParms->lpstrElementName));
474c2c66affSColin Finck /* Only the first letter counts since w2k
475c2c66affSColin Finck * Win9x-NT accept only d: and w98SE accepts d:\foobar as well.
476c2c66affSColin Finck * Play d:\Track03.cda plays from the first track, not #3. */
477c2c66affSColin Finck if (!isalpha(lpOpenParms->lpstrElementName[0]))
478c2c66affSColin Finck {
479c2c66affSColin Finck ret = MCIERR_INVALID_FILE;
480c2c66affSColin Finck goto the_error;
481c2c66affSColin Finck }
482c2c66affSColin Finck drive = toupper(lpOpenParms->lpstrElementName[0]);
483c2c66affSColin Finck root[0] = drive; root[1] = ':'; root[2] = '\\'; root[3] = '\0';
484c2c66affSColin Finck if (GetDriveTypeW(root) != DRIVE_CDROM)
485c2c66affSColin Finck {
486c2c66affSColin Finck ret = MCIERR_INVALID_FILE;
487c2c66affSColin Finck goto the_error;
488c2c66affSColin Finck }
489c2c66affSColin Finck }
490c2c66affSColin Finck else
491c2c66affSColin Finck {
492c2c66affSColin Finck root[0] = 'A'; root[1] = ':'; root[2] = '\\'; root[3] = '\0';
493c2c66affSColin Finck for ( ; root[0] <= 'Z'; root[0]++)
494c2c66affSColin Finck {
495c2c66affSColin Finck if (GetDriveTypeW(root) == DRIVE_CDROM)
496c2c66affSColin Finck {
497c2c66affSColin Finck drive = root[0];
498c2c66affSColin Finck break;
499c2c66affSColin Finck }
500c2c66affSColin Finck }
501c2c66affSColin Finck if (!drive)
502c2c66affSColin Finck {
503c2c66affSColin Finck ret = MCIERR_CANNOT_LOAD_DRIVER; /* drvOpen should return this */
504c2c66affSColin Finck goto the_error;
505c2c66affSColin Finck }
506c2c66affSColin Finck }
507c2c66affSColin Finck
508c2c66affSColin Finck wmcda->wNotifyDeviceID = dwDeviceID;
509c2c66affSColin Finck wmcda->dwTimeFormat = MCI_FORMAT_MSF;
510c2c66affSColin Finck
511c2c66affSColin Finck /* now, open the handle */
512c2c66affSColin Finck root[0] = root[1] = '\\'; root[2] = '.'; root[3] = '\\'; root[4] = drive; root[5] = ':'; root[6] = '\0';
513c2c66affSColin Finck wmcda->handle = CreateFileW(root, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
514c2c66affSColin Finck if (wmcda->handle == INVALID_HANDLE_VALUE)
515c2c66affSColin Finck {
516c2c66affSColin Finck ret = MCIERR_MUST_USE_SHAREABLE;
517c2c66affSColin Finck goto the_error;
518c2c66affSColin Finck }
519c2c66affSColin Finck
520c2c66affSColin Finck if (dwFlags & MCI_NOTIFY) {
521c2c66affSColin Finck mciDriverNotify(HWND_32(LOWORD(lpOpenParms->dwCallback)),
522c2c66affSColin Finck dwDeviceID, MCI_NOTIFY_SUCCESSFUL);
523c2c66affSColin Finck }
524c2c66affSColin Finck return 0;
525c2c66affSColin Finck
526c2c66affSColin Finck the_error:
527c2c66affSColin Finck --wmcda->nUseCount;
528c2c66affSColin Finck return ret;
529c2c66affSColin Finck }
530c2c66affSColin Finck
531c2c66affSColin Finck /**************************************************************************
532c2c66affSColin Finck * MCICDA_Close [internal]
533c2c66affSColin Finck */
MCICDA_Close(UINT wDevID,DWORD dwParam,LPMCI_GENERIC_PARMS lpParms)534c2c66affSColin Finck static DWORD MCICDA_Close(UINT wDevID, DWORD dwParam, LPMCI_GENERIC_PARMS lpParms)
535c2c66affSColin Finck {
536c2c66affSColin Finck WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
537c2c66affSColin Finck
538c2c66affSColin Finck TRACE("(%04X, %08X, %p);\n", wDevID, dwParam, lpParms);
539c2c66affSColin Finck
540c2c66affSColin Finck if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
541c2c66affSColin Finck
542c2c66affSColin Finck MCICDA_Stop(wDevID, MCI_WAIT, NULL);
543c2c66affSColin Finck
544c2c66affSColin Finck if (--wmcda->nUseCount == 0) {
545c2c66affSColin Finck CloseHandle(wmcda->handle);
546c2c66affSColin Finck }
547c2c66affSColin Finck if ((dwParam & MCI_NOTIFY) && lpParms)
548c2c66affSColin Finck MCICDA_Notify(lpParms->dwCallback, wmcda, MCI_NOTIFY_SUCCESSFUL);
549c2c66affSColin Finck return 0;
550c2c66affSColin Finck }
551c2c66affSColin Finck
552c2c66affSColin Finck /**************************************************************************
553c2c66affSColin Finck * MCICDA_GetDevCaps [internal]
554c2c66affSColin Finck */
MCICDA_GetDevCaps(UINT wDevID,DWORD dwFlags,LPMCI_GETDEVCAPS_PARMS lpParms)555c2c66affSColin Finck static DWORD MCICDA_GetDevCaps(UINT wDevID, DWORD dwFlags,
556c2c66affSColin Finck LPMCI_GETDEVCAPS_PARMS lpParms)
557c2c66affSColin Finck {
558c2c66affSColin Finck WINE_MCICDAUDIO* wmcda = (WINE_MCICDAUDIO*)mciGetDriverData(wDevID);
559c2c66affSColin Finck DWORD ret = 0;
560c2c66affSColin Finck
561c2c66affSColin Finck TRACE("(%04X, %08X, %p);\n", wDevID, dwFlags, lpParms);
562c2c66affSColin Finck
563c2c66affSColin Finck if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
564c2c66affSColin Finck if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
565c2c66affSColin Finck
566c2c66affSColin Finck if (dwFlags & MCI_GETDEVCAPS_ITEM) {
567c2c66affSColin Finck TRACE("MCI_GETDEVCAPS_ITEM dwItem=%08X;\n", lpParms->dwItem);
568c2c66affSColin Finck
569c2c66affSColin Finck switch (lpParms->dwItem) {
570c2c66affSColin Finck case MCI_GETDEVCAPS_CAN_RECORD:
571c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
572c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
573c2c66affSColin Finck break;
574c2c66affSColin Finck case MCI_GETDEVCAPS_HAS_AUDIO:
575c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
576c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
577c2c66affSColin Finck break;
578c2c66affSColin Finck case MCI_GETDEVCAPS_HAS_VIDEO:
579c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
580c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
581c2c66affSColin Finck break;
582c2c66affSColin Finck case MCI_GETDEVCAPS_DEVICE_TYPE:
583c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(MCI_DEVTYPE_CD_AUDIO, MCI_DEVTYPE_CD_AUDIO);
584c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
585c2c66affSColin Finck break;
586c2c66affSColin Finck case MCI_GETDEVCAPS_USES_FILES:
587c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
588c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
589c2c66affSColin Finck break;
590c2c66affSColin Finck case MCI_GETDEVCAPS_COMPOUND_DEVICE:
591c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
592c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
593c2c66affSColin Finck break;
594c2c66affSColin Finck case MCI_GETDEVCAPS_CAN_EJECT:
595c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
596c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
597c2c66affSColin Finck break;
598c2c66affSColin Finck case MCI_GETDEVCAPS_CAN_PLAY:
599c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
600c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
601c2c66affSColin Finck break;
602c2c66affSColin Finck case MCI_GETDEVCAPS_CAN_SAVE:
603c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
604c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
605c2c66affSColin Finck break;
606c2c66affSColin Finck default:
607c2c66affSColin Finck WARN("Unsupported %x devCaps item\n", lpParms->dwItem);
608c2c66affSColin Finck return MCIERR_UNSUPPORTED_FUNCTION;
609c2c66affSColin Finck }
610c2c66affSColin Finck } else {
611c2c66affSColin Finck TRACE("No GetDevCaps-Item !\n");
612c2c66affSColin Finck return MCIERR_MISSING_PARAMETER;
613c2c66affSColin Finck }
614c2c66affSColin Finck TRACE("lpParms->dwReturn=%08X;\n", lpParms->dwReturn);
615c2c66affSColin Finck if (dwFlags & MCI_NOTIFY) {
616c2c66affSColin Finck MCICDA_Notify(lpParms->dwCallback, wmcda, MCI_NOTIFY_SUCCESSFUL);
617c2c66affSColin Finck }
618c2c66affSColin Finck return ret;
619c2c66affSColin Finck }
620c2c66affSColin Finck
CDROM_Audio_GetSerial(CDROM_TOC * toc)621c2c66affSColin Finck static DWORD CDROM_Audio_GetSerial(CDROM_TOC* toc)
622c2c66affSColin Finck {
623c2c66affSColin Finck DWORD serial = 0;
624c2c66affSColin Finck int i;
625c2c66affSColin Finck WORD wMagic;
626c2c66affSColin Finck DWORD dwStart, dwEnd;
627c2c66affSColin Finck
628c2c66affSColin Finck /*
629c2c66affSColin Finck * wMagic collects the wFrames from track 1
630c2c66affSColin Finck * dwStart, dwEnd collect the beginning and end of the disc respectively, in
631c2c66affSColin Finck * frames.
632c2c66affSColin Finck * There it is collected for correcting the serial when there are less than
633c2c66affSColin Finck * 3 tracks.
634c2c66affSColin Finck */
635c2c66affSColin Finck wMagic = toc->TrackData[0].Address[3];
636c2c66affSColin Finck dwStart = FRAME_OF_TOC(*toc, toc->FirstTrack);
637c2c66affSColin Finck
638c2c66affSColin Finck for (i = 0; i <= toc->LastTrack - toc->FirstTrack; i++) {
639c2c66affSColin Finck serial += (toc->TrackData[i].Address[1] << 16) |
640c2c66affSColin Finck (toc->TrackData[i].Address[2] << 8) | toc->TrackData[i].Address[3];
641c2c66affSColin Finck }
642c2c66affSColin Finck dwEnd = FRAME_OF_TOC(*toc, toc->LastTrack + 1);
643c2c66affSColin Finck
644c2c66affSColin Finck if (toc->LastTrack - toc->FirstTrack + 1 < 3)
645c2c66affSColin Finck serial += wMagic + (dwEnd - dwStart);
646c2c66affSColin Finck
647c2c66affSColin Finck return serial;
648c2c66affSColin Finck }
649c2c66affSColin Finck
650c2c66affSColin Finck
651c2c66affSColin Finck /**************************************************************************
652c2c66affSColin Finck * MCICDA_Info [internal]
653c2c66affSColin Finck */
MCICDA_Info(UINT wDevID,DWORD dwFlags,LPMCI_INFO_PARMSW lpParms)654c2c66affSColin Finck static DWORD MCICDA_Info(UINT wDevID, DWORD dwFlags, LPMCI_INFO_PARMSW lpParms)
655c2c66affSColin Finck {
656c2c66affSColin Finck LPCWSTR str = NULL;
657c2c66affSColin Finck WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
658c2c66affSColin Finck DWORD ret = 0;
659c2c66affSColin Finck WCHAR buffer[16];
660c2c66affSColin Finck
661c2c66affSColin Finck TRACE("(%04X, %08X, %p);\n", wDevID, dwFlags, lpParms);
662c2c66affSColin Finck
663c2c66affSColin Finck if (lpParms == NULL || lpParms->lpstrReturn == NULL)
664c2c66affSColin Finck return MCIERR_NULL_PARAMETER_BLOCK;
665c2c66affSColin Finck if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
666c2c66affSColin Finck
667c2c66affSColin Finck TRACE("buf=%p, len=%u\n", lpParms->lpstrReturn, lpParms->dwRetSize);
668c2c66affSColin Finck
669c2c66affSColin Finck if (dwFlags & MCI_INFO_PRODUCT) {
670c2c66affSColin Finck static const WCHAR wszAudioCd[] = {'W','i','n','e','\'','s',' ','a','u','d','i','o',' ','C','D',0};
671c2c66affSColin Finck str = wszAudioCd;
672c2c66affSColin Finck } else if (dwFlags & MCI_INFO_MEDIA_UPC) {
673c2c66affSColin Finck ret = MCIERR_NO_IDENTITY;
674c2c66affSColin Finck } else if (dwFlags & MCI_INFO_MEDIA_IDENTITY) {
675c2c66affSColin Finck DWORD res = 0;
676c2c66affSColin Finck CDROM_TOC toc;
677c2c66affSColin Finck DWORD br;
678c2c66affSColin Finck static const WCHAR wszLu[] = {'%','l','u',0};
679c2c66affSColin Finck
680c2c66affSColin Finck if (!device_io(wmcda->handle, IOCTL_CDROM_READ_TOC, NULL, 0,
681c2c66affSColin Finck &toc, sizeof(toc), &br, NULL)) {
682c2c66affSColin Finck return MCICDA_GetError(wmcda);
683c2c66affSColin Finck }
684c2c66affSColin Finck
685c2c66affSColin Finck res = CDROM_Audio_GetSerial(&toc);
686c2c66affSColin Finck sprintfW(buffer, wszLu, res);
687c2c66affSColin Finck str = buffer;
688c2c66affSColin Finck } else {
689c2c66affSColin Finck WARN("Don't know this info command (%u)\n", dwFlags);
690c2c66affSColin Finck ret = MCIERR_MISSING_PARAMETER;
691c2c66affSColin Finck }
692c2c66affSColin Finck if (!ret) {
693c2c66affSColin Finck TRACE("=> %s\n", debugstr_w(str));
694c2c66affSColin Finck if (lpParms->dwRetSize) {
695c2c66affSColin Finck /* FIXME? Since NT, mciwave, mciseq and mcicda set dwRetSize
696c2c66affSColin Finck * to the number of characters written, excluding \0. */
697c2c66affSColin Finck lstrcpynW(lpParms->lpstrReturn, str, lpParms->dwRetSize);
698c2c66affSColin Finck } else ret = MCIERR_PARAM_OVERFLOW;
699c2c66affSColin Finck }
700c2c66affSColin Finck if (MMSYSERR_NOERROR==ret && (dwFlags & MCI_NOTIFY))
701c2c66affSColin Finck MCICDA_Notify(lpParms->dwCallback, wmcda, MCI_NOTIFY_SUCCESSFUL);
702c2c66affSColin Finck return ret;
703c2c66affSColin Finck }
704c2c66affSColin Finck
705c2c66affSColin Finck /**************************************************************************
706c2c66affSColin Finck * MCICDA_Status [internal]
707c2c66affSColin Finck */
MCICDA_Status(UINT wDevID,DWORD dwFlags,LPMCI_STATUS_PARMS lpParms)708c2c66affSColin Finck static DWORD MCICDA_Status(UINT wDevID, DWORD dwFlags, LPMCI_STATUS_PARMS lpParms)
709c2c66affSColin Finck {
710c2c66affSColin Finck WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
711c2c66affSColin Finck DWORD ret = 0;
712c2c66affSColin Finck CDROM_SUB_Q_DATA_FORMAT fmt;
713c2c66affSColin Finck SUB_Q_CHANNEL_DATA data;
714c2c66affSColin Finck CDROM_TOC toc;
715c2c66affSColin Finck DWORD br;
716c2c66affSColin Finck
717c2c66affSColin Finck TRACE("(%04X, %08X, %p);\n", wDevID, dwFlags, lpParms);
718c2c66affSColin Finck
719c2c66affSColin Finck if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
720c2c66affSColin Finck if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
721c2c66affSColin Finck
722c2c66affSColin Finck if (dwFlags & MCI_STATUS_ITEM) {
723c2c66affSColin Finck TRACE("dwItem = %x\n", lpParms->dwItem);
724c2c66affSColin Finck switch (lpParms->dwItem) {
725c2c66affSColin Finck case MCI_STATUS_CURRENT_TRACK:
726c2c66affSColin Finck fmt.Format = IOCTL_CDROM_CURRENT_POSITION;
727c2c66affSColin Finck if (!device_io(wmcda->handle, IOCTL_CDROM_READ_Q_CHANNEL, &fmt, sizeof(fmt),
728c2c66affSColin Finck &data, sizeof(data), &br, NULL))
729c2c66affSColin Finck {
730c2c66affSColin Finck return MCICDA_GetError(wmcda);
731c2c66affSColin Finck /* alt. data.CurrentPosition.TrackNumber = 1; -- what native yields */
732c2c66affSColin Finck }
733c2c66affSColin Finck lpParms->dwReturn = data.CurrentPosition.TrackNumber;
734c2c66affSColin Finck TRACE("CURRENT_TRACK=%lu\n", lpParms->dwReturn);
735c2c66affSColin Finck break;
736c2c66affSColin Finck case MCI_STATUS_LENGTH:
737c2c66affSColin Finck if (!MCICDA_ReadTOC(wmcda, &toc, &br))
738c2c66affSColin Finck return MCICDA_GetError(wmcda);
739c2c66affSColin Finck
740c2c66affSColin Finck if (dwFlags & MCI_TRACK) {
741c2c66affSColin Finck TRACE("MCI_TRACK #%u LENGTH=??? !\n", lpParms->dwTrack);
742c2c66affSColin Finck if (lpParms->dwTrack < toc.FirstTrack || lpParms->dwTrack > toc.LastTrack)
743c2c66affSColin Finck return MCIERR_OUTOFRANGE;
744c2c66affSColin Finck lpParms->dwReturn = FRAME_OF_TOC(toc, lpParms->dwTrack + 1) -
745c2c66affSColin Finck FRAME_OF_TOC(toc, lpParms->dwTrack);
746c2c66affSColin Finck /* Windows returns one frame less than the total track length for the
747c2c66affSColin Finck last track on the CD. See CDDB HOWTO. Verified on Win95OSR2. */
748c2c66affSColin Finck if (lpParms->dwTrack == toc.LastTrack)
749c2c66affSColin Finck lpParms->dwReturn--;
750c2c66affSColin Finck } else {
751c2c66affSColin Finck /* Sum of the lengths of all of the tracks. Inherits the
752c2c66affSColin Finck 'off by one frame' behavior from the length of the last track.
753c2c66affSColin Finck See above comment. */
754c2c66affSColin Finck lpParms->dwReturn = FRAME_OF_TOC(toc, toc.LastTrack + 1) -
755c2c66affSColin Finck FRAME_OF_TOC(toc, toc.FirstTrack) - 1;
756c2c66affSColin Finck }
757c2c66affSColin Finck lpParms->dwReturn = MCICDA_CalcTime(wmcda,
758c2c66affSColin Finck (wmcda->dwTimeFormat == MCI_FORMAT_TMSF)
759c2c66affSColin Finck ? MCI_FORMAT_MSF : wmcda->dwTimeFormat,
760c2c66affSColin Finck lpParms->dwReturn,
761c2c66affSColin Finck &ret);
762c2c66affSColin Finck TRACE("LENGTH=%lu\n", lpParms->dwReturn);
763c2c66affSColin Finck break;
764c2c66affSColin Finck case MCI_STATUS_MODE:
765c2c66affSColin Finck lpParms->dwReturn = MCICDA_GetStatus(wmcda);
766c2c66affSColin Finck TRACE("MCI_STATUS_MODE=%08lX\n", lpParms->dwReturn);
767c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(lpParms->dwReturn, lpParms->dwReturn);
768c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
769c2c66affSColin Finck break;
770c2c66affSColin Finck case MCI_STATUS_MEDIA_PRESENT:
771c2c66affSColin Finck lpParms->dwReturn = (MCICDA_GetStatus(wmcda) == MCI_MODE_OPEN) ?
772c2c66affSColin Finck MAKEMCIRESOURCE(FALSE, MCI_FALSE) : MAKEMCIRESOURCE(TRUE, MCI_TRUE);
773c2c66affSColin Finck TRACE("MCI_STATUS_MEDIA_PRESENT =%c!\n", LOWORD(lpParms->dwReturn) ? 'Y' : 'N');
774c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
775c2c66affSColin Finck break;
776c2c66affSColin Finck case MCI_STATUS_NUMBER_OF_TRACKS:
777c2c66affSColin Finck if (!MCICDA_ReadTOC(wmcda, &toc, &br))
778c2c66affSColin Finck return MCICDA_GetError(wmcda);
779c2c66affSColin Finck
780c2c66affSColin Finck lpParms->dwReturn = toc.LastTrack - toc.FirstTrack + 1;
781c2c66affSColin Finck TRACE("MCI_STATUS_NUMBER_OF_TRACKS = %lu\n", lpParms->dwReturn);
782c2c66affSColin Finck if (lpParms->dwReturn == (WORD)-1)
783c2c66affSColin Finck return MCICDA_GetError(wmcda);
784c2c66affSColin Finck break;
785c2c66affSColin Finck case MCI_STATUS_POSITION:
786c2c66affSColin Finck switch (dwFlags & (MCI_STATUS_START | MCI_TRACK)) {
787c2c66affSColin Finck case MCI_STATUS_START:
788c2c66affSColin Finck if (!MCICDA_ReadTOC(wmcda, &toc, &br))
789c2c66affSColin Finck return MCICDA_GetError(wmcda);
790c2c66affSColin Finck
791c2c66affSColin Finck lpParms->dwReturn = FRAME_OF_TOC(toc, toc.FirstTrack);
792c2c66affSColin Finck TRACE("get MCI_STATUS_START !\n");
793c2c66affSColin Finck break;
794c2c66affSColin Finck case MCI_TRACK:
795c2c66affSColin Finck if (!MCICDA_ReadTOC(wmcda, &toc, &br))
796c2c66affSColin Finck return MCICDA_GetError(wmcda);
797c2c66affSColin Finck
798c2c66affSColin Finck if (lpParms->dwTrack < toc.FirstTrack || lpParms->dwTrack > toc.LastTrack)
799c2c66affSColin Finck return MCIERR_OUTOFRANGE;
800c2c66affSColin Finck lpParms->dwReturn = FRAME_OF_TOC(toc, lpParms->dwTrack);
801c2c66affSColin Finck TRACE("get MCI_TRACK #%u !\n", lpParms->dwTrack);
802c2c66affSColin Finck break;
803c2c66affSColin Finck case 0:
804c2c66affSColin Finck fmt.Format = IOCTL_CDROM_CURRENT_POSITION;
805c2c66affSColin Finck if (!device_io(wmcda->handle, IOCTL_CDROM_READ_Q_CHANNEL, &fmt, sizeof(fmt),
806c2c66affSColin Finck &data, sizeof(data), &br, NULL)) {
807c2c66affSColin Finck return MCICDA_GetError(wmcda);
808c2c66affSColin Finck }
809c2c66affSColin Finck lpParms->dwReturn = FRAME_OF_ADDR(data.CurrentPosition.AbsoluteAddress);
810c2c66affSColin Finck break;
811c2c66affSColin Finck default:
812c2c66affSColin Finck return MCIERR_FLAGS_NOT_COMPATIBLE;
813c2c66affSColin Finck }
814c2c66affSColin Finck lpParms->dwReturn = MCICDA_CalcTime(wmcda, wmcda->dwTimeFormat, lpParms->dwReturn, &ret);
815c2c66affSColin Finck TRACE("MCI_STATUS_POSITION=%08lX\n", lpParms->dwReturn);
816c2c66affSColin Finck break;
817c2c66affSColin Finck case MCI_STATUS_READY:
818c2c66affSColin Finck TRACE("MCI_STATUS_READY !\n");
819c2c66affSColin Finck switch (MCICDA_GetStatus(wmcda))
820c2c66affSColin Finck {
821c2c66affSColin Finck case MCI_MODE_NOT_READY:
822c2c66affSColin Finck case MCI_MODE_OPEN:
823c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(FALSE, MCI_FALSE);
824c2c66affSColin Finck break;
825c2c66affSColin Finck default:
826c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(TRUE, MCI_TRUE);
827c2c66affSColin Finck break;
828c2c66affSColin Finck }
829c2c66affSColin Finck TRACE("MCI_STATUS_READY=%u!\n", LOWORD(lpParms->dwReturn));
830c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
831c2c66affSColin Finck break;
832c2c66affSColin Finck case MCI_STATUS_TIME_FORMAT:
833c2c66affSColin Finck lpParms->dwReturn = MAKEMCIRESOURCE(wmcda->dwTimeFormat, MCI_FORMAT_RETURN_BASE + wmcda->dwTimeFormat);
834c2c66affSColin Finck TRACE("MCI_STATUS_TIME_FORMAT=%08x!\n", LOWORD(lpParms->dwReturn));
835c2c66affSColin Finck ret = MCI_RESOURCE_RETURNED;
836c2c66affSColin Finck break;
837c2c66affSColin Finck case 4001: /* FIXME: for bogus FullCD */
838c2c66affSColin Finck case MCI_CDA_STATUS_TYPE_TRACK:
839c2c66affSColin Finck if (!(dwFlags & MCI_TRACK))
840c2c66affSColin Finck ret = MCIERR_MISSING_PARAMETER;
841c2c66affSColin Finck else {
842c2c66affSColin Finck if (!MCICDA_ReadTOC(wmcda, &toc, &br))
843c2c66affSColin Finck return MCICDA_GetError(wmcda);
844c2c66affSColin Finck
845c2c66affSColin Finck if (lpParms->dwTrack < toc.FirstTrack || lpParms->dwTrack > toc.LastTrack)
846c2c66affSColin Finck ret = MCIERR_OUTOFRANGE;
847c2c66affSColin Finck else
848c2c66affSColin Finck lpParms->dwReturn = (toc.TrackData[lpParms->dwTrack - toc.FirstTrack].Control & 0x04) ?
849c2c66affSColin Finck MCI_CDA_TRACK_OTHER : MCI_CDA_TRACK_AUDIO;
850c2c66affSColin Finck /* FIXME: MAKEMCIRESOURCE "audio" | "other", localised */
851c2c66affSColin Finck }
852c2c66affSColin Finck TRACE("MCI_CDA_STATUS_TYPE_TRACK[%d]=%ld\n", lpParms->dwTrack, lpParms->dwReturn);
853c2c66affSColin Finck break;
854c2c66affSColin Finck default:
855c2c66affSColin Finck FIXME("unknown command %08X !\n", lpParms->dwItem);
856c2c66affSColin Finck return MCIERR_UNSUPPORTED_FUNCTION;
857c2c66affSColin Finck }
858c2c66affSColin Finck } else return MCIERR_MISSING_PARAMETER;
859c2c66affSColin Finck if ((dwFlags & MCI_NOTIFY) && HRESULT_CODE(ret)==0)
860c2c66affSColin Finck MCICDA_Notify(lpParms->dwCallback, wmcda, MCI_NOTIFY_SUCCESSFUL);
861c2c66affSColin Finck return ret;
862c2c66affSColin Finck }
863c2c66affSColin Finck
864c2c66affSColin Finck /**************************************************************************
865c2c66affSColin Finck * MCICDA_SkipDataTracks [internal]
866c2c66affSColin Finck */
MCICDA_SkipDataTracks(WINE_MCICDAUDIO * wmcda,DWORD * frame)867c2c66affSColin Finck static DWORD MCICDA_SkipDataTracks(WINE_MCICDAUDIO* wmcda,DWORD *frame)
868c2c66affSColin Finck {
869c2c66affSColin Finck int i;
870c2c66affSColin Finck DWORD br;
871c2c66affSColin Finck CDROM_TOC toc;
872c2c66affSColin Finck if (!MCICDA_ReadTOC(wmcda, &toc, &br))
873c2c66affSColin Finck return MCICDA_GetError(wmcda);
874c2c66affSColin Finck
875c2c66affSColin Finck if (*frame < FRAME_OF_TOC(toc,toc.FirstTrack) ||
876c2c66affSColin Finck *frame >= FRAME_OF_TOC(toc,toc.LastTrack+1)) /* lead-out */
877c2c66affSColin Finck return MCIERR_OUTOFRANGE;
878c2c66affSColin Finck for(i=toc.LastTrack+1;i>toc.FirstTrack;i--)
879c2c66affSColin Finck if ( FRAME_OF_TOC(toc, i) <= *frame ) break;
880c2c66affSColin Finck /* i points to last track whose start address is not greater than frame.
881c2c66affSColin Finck * Now skip non-audio tracks */
882c2c66affSColin Finck for(;i<=toc.LastTrack;i++)
883c2c66affSColin Finck if ( ! (toc.TrackData[i-toc.FirstTrack].Control & 4) )
884c2c66affSColin Finck break;
885c2c66affSColin Finck /* The frame will be an address in the next audio track or
886c2c66affSColin Finck * address of lead-out. */
887c2c66affSColin Finck if ( FRAME_OF_TOC(toc, i) > *frame )
888c2c66affSColin Finck *frame = FRAME_OF_TOC(toc, i);
889c2c66affSColin Finck /* Lead-out is an invalid seek position (on Linux as well). */
890c2c66affSColin Finck if (*frame == FRAME_OF_TOC(toc,toc.LastTrack+1))
891c2c66affSColin Finck (*frame)--;
892c2c66affSColin Finck return 0;
893c2c66affSColin Finck }
894c2c66affSColin Finck
895c2c66affSColin Finck /**************************************************************************
896c2c66affSColin Finck * MCICDA_Play [internal]
897c2c66affSColin Finck */
MCICDA_Play(UINT wDevID,DWORD dwFlags,LPMCI_PLAY_PARMS lpParms)898c2c66affSColin Finck static DWORD MCICDA_Play(UINT wDevID, DWORD dwFlags, LPMCI_PLAY_PARMS lpParms)
899c2c66affSColin Finck {
900c2c66affSColin Finck WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
901c2c66affSColin Finck DWORD ret = 0, start, end;
902c2c66affSColin Finck HANDLE oldcb;
903c2c66affSColin Finck DWORD br;
904c2c66affSColin Finck CDROM_PLAY_AUDIO_MSF play;
905c2c66affSColin Finck CDROM_SUB_Q_DATA_FORMAT fmt;
906c2c66affSColin Finck SUB_Q_CHANNEL_DATA data;
907c2c66affSColin Finck CDROM_TOC toc;
908c2c66affSColin Finck
909c2c66affSColin Finck TRACE("(%04X, %08X, %p);\n", wDevID, dwFlags, lpParms);
910c2c66affSColin Finck
911c2c66affSColin Finck if (lpParms == NULL)
912c2c66affSColin Finck return MCIERR_NULL_PARAMETER_BLOCK;
913c2c66affSColin Finck
914c2c66affSColin Finck if (wmcda == NULL)
915c2c66affSColin Finck return MCIERR_INVALID_DEVICE_ID;
916c2c66affSColin Finck
917c2c66affSColin Finck if (!MCICDA_ReadTOC(wmcda, &toc, &br))
918c2c66affSColin Finck return MCICDA_GetError(wmcda);
919c2c66affSColin Finck
920c2c66affSColin Finck if (dwFlags & MCI_FROM) {
921c2c66affSColin Finck start = MCICDA_CalcFrame(wmcda, lpParms->dwFrom);
922c2c66affSColin Finck if ( (ret=MCICDA_SkipDataTracks(wmcda, &start)) )
923c2c66affSColin Finck return ret;
924c2c66affSColin Finck TRACE("MCI_FROM=%08X -> %u\n", lpParms->dwFrom, start);
925c2c66affSColin Finck } else {
926c2c66affSColin Finck fmt.Format = IOCTL_CDROM_CURRENT_POSITION;
927c2c66affSColin Finck if (!device_io(wmcda->handle, IOCTL_CDROM_READ_Q_CHANNEL, &fmt, sizeof(fmt),
928c2c66affSColin Finck &data, sizeof(data), &br, NULL)) {
929c2c66affSColin Finck return MCICDA_GetError(wmcda);
930c2c66affSColin Finck }
931c2c66affSColin Finck start = FRAME_OF_ADDR(data.CurrentPosition.AbsoluteAddress);
932c2c66affSColin Finck if ( (ret=MCICDA_SkipDataTracks(wmcda, &start)) )
933c2c66affSColin Finck return ret;
934c2c66affSColin Finck }
935c2c66affSColin Finck if (dwFlags & MCI_TO) {
936c2c66affSColin Finck end = MCICDA_CalcFrame(wmcda, lpParms->dwTo);
937c2c66affSColin Finck if ( (ret=MCICDA_SkipDataTracks(wmcda, &end)) )
938c2c66affSColin Finck return ret;
939c2c66affSColin Finck TRACE("MCI_TO=%08X -> %u\n", lpParms->dwTo, end);
940c2c66affSColin Finck } else {
941c2c66affSColin Finck end = FRAME_OF_TOC(toc, toc.LastTrack + 1) - 1;
942c2c66affSColin Finck }
943c2c66affSColin Finck if (end < start) return MCIERR_OUTOFRANGE;
944c2c66affSColin Finck TRACE("Playing from %u to %u\n", start, end);
945c2c66affSColin Finck
946c2c66affSColin Finck oldcb = InterlockedExchangePointer(&wmcda->hCallback,
947c2c66affSColin Finck (dwFlags & MCI_NOTIFY) ? HWND_32(LOWORD(lpParms->dwCallback)) : NULL);
948c2c66affSColin Finck if (oldcb) mciDriverNotify(oldcb, wmcda->wNotifyDeviceID, MCI_NOTIFY_ABORTED);
949c2c66affSColin Finck
950c2c66affSColin Finck if (start == end || start == FRAME_OF_TOC(toc,toc.LastTrack+1)-1) {
951c2c66affSColin Finck if (dwFlags & MCI_NOTIFY) {
952c2c66affSColin Finck oldcb = InterlockedExchangePointer(&wmcda->hCallback, NULL);
953c2c66affSColin Finck if (oldcb) mciDriverNotify(oldcb, wDevID, MCI_NOTIFY_SUCCESSFUL);
954c2c66affSColin Finck }
955c2c66affSColin Finck return MMSYSERR_NOERROR;
956c2c66affSColin Finck }
957c2c66affSColin Finck
958c2c66affSColin Finck if (wmcda->hThread != 0) {
959c2c66affSColin Finck SetEvent(wmcda->stopEvent);
960c2c66affSColin Finck WaitForSingleObject(wmcda->hThread, INFINITE);
961c2c66affSColin Finck
962c2c66affSColin Finck CloseHandle(wmcda->hThread);
963c2c66affSColin Finck wmcda->hThread = 0;
964c2c66affSColin Finck CloseHandle(wmcda->stopEvent);
965c2c66affSColin Finck wmcda->stopEvent = 0;
966c2c66affSColin Finck
967c2c66affSColin Finck IDirectSoundBuffer_Stop(wmcda->dsBuf);
968c2c66affSColin Finck IDirectSoundBuffer_Release(wmcda->dsBuf);
969c2c66affSColin Finck wmcda->dsBuf = NULL;
970c2c66affSColin Finck IDirectSound_Release(wmcda->dsObj);
971c2c66affSColin Finck wmcda->dsObj = NULL;
972c2c66affSColin Finck }
973c2c66affSColin Finck
974c2c66affSColin Finck if (pDirectSoundCreate) {
975c2c66affSColin Finck WAVEFORMATEX format;
976c2c66affSColin Finck DSBUFFERDESC desc;
977c2c66affSColin Finck DWORD lockLen;
978c2c66affSColin Finck void *cdData;
979c2c66affSColin Finck HRESULT hr;
980c2c66affSColin Finck
981c2c66affSColin Finck hr = pDirectSoundCreate(NULL, &wmcda->dsObj, NULL);
982c2c66affSColin Finck if (SUCCEEDED(hr)) {
983c2c66affSColin Finck IDirectSound_SetCooperativeLevel(wmcda->dsObj, GetDesktopWindow(), DSSCL_PRIORITY);
984c2c66affSColin Finck
985c2c66affSColin Finck /* The "raw" frame is relative to the start of the first track */
986c2c66affSColin Finck wmcda->start = start - FRAME_OF_TOC(toc, toc.FirstTrack);
987c2c66affSColin Finck wmcda->end = end - FRAME_OF_TOC(toc, toc.FirstTrack);
988c2c66affSColin Finck
989c2c66affSColin Finck memset(&format, 0, sizeof(format));
990c2c66affSColin Finck format.wFormatTag = WAVE_FORMAT_PCM;
991c2c66affSColin Finck format.nChannels = 2;
992c2c66affSColin Finck format.nSamplesPerSec = 44100;
993c2c66affSColin Finck format.wBitsPerSample = 16;
994c2c66affSColin Finck format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
995c2c66affSColin Finck format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
996c2c66affSColin Finck format.cbSize = 0;
997c2c66affSColin Finck
998c2c66affSColin Finck memset(&desc, 0, sizeof(desc));
999c2c66affSColin Finck desc.dwSize = sizeof(desc);
1000c2c66affSColin Finck desc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS;
1001c2c66affSColin Finck desc.dwBufferBytes = (CDDA_FRAG_SIZE - (CDDA_FRAG_SIZE%RAW_SECTOR_SIZE)) * CDDA_FRAG_COUNT;
1002c2c66affSColin Finck desc.lpwfxFormat = &format;
1003c2c66affSColin Finck
1004c2c66affSColin Finck hr = IDirectSound_CreateSoundBuffer(wmcda->dsObj, &desc, &wmcda->dsBuf, NULL);
1005c2c66affSColin Finck }
1006c2c66affSColin Finck if (SUCCEEDED(hr)) {
1007c2c66affSColin Finck hr = IDirectSoundBuffer_Lock(wmcda->dsBuf, 0, 0, &cdData, &lockLen,
1008c2c66affSColin Finck NULL, NULL, DSBLOCK_ENTIREBUFFER);
1009c2c66affSColin Finck }
1010c2c66affSColin Finck if (SUCCEEDED(hr)) {
1011c2c66affSColin Finck RAW_READ_INFO rdInfo;
1012c2c66affSColin Finck int readok;
1013c2c66affSColin Finck
1014c2c66affSColin Finck rdInfo.DiskOffset.QuadPart = wmcda->start<<11;
1015c2c66affSColin Finck rdInfo.SectorCount = min(desc.dwBufferBytes/RAW_SECTOR_SIZE,
1016c2c66affSColin Finck wmcda->end-wmcda->start);
1017c2c66affSColin Finck rdInfo.TrackMode = CDDA;
1018c2c66affSColin Finck
1019c2c66affSColin Finck readok = device_io(wmcda->handle, IOCTL_CDROM_RAW_READ,
1020c2c66affSColin Finck &rdInfo, sizeof(rdInfo), cdData, lockLen,
1021c2c66affSColin Finck &br, NULL);
1022c2c66affSColin Finck IDirectSoundBuffer_Unlock(wmcda->dsBuf, cdData, lockLen, NULL, 0);
1023c2c66affSColin Finck
1024c2c66affSColin Finck if (readok) {
1025c2c66affSColin Finck wmcda->start += rdInfo.SectorCount;
1026c2c66affSColin Finck wmcda->stopEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
1027c2c66affSColin Finck }
1028c2c66affSColin Finck if (wmcda->stopEvent != 0)
1029c2c66affSColin Finck wmcda->hThread = CreateThread(NULL, 0, MCICDA_playLoop, wmcda, 0, &br);
1030c2c66affSColin Finck if (wmcda->hThread != 0) {
1031c2c66affSColin Finck hr = IDirectSoundBuffer_Play(wmcda->dsBuf, 0, 0, DSBPLAY_LOOPING);
1032c2c66affSColin Finck if (SUCCEEDED(hr)) {
1033c2c66affSColin Finck /* FIXME: implement MCI_WAIT and send notification only in that case */
1034c2c66affSColin Finck if (0) {
1035c2c66affSColin Finck oldcb = InterlockedExchangePointer(&wmcda->hCallback, NULL);
1036c2c66affSColin Finck if (oldcb) mciDriverNotify(oldcb, wmcda->wNotifyDeviceID,
1037c2c66affSColin Finck FAILED(hr) ? MCI_NOTIFY_FAILURE : MCI_NOTIFY_SUCCESSFUL);
1038c2c66affSColin Finck }
1039c2c66affSColin Finck return ret;
1040c2c66affSColin Finck }
1041c2c66affSColin Finck
1042c2c66affSColin Finck SetEvent(wmcda->stopEvent);
1043c2c66affSColin Finck WaitForSingleObject(wmcda->hThread, INFINITE);
1044c2c66affSColin Finck CloseHandle(wmcda->hThread);
1045c2c66affSColin Finck wmcda->hThread = 0;
1046c2c66affSColin Finck }
1047c2c66affSColin Finck }
1048c2c66affSColin Finck
1049c2c66affSColin Finck if (wmcda->stopEvent != 0) {
1050c2c66affSColin Finck CloseHandle(wmcda->stopEvent);
1051c2c66affSColin Finck wmcda->stopEvent = 0;
1052c2c66affSColin Finck }
1053c2c66affSColin Finck if (wmcda->dsBuf) {
1054c2c66affSColin Finck IDirectSoundBuffer_Release(wmcda->dsBuf);
1055c2c66affSColin Finck wmcda->dsBuf = NULL;
1056c2c66affSColin Finck }
1057c2c66affSColin Finck if (wmcda->dsObj) {
1058c2c66affSColin Finck IDirectSound_Release(wmcda->dsObj);
1059c2c66affSColin Finck wmcda->dsObj = NULL;
1060c2c66affSColin Finck }
1061c2c66affSColin Finck }
1062c2c66affSColin Finck
1063c2c66affSColin Finck play.StartingM = start / CDFRAMES_PERMIN;
1064c2c66affSColin Finck play.StartingS = (start / CDFRAMES_PERSEC) % 60;
1065c2c66affSColin Finck play.StartingF = start % CDFRAMES_PERSEC;
1066c2c66affSColin Finck play.EndingM = end / CDFRAMES_PERMIN;
1067c2c66affSColin Finck play.EndingS = (end / CDFRAMES_PERSEC) % 60;
1068c2c66affSColin Finck play.EndingF = end % CDFRAMES_PERSEC;
1069c2c66affSColin Finck if (!device_io(wmcda->handle, IOCTL_CDROM_PLAY_AUDIO_MSF, &play, sizeof(play),
1070c2c66affSColin Finck NULL, 0, &br, NULL)) {
1071c2c66affSColin Finck wmcda->hCallback = NULL;
1072c2c66affSColin Finck ret = MCIERR_HARDWARE;
1073c2c66affSColin Finck }
1074c2c66affSColin Finck /* The independent CD player has no means to signal MCI_NOTIFY when it's done.
1075c2c66affSColin Finck * Native sends a notification with MCI_WAIT only. */
1076c2c66affSColin Finck return ret;
1077c2c66affSColin Finck }
1078c2c66affSColin Finck
1079c2c66affSColin Finck /**************************************************************************
1080c2c66affSColin Finck * MCICDA_Stop [internal]
1081c2c66affSColin Finck */
MCICDA_Stop(UINT wDevID,DWORD dwFlags,LPMCI_GENERIC_PARMS lpParms)1082c2c66affSColin Finck static DWORD MCICDA_Stop(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1083c2c66affSColin Finck {
1084c2c66affSColin Finck WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
1085c2c66affSColin Finck HANDLE oldcb;
1086c2c66affSColin Finck DWORD br;
1087c2c66affSColin Finck
1088c2c66affSColin Finck TRACE("(%04X, %08X, %p);\n", wDevID, dwFlags, lpParms);
1089c2c66affSColin Finck
1090c2c66affSColin Finck if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
1091c2c66affSColin Finck
1092c2c66affSColin Finck oldcb = InterlockedExchangePointer(&wmcda->hCallback, NULL);
1093c2c66affSColin Finck if (oldcb) mciDriverNotify(oldcb, wmcda->wNotifyDeviceID, MCI_NOTIFY_ABORTED);
1094c2c66affSColin Finck
1095c2c66affSColin Finck if (wmcda->hThread != 0) {
1096c2c66affSColin Finck SetEvent(wmcda->stopEvent);
1097c2c66affSColin Finck WaitForSingleObject(wmcda->hThread, INFINITE);
1098c2c66affSColin Finck
1099c2c66affSColin Finck CloseHandle(wmcda->hThread);
1100c2c66affSColin Finck wmcda->hThread = 0;
1101c2c66affSColin Finck CloseHandle(wmcda->stopEvent);
1102c2c66affSColin Finck wmcda->stopEvent = 0;
1103c2c66affSColin Finck
1104c2c66affSColin Finck IDirectSoundBuffer_Release(wmcda->dsBuf);
1105c2c66affSColin Finck wmcda->dsBuf = NULL;
1106c2c66affSColin Finck IDirectSound_Release(wmcda->dsObj);
1107c2c66affSColin Finck wmcda->dsObj = NULL;
1108c2c66affSColin Finck }
1109c2c66affSColin Finck else if (!device_io(wmcda->handle, IOCTL_CDROM_STOP_AUDIO, NULL, 0, NULL, 0, &br, NULL))
1110c2c66affSColin Finck return MCIERR_HARDWARE;
1111c2c66affSColin Finck
1112c2c66affSColin Finck if ((dwFlags & MCI_NOTIFY) && lpParms)
1113c2c66affSColin Finck MCICDA_Notify(lpParms->dwCallback, wmcda, MCI_NOTIFY_SUCCESSFUL);
1114c2c66affSColin Finck return 0;
1115c2c66affSColin Finck }
1116c2c66affSColin Finck
1117c2c66affSColin Finck /**************************************************************************
1118c2c66affSColin Finck * MCICDA_Pause [internal]
1119c2c66affSColin Finck */
MCICDA_Pause(UINT wDevID,DWORD dwFlags,LPMCI_GENERIC_PARMS lpParms)1120c2c66affSColin Finck static DWORD MCICDA_Pause(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1121c2c66affSColin Finck {
1122c2c66affSColin Finck WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
1123c2c66affSColin Finck HANDLE oldcb;
1124c2c66affSColin Finck DWORD br;
1125c2c66affSColin Finck
1126c2c66affSColin Finck TRACE("(%04X, %08X, %p);\n", wDevID, dwFlags, lpParms);
1127c2c66affSColin Finck
1128c2c66affSColin Finck if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
1129c2c66affSColin Finck
1130c2c66affSColin Finck oldcb = InterlockedExchangePointer(&wmcda->hCallback, NULL);
1131c2c66affSColin Finck if (oldcb) mciDriverNotify(oldcb, wmcda->wNotifyDeviceID, MCI_NOTIFY_ABORTED);
1132c2c66affSColin Finck
1133c2c66affSColin Finck if (wmcda->hThread != 0) {
1134c2c66affSColin Finck /* Don't bother calling stop if the playLoop thread has already stopped */
1135c2c66affSColin Finck if(WaitForSingleObject(wmcda->stopEvent, 0) != WAIT_OBJECT_0 &&
1136c2c66affSColin Finck FAILED(IDirectSoundBuffer_Stop(wmcda->dsBuf)))
1137c2c66affSColin Finck return MCIERR_HARDWARE;
1138c2c66affSColin Finck }
1139c2c66affSColin Finck else if (!device_io(wmcda->handle, IOCTL_CDROM_PAUSE_AUDIO, NULL, 0, NULL, 0, &br, NULL))
1140c2c66affSColin Finck return MCIERR_HARDWARE;
1141c2c66affSColin Finck
1142c2c66affSColin Finck if ((dwFlags & MCI_NOTIFY) && lpParms)
1143c2c66affSColin Finck MCICDA_Notify(lpParms->dwCallback, wmcda, MCI_NOTIFY_SUCCESSFUL);
1144c2c66affSColin Finck return 0;
1145c2c66affSColin Finck }
1146c2c66affSColin Finck
1147c2c66affSColin Finck /**************************************************************************
1148c2c66affSColin Finck * MCICDA_Resume [internal]
1149c2c66affSColin Finck */
MCICDA_Resume(UINT wDevID,DWORD dwFlags,LPMCI_GENERIC_PARMS lpParms)1150c2c66affSColin Finck static DWORD MCICDA_Resume(UINT wDevID, DWORD dwFlags, LPMCI_GENERIC_PARMS lpParms)
1151c2c66affSColin Finck {
1152c2c66affSColin Finck WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
1153c2c66affSColin Finck DWORD br;
1154c2c66affSColin Finck
1155c2c66affSColin Finck TRACE("(%04X, %08X, %p);\n", wDevID, dwFlags, lpParms);
1156c2c66affSColin Finck
1157c2c66affSColin Finck if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
1158c2c66affSColin Finck
1159c2c66affSColin Finck if (wmcda->hThread != 0) {
1160c2c66affSColin Finck /* Don't restart if the playLoop thread has already stopped */
1161c2c66affSColin Finck if(WaitForSingleObject(wmcda->stopEvent, 0) != WAIT_OBJECT_0 &&
1162c2c66affSColin Finck FAILED(IDirectSoundBuffer_Play(wmcda->dsBuf, 0, 0, DSBPLAY_LOOPING)))
1163c2c66affSColin Finck return MCIERR_HARDWARE;
1164c2c66affSColin Finck }
1165c2c66affSColin Finck else if (!device_io(wmcda->handle, IOCTL_CDROM_RESUME_AUDIO, NULL, 0, NULL, 0, &br, NULL))
1166c2c66affSColin Finck return MCIERR_HARDWARE;
1167c2c66affSColin Finck
1168c2c66affSColin Finck if ((dwFlags & MCI_NOTIFY) && lpParms)
1169c2c66affSColin Finck MCICDA_Notify(lpParms->dwCallback, wmcda, MCI_NOTIFY_SUCCESSFUL);
1170c2c66affSColin Finck return 0;
1171c2c66affSColin Finck }
1172c2c66affSColin Finck
1173c2c66affSColin Finck /**************************************************************************
1174c2c66affSColin Finck * MCICDA_Seek [internal]
1175c2c66affSColin Finck */
MCICDA_Seek(UINT wDevID,DWORD dwFlags,LPMCI_SEEK_PARMS lpParms)1176c2c66affSColin Finck static DWORD MCICDA_Seek(UINT wDevID, DWORD dwFlags, LPMCI_SEEK_PARMS lpParms)
1177c2c66affSColin Finck {
1178c2c66affSColin Finck DWORD at;
1179c2c66affSColin Finck WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
1180c2c66affSColin Finck CDROM_SEEK_AUDIO_MSF seek;
1181c2c66affSColin Finck DWORD br, position, ret;
1182c2c66affSColin Finck CDROM_TOC toc;
1183c2c66affSColin Finck
1184c2c66affSColin Finck TRACE("(%04X, %08X, %p);\n", wDevID, dwFlags, lpParms);
1185c2c66affSColin Finck
1186c2c66affSColin Finck if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
1187c2c66affSColin Finck if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1188c2c66affSColin Finck
1189c2c66affSColin Finck position = dwFlags & (MCI_SEEK_TO_START|MCI_SEEK_TO_END|MCI_TO);
1190c2c66affSColin Finck if (!position) return MCIERR_MISSING_PARAMETER;
1191c2c66affSColin Finck if (position&(position-1)) return MCIERR_FLAGS_NOT_COMPATIBLE;
1192c2c66affSColin Finck
1193c2c66affSColin Finck /* Stop sends MCI_NOTIFY_ABORTED when needed.
1194c2c66affSColin Finck * Tests show that native first sends ABORTED and reads the TOC,
1195c2c66affSColin Finck * then only checks the position flags, then stops and seeks. */
1196c2c66affSColin Finck MCICDA_Stop(wDevID, MCI_WAIT, 0);
1197c2c66affSColin Finck
1198c2c66affSColin Finck if (!MCICDA_ReadTOC(wmcda, &toc, &br))
1199c2c66affSColin Finck return MCICDA_GetError(wmcda);
1200c2c66affSColin Finck
1201c2c66affSColin Finck switch (position) {
1202c2c66affSColin Finck case MCI_SEEK_TO_START:
1203c2c66affSColin Finck TRACE("Seeking to start\n");
1204c2c66affSColin Finck at = FRAME_OF_TOC(toc,toc.FirstTrack);
1205c2c66affSColin Finck if ( (ret=MCICDA_SkipDataTracks(wmcda, &at)) )
1206c2c66affSColin Finck return ret;
1207c2c66affSColin Finck break;
1208c2c66affSColin Finck case MCI_SEEK_TO_END:
1209c2c66affSColin Finck TRACE("Seeking to end\n");
1210c2c66affSColin Finck /* End is prior to lead-out
1211c2c66affSColin Finck * yet Win9X seeks to even one frame less than that. */
1212c2c66affSColin Finck at = FRAME_OF_TOC(toc, toc.LastTrack + 1) - 1;
1213c2c66affSColin Finck if ( (ret=MCICDA_SkipDataTracks(wmcda, &at)) )
1214c2c66affSColin Finck return ret;
1215c2c66affSColin Finck break;
1216c2c66affSColin Finck case MCI_TO:
1217c2c66affSColin Finck TRACE("Seeking to %u\n", lpParms->dwTo);
1218c2c66affSColin Finck at = MCICDA_CalcFrame(wmcda, lpParms->dwTo);
1219c2c66affSColin Finck if ( (ret=MCICDA_SkipDataTracks(wmcda, &at)) )
1220c2c66affSColin Finck return ret;
1221c2c66affSColin Finck break;
1222c2c66affSColin Finck default:
1223c2c66affSColin Finck return MCIERR_FLAGS_NOT_COMPATIBLE;
1224c2c66affSColin Finck }
1225c2c66affSColin Finck
1226c2c66affSColin Finck {
1227c2c66affSColin Finck seek.M = at / CDFRAMES_PERMIN;
1228c2c66affSColin Finck seek.S = (at / CDFRAMES_PERSEC) % 60;
1229c2c66affSColin Finck seek.F = at % CDFRAMES_PERSEC;
1230c2c66affSColin Finck if (!device_io(wmcda->handle, IOCTL_CDROM_SEEK_AUDIO_MSF, &seek, sizeof(seek),
1231c2c66affSColin Finck NULL, 0, &br, NULL))
1232c2c66affSColin Finck return MCIERR_HARDWARE;
1233c2c66affSColin Finck }
1234c2c66affSColin Finck
1235c2c66affSColin Finck if (dwFlags & MCI_NOTIFY)
1236c2c66affSColin Finck MCICDA_Notify(lpParms->dwCallback, wmcda, MCI_NOTIFY_SUCCESSFUL);
1237c2c66affSColin Finck return 0;
1238c2c66affSColin Finck }
1239c2c66affSColin Finck
1240c2c66affSColin Finck /**************************************************************************
1241c2c66affSColin Finck * MCICDA_SetDoor [internal]
1242c2c66affSColin Finck */
MCICDA_SetDoor(UINT wDevID,BOOL open)1243c2c66affSColin Finck static DWORD MCICDA_SetDoor(UINT wDevID, BOOL open)
1244c2c66affSColin Finck {
1245c2c66affSColin Finck WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
1246c2c66affSColin Finck DWORD br;
1247c2c66affSColin Finck
1248c2c66affSColin Finck TRACE("(%04x, %s) !\n", wDevID, (open) ? "OPEN" : "CLOSE");
1249c2c66affSColin Finck
1250c2c66affSColin Finck if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
1251c2c66affSColin Finck
1252c2c66affSColin Finck if (!device_io(wmcda->handle,
1253c2c66affSColin Finck (open) ? IOCTL_STORAGE_EJECT_MEDIA : IOCTL_STORAGE_LOAD_MEDIA,
1254c2c66affSColin Finck NULL, 0, NULL, 0, &br, NULL))
1255c2c66affSColin Finck return MCIERR_HARDWARE;
1256c2c66affSColin Finck
1257c2c66affSColin Finck return 0;
1258c2c66affSColin Finck }
1259c2c66affSColin Finck
1260c2c66affSColin Finck /**************************************************************************
1261c2c66affSColin Finck * MCICDA_Set [internal]
1262c2c66affSColin Finck */
MCICDA_Set(UINT wDevID,DWORD dwFlags,LPMCI_SET_PARMS lpParms)1263c2c66affSColin Finck static DWORD MCICDA_Set(UINT wDevID, DWORD dwFlags, LPMCI_SET_PARMS lpParms)
1264c2c66affSColin Finck {
1265c2c66affSColin Finck WINE_MCICDAUDIO* wmcda = MCICDA_GetOpenDrv(wDevID);
1266c2c66affSColin Finck
1267c2c66affSColin Finck TRACE("(%04X, %08X, %p);\n", wDevID, dwFlags, lpParms);
1268c2c66affSColin Finck
1269c2c66affSColin Finck if (wmcda == NULL) return MCIERR_INVALID_DEVICE_ID;
1270c2c66affSColin Finck
1271c2c66affSColin Finck if (dwFlags & MCI_SET_DOOR_OPEN) {
1272c2c66affSColin Finck MCICDA_SetDoor(wDevID, TRUE);
1273c2c66affSColin Finck }
1274c2c66affSColin Finck if (dwFlags & MCI_SET_DOOR_CLOSED) {
1275c2c66affSColin Finck MCICDA_SetDoor(wDevID, FALSE);
1276c2c66affSColin Finck }
1277c2c66affSColin Finck
1278c2c66affSColin Finck /* only functions which require valid lpParms below this line ! */
1279c2c66affSColin Finck if (lpParms == NULL) return MCIERR_NULL_PARAMETER_BLOCK;
1280c2c66affSColin Finck /*
1281c2c66affSColin Finck TRACE("dwTimeFormat=%08lX\n", lpParms->dwTimeFormat);
1282c2c66affSColin Finck */
1283c2c66affSColin Finck if (dwFlags & MCI_SET_TIME_FORMAT) {
1284c2c66affSColin Finck switch (lpParms->dwTimeFormat) {
1285c2c66affSColin Finck case MCI_FORMAT_MILLISECONDS:
1286c2c66affSColin Finck TRACE("MCI_FORMAT_MILLISECONDS !\n");
1287c2c66affSColin Finck break;
1288c2c66affSColin Finck case MCI_FORMAT_MSF:
1289c2c66affSColin Finck TRACE("MCI_FORMAT_MSF !\n");
1290c2c66affSColin Finck break;
1291c2c66affSColin Finck case MCI_FORMAT_TMSF:
1292c2c66affSColin Finck TRACE("MCI_FORMAT_TMSF !\n");
1293c2c66affSColin Finck break;
1294c2c66affSColin Finck default:
1295c2c66affSColin Finck return MCIERR_BAD_TIME_FORMAT;
1296c2c66affSColin Finck }
1297c2c66affSColin Finck wmcda->dwTimeFormat = lpParms->dwTimeFormat;
1298c2c66affSColin Finck }
1299c2c66affSColin Finck if (dwFlags & MCI_SET_AUDIO) /* one xp machine ignored it */
1300c2c66affSColin Finck TRACE("SET_AUDIO %X %x\n", dwFlags, lpParms->dwAudio);
1301c2c66affSColin Finck
1302c2c66affSColin Finck if (dwFlags & MCI_NOTIFY)
1303c2c66affSColin Finck MCICDA_Notify(lpParms->dwCallback, wmcda, MCI_NOTIFY_SUCCESSFUL);
1304c2c66affSColin Finck return 0;
1305c2c66affSColin Finck }
1306c2c66affSColin Finck
1307c2c66affSColin Finck /**************************************************************************
1308c2c66affSColin Finck * DriverProc (MCICDA.@)
1309c2c66affSColin Finck */
MCICDA_DriverProc(DWORD_PTR dwDevID,HDRVR hDriv,UINT wMsg,LPARAM dwParam1,LPARAM dwParam2)1310c2c66affSColin Finck LRESULT CALLBACK MCICDA_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
1311c2c66affSColin Finck LPARAM dwParam1, LPARAM dwParam2)
1312c2c66affSColin Finck {
1313c2c66affSColin Finck switch(wMsg) {
1314c2c66affSColin Finck case DRV_LOAD: return 1;
1315c2c66affSColin Finck case DRV_FREE: return 1;
1316c2c66affSColin Finck case DRV_OPEN: return MCICDA_drvOpen((LPCWSTR)dwParam1, (LPMCI_OPEN_DRIVER_PARMSW)dwParam2);
1317c2c66affSColin Finck case DRV_CLOSE: return MCICDA_drvClose(dwDevID);
1318c2c66affSColin Finck case DRV_ENABLE: return 1;
1319c2c66affSColin Finck case DRV_DISABLE: return 1;
1320c2c66affSColin Finck case DRV_QUERYCONFIGURE: return 1;
1321c2c66affSColin Finck case DRV_CONFIGURE: MessageBoxA(0, "MCI audio CD driver !", "Wine Driver", MB_OK); return 1;
1322c2c66affSColin Finck case DRV_INSTALL: return DRVCNF_RESTART;
1323c2c66affSColin Finck case DRV_REMOVE: return DRVCNF_RESTART;
1324c2c66affSColin Finck }
1325c2c66affSColin Finck
1326c2c66affSColin Finck if (dwDevID == 0xFFFFFFFF) return MCIERR_UNSUPPORTED_FUNCTION;
1327c2c66affSColin Finck
1328c2c66affSColin Finck switch (wMsg) {
1329c2c66affSColin Finck case MCI_OPEN_DRIVER: return MCICDA_Open(dwDevID, dwParam1, (LPMCI_OPEN_PARMSW)dwParam2);
1330c2c66affSColin Finck case MCI_CLOSE_DRIVER: return MCICDA_Close(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1331c2c66affSColin Finck case MCI_GETDEVCAPS: return MCICDA_GetDevCaps(dwDevID, dwParam1, (LPMCI_GETDEVCAPS_PARMS)dwParam2);
1332c2c66affSColin Finck case MCI_INFO: return MCICDA_Info(dwDevID, dwParam1, (LPMCI_INFO_PARMSW)dwParam2);
1333c2c66affSColin Finck case MCI_STATUS: return MCICDA_Status(dwDevID, dwParam1, (LPMCI_STATUS_PARMS)dwParam2);
1334c2c66affSColin Finck case MCI_SET: return MCICDA_Set(dwDevID, dwParam1, (LPMCI_SET_PARMS)dwParam2);
1335c2c66affSColin Finck case MCI_PLAY: return MCICDA_Play(dwDevID, dwParam1, (LPMCI_PLAY_PARMS)dwParam2);
1336c2c66affSColin Finck case MCI_STOP: return MCICDA_Stop(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1337c2c66affSColin Finck case MCI_PAUSE: return MCICDA_Pause(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1338c2c66affSColin Finck case MCI_RESUME: return MCICDA_Resume(dwDevID, dwParam1, (LPMCI_GENERIC_PARMS)dwParam2);
1339c2c66affSColin Finck case MCI_SEEK: return MCICDA_Seek(dwDevID, dwParam1, (LPMCI_SEEK_PARMS)dwParam2);
1340c2c66affSColin Finck /* commands that should report an error as they are not supported in
1341c2c66affSColin Finck * the native version */
1342c2c66affSColin Finck case MCI_RECORD:
1343c2c66affSColin Finck case MCI_LOAD:
1344c2c66affSColin Finck case MCI_SAVE:
1345c2c66affSColin Finck return MCIERR_UNSUPPORTED_FUNCTION;
1346c2c66affSColin Finck case MCI_BREAK:
1347c2c66affSColin Finck case MCI_FREEZE:
1348c2c66affSColin Finck case MCI_PUT:
1349c2c66affSColin Finck case MCI_REALIZE:
1350c2c66affSColin Finck case MCI_UNFREEZE:
1351c2c66affSColin Finck case MCI_UPDATE:
1352c2c66affSColin Finck case MCI_WHERE:
1353c2c66affSColin Finck case MCI_STEP:
1354c2c66affSColin Finck case MCI_SPIN:
1355c2c66affSColin Finck case MCI_ESCAPE:
1356c2c66affSColin Finck case MCI_COPY:
1357c2c66affSColin Finck case MCI_CUT:
1358c2c66affSColin Finck case MCI_DELETE:
1359c2c66affSColin Finck case MCI_PASTE:
1360c2c66affSColin Finck case MCI_WINDOW:
1361c2c66affSColin Finck TRACE("Unsupported command [0x%x]\n", wMsg);
1362c2c66affSColin Finck break;
1363c2c66affSColin Finck case MCI_OPEN:
1364c2c66affSColin Finck case MCI_CLOSE:
1365c2c66affSColin Finck ERR("Shouldn't receive a MCI_OPEN or CLOSE message\n");
1366c2c66affSColin Finck break;
1367c2c66affSColin Finck default:
1368c2c66affSColin Finck TRACE("Sending msg [0x%x] to default driver proc\n", wMsg);
1369c2c66affSColin Finck return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1370c2c66affSColin Finck }
1371c2c66affSColin Finck return MCIERR_UNRECOGNIZED_COMMAND;
1372c2c66affSColin Finck }
1373c2c66affSColin Finck
1374c2c66affSColin Finck /*-----------------------------------------------------------------------*/
1375